Undefined reference to a function in another library - linux

I'm trying to compile an object code with a reference to one lib. This is the code of libexample.c:
#include "libexample.h"
#include <signal.h>
#include <time.h>
timer_t sched;
struct itimerspec timer = {{0, 0}, {0, 0}};
void init() {
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &sched);
timer_settime(sched, TIMER_ABSTIME, &timer, NULL);
}
And the simple code of a example program:
#include "libexample.h"
int main() {
init();
return 0;
}
I use this to compile:
gcc libexample.c -c -lrt -o libexample.o
gcc example.c -lrt ibexample.o -o example
And I get this when I'm trying to compile with the second line:
./libexample.so: undefined reference to `timer_create'
./libexample.so: undefined reference to `timer_settime'
Anyone knows what I'm doing wrong?

Add -lrt to your link command. timer_create and timer_settime are not part of the C Standard library.
gcc -fPIC -shared libexample.c -lrt -o libexample.so
gcc -L. example.c -lexample -o example

The man timer_create command explains you:
NAME
timer_create - create a POSIX per-process timer
SYNOPSIS
#include <signal.h>
#include <time.h>
int timer_create(clockid_t clockid, struct sigevent *sevp,
timer_t *timerid);
Link with -lrt.
So you should, as documentation says, link with -lrt.
So use
gcc libexample.c -fPIC -shared -o libexample.so -lrt
to produce your libexample.so.
As undur_gongor commented, you need to put the libraries in good order after all the rest (the usual order for gcc arguments is source files, object files, libraries in dependency order) in gcc or ld commands (and that is documented in ld documentation, and in gcc ones). So -lrt should go last.
And learn to read man pages.

Looks like you forgot to link in the library that defines timer_create and timer_settime -- you need to add -lrt to your gcc command.
(source: http://www.kernel.org/doc/man-pages/online/pages/man2/timer_create.2.html)

If you are using cmake, make sure you include the libraries using target_link_libraries(). For e.g., timer functions like timer_create() you need "rt" and for pthread you need "pthread" added using target_link_libraries().

Related

Loading executable or executing a library

There is a large number of questions on SO about how to execute a library or dynamically load an executable. As far as I can tell, all the answers come down to: compile your executable as position-independent code and load it with dlopen. This worked great --- and still works great on macOS --- until a recent change in glibc, which explicitly disabled dlopening PIEs. This change is now in the current version of glibc (2.30) on ArchLinux, for example, and trying to dlopen a position-independent executable gives an error: "cannot dynamically load position-independent executable".
It's difficult to guess what prompted such a radical change that breaks so much code and useful use cases. (The explanations on Patchwork and Bugzilla don't make much sense to me.) But there is now a question: what to do if you want to create an executable that's also a dynamic library, or vice versa?
A solution was linked from one of the comments. Reproducing it here for posterity:
#include <stdio.h>
#include <unistd.h>
const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux-x86-64.so.2";
extern "C" {
void lib_entry(void)
{
printf("Entry point of the service library\n");
_exit(0);
}
}
Compiling with g++ -shared test-no-pie.cpp -o test-no-pie -Wl,-e,lib_entry produces a shared object (dynamic library) that can also be executed on Linux.
I have two questions:
What if I want to pass command-line arguments? How to modify this solution so it accepts arc,argv?
Are there other alternatives?
It's difficult to guess what prompted such a radical change
Not really: it never worked correctly.
that breaks so much code
That code was broken already in subtle ways. Now you get a clear indication that it will not work.
Are there other alternatives?
Don't do that?
What problem does dlopening an executable solve?
If it's a real problem, open a GLIBC bugzilla feature request, explaining that problem and requesting a supported mechanism to achieve desired result.
Update:
at least say why "it never worked correctly". Is it some triviality like potentially clashing globals between the executables, or something real?
Thread-local variables is an example that doesn't work correctly. Whether you think they are "real" or not I have no idea.
Here is the code:
// foo.c
#include <stdio.h>
__thread int var;
__attribute__((constructor))
static void init()
{
var = 42;
printf("foo.c init: %d %p\n", var, &var);
}
int bar() {
printf("foo.c bar: %d %p\n", var, &var);
return var;
}
int main()
{
printf("foo.c main: %d %p bar()=%d\n", var, &var, bar());
return 0;
}
gcc -g foo.c -o foo -Wl,-E -fpie -pie && ./foo
foo.c init: 42 0x7fb5dfd7d4fc
foo.c bar: 42 0x7fb5dfd7d4fc
foo.c main: 42 0x7fb5dfd7d4fc bar()=42
// main.c
// Error checking omitted for brevity
#include <dlfcn.h>
#include <stdio.h>
int main()
{
void *h1 = dlopen("./foo", RTLD_LOCAL|RTLD_LAZY);
int (*bar)(void) = dlsym(h1, "bar");
printf("main.c: %d\n", bar());
return 0;
}
gcc -g main.c -ldl && ./a.out
foo.c init: 42 0x7fb7305da73c
foo.c bar: 0 0x7fb7305da73c <<< what?
main.c: 0 <<< what?
This is using GNU C Library (Debian GLIBC 2.28-10) stable release version 2.28.
Bottom line: this was never designed to work, and you just happened to not step on many of the land-mines, so you thought it is working, when in fact you were exercising undefined behavior.
Please see this answer:
https://stackoverflow.com/a/68339111/14760867
The argc, argv question is not answered there, but when I found I needed one, I hacked something together to parse /proc/self/cmdline at runtime for pam_cap.so use.

clock_gettime() doesn't work

I read the following manual:
http://linux.die.net/man/3/clock_gettime
and I wrote the following code:
#include <time.h>
int main() {
struct timespec clk;
clock_gettime(CLOCK_REALTIME, &clk);
return 0;
}
Surprisingly, I get the following errors:
Symbol CLOCK_REALTIME could not be resolved
undefined reference to clock_gettime
I still don't understand what is the problem. I included the header, and these names show in this header.
maybe you should use#define _POSIX_TIMERS,#define _REENTRANT
besides, when you compile the code, make sure to link the real-time library which is cc filename.c -o filename -lrt
Update 1.0:
sometimes in windows or mac os, C ide may not include real-time library automatically, or we may not used the posix directly without _POSIX_TIMES, therefore you have to link the real-time library manually. In Linux, you can just type in cc filename.c -o filename -lrt to compile the c file.

Multithreaded program C using multiple .cpp files

I have a multi threaded program in C that was working well but was in one single main.cpp file.
I have moved the thread in another .cpp file and added it's signature, void* displayScreen(void*); , in the header. I include the header in my initial main.cpp file.
Compiling works but the linker returns an error when trying to call pthread_create(): undefined reference to `displayScreen(void*)'
It looks like it compiled displayScreen(void *) fine but does not know where to load it from. Is there a way for me to tell the linker where to find it or am I doing it wrong please?
Thank you very much.
Adding the signature alone lets you compile the main translation unit, but you still have to compile the implementation of the function separately and link the two:
main.cpp
void* displayScreen(void*);
int main()
{
/* .... */
}
display.cpp
void* displayScreen(void*)
{
/* implementation */
}
Compile:
g++ -O2 -o main.o main.cpp
g++ -O2 -o display.o display.cpp
Link:
g++ -o myprogram main.o display.o -lpthread -s

How to ignore undefined symbols at runtime in Linux?

I know that by default undefined symbols are ignored at compile time. However, I would also like them to be ignored at run-time. I need to distribute a .so that will run with and without MPI. I will know ahead of time if it is an MPI job and if it is not I won't make any MPI_* calls. If it's not an MPI run I need the application to not care that it cannot resolve the MPI_* symbols.
Is this possible? I could have sworn I've done this before but I can't get it working. Everytime I run I immediately get the following even though the logic in my code will never allow that symbol to be referenced:
undefined symbol: hpmp_comm_world
For what it's worth I am using the Intel Fortran Compiler to build the .so file.
EDIT
I found the linker flag: "-z lazy" which is supposed to resolve references to functions when the function is called which is what I want. That doesn't fix my problem, but hpmp_comm_world is a variable - not a function. Should that make a difference?
You can define a symbol to be a weak reference to its definition. Then, the symbol's value will be zero if the definition is not present.
For example, suppose the following is ref.c, which references a function and variable that may or may not be present; we'll use it to build libref.so (corresponding to your library, in your question):
#include <stdio.h>
void global_func(void);
void global_func(void) __attribute__ ((weak));
extern int global_variable __attribute__((weak));
void ref_func() {
printf("global_func = %p\n", global_func);
if (&global_variable)
global_variable++;
if (global_func)
global_func();
}
Here, global_func and global_variable are the weak references to the possibly-available function and variable. This code prints the function's address, increments the variable if it is present, and calls the function if it is present. (Note that the function's and variable's addresses are zero when they are not defined, so it is &global_variable that you must compare with zero.)
And suppose this is def.c, which defines global_func and global_variable; we'll use it to build libdef.so (corresponding to MPI, in your question):
#include <stdio.h>
int global_variable;
void global_func(void) {
printf("Hi, from global_func! global_variable = %d\n", global_variable);
}
And finally, suppose we have a main program, main.c, which calls ref_func from libref.so:
#include <stdio.h>
extern void ref_func(void);
int main(int argc, char **argv) {
printf("%s: ", argv[0]);
ref_func();
return 0;
}
Here's the Makefile that builds libref.so and libdef.so, and then builds two executables, both of which link against libref.so, but only one of which links against libdef.so:
all: ref-absent ref-present
ref-absent: main.o libref.so
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $#
ref-present: main.o libref.so libdef.so
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $#
lib%.so: %.o
$(CC) $(CFLAGS) $(LDFLAGS) -shared $^ -o $#
ref.o def.o: CFLAGS += -fpic
clean:
rm -f *.o *.so ref-absent ref-present
Do the build:
$ make
cc -c -o main.o main.c
cc -fpic -c -o ref.o ref.c
cc -shared ref.o -o libref.so
cc main.o libref.so -o ref-absent
cc -fpic -c -o def.o def.c
cc -shared def.o -o libdef.so
cc main.o libref.so libdef.so -o ref-present
$
Note that both ref-absent and ref-present linked without problems, even though there is no definition for global_name in ref-absent.
Now we can run the programs, and see that ref-absent skips the function call, while ref-present uses it. (We have to set LD_LIBRARY_PATH to allow the dynamic linker to find our shared libraries in the current directory.)
$ LD_LIBRARY_PATH=. ./ref-absent
./ref-absent: global_func = (nil)
$ LD_LIBRARY_PATH=. ./ref-present
./ref-present: global_func = 0x15d4ac
Hi, from global_func! global_variable = 1
$
The trick for you will be getting the ((weak)) attribute attached to every declaration of every MPI function your library references. However, as ref.c shows, there can be multiple declarations, and as long as one of them mentions the weak attribute, you're done. So you'll probably have to say something like this (I don't really know MPI):
#include <mpi.h>
mpi_fake_type_t mpi_function_foo(mpi_arg_type_t) __attribute__((weak));
mpi_fake_type_t mpi_function_bar(mpi_other_arg_type_t) __attribute__((weak));
Every reference to an MPI function needs to be in the scope of a ((weak)) declaration for that function; that's how the compiler decides what sort of symbol reference to put in the object file. You'll want to have automated tests to verify that you haven't accidentally generated any non-weak references.

Hook file saving in Linux

How can i hook file saving in Linux systems (to show my programm dialog, opearting with them then)?
Just use the inotify interface to get notification of file system changes. See: http://linux.die.net/man/7/inotify
You can try FILE_PRELOAD utility which generate C++ code with hooks, compile and LD_PRELOAD it. After short look at it you can feel how easy to hook linux. Start point is this tutorial.
For example, if you want to change 'open call' of file /tmp/some with /tmp/replace_with:
#: FILE_PRELOAD -C "A+f:/tmp/some:/tmp/replace_with" -- bash
#: echo "HaHa" >> /tmp/some
#: ll /tmp/some
ls: cannot access /tmp/some: No such file or directory
#: cat /tmp/replace_with
HaHa
If you want to see the source of generated code just add "-p" to options.
#: FILE_PRELOAD -p -C "A+f:/tmp/some:/tmp/replace_with" -- bash
In additional all generated.cpp files you can find in /tmp/$USER/FILE_PRELOAD/cpp.
Have a nice play with linux hooks)
Generated code looks like this:
#include <sys/types.h>
#include <dlfcn.h>
#include <stdio.h>
#include <map>
#include <string>
#define I int
#define C char
#define S string
#define P printf
#define R return
using std::map;
using std::string;
typedef map<S,S> MAP;
static I (*old_open)(const C *p, I flags, mode_t mode);
extern "C"
I open (const C *p, I flags, mode_t mode){
old_open = dlsym(RTLD_NEXT, "open");
P("open hook\n");
MAP files;
files[p]=p;
files["/tmp/some"]="/tmp/replace_with";
S newpath = files[S(p)];
R old_open(newpath.c_str(), flags, mode);
}
# &compile
gcc -w -fpermissive -fPIC -c -Wall file.cpp
gcc -shared file.o -ldl -lstdc++ -o wrap_loadfile.so
LD_PRELOAD=./wrap_loadfile.so bash
nm -D /lib/libc.so.6 | grep open # we hook this syscall
If you can compile them you can link first against a custom library that provides open().
There's a stock way of doing it.
If you can't compile it, this works most of the time:
Write function _open_posthook that does syscall(NR_OPEN, ...)
Provide shared library libopenhook that provides your new open. Rembember you renamed open to _open_posthook() here unless you want recursion. Don't forget to also provide creat().
Load this library with LD_PRELOAD.
EDIT: if you're trying for security this won't work. You might be able to get away with using strace() but unless you are very careful a determined programmer can overcome that too.

Resources