linuxlinkershared-librariesshared-memoryglibc

shm_open is an undefined symbol in shared library


I compiled a object file shm.o and packaged it as a shared library libshm.so

arm-linux-gnueabihf-gcc -fPIC -o shm.o -c shm.c
arm-linux-gnueabihf-gcc -shared shm.o -o libshm.so -lrt

where shm.c and output of nm libshm.so are shown as follow.

/*shm.c*/

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

void func_shm(void)
{
    int ret = shm_open("/test_shm", O_CREAT, 0644);
}



/*output of nm libshm.so*/

00000328 t $a
000002e4 t $a
00000484 t $a
...
...
00000328 t call_weak_fn
0001102c b completed.10740
         w __cxa_finalize@@GLIBC_2.4
...
...
0000034c t deregister_tm_clones
000003e0 t __do_global_dtors_aux
00010f0c t __do_global_dtors_aux_fini_array_entry
00011028 d __dso_handle
00010f10 a _DYNAMIC
00000484 t _fini
00000448 t frame_dummy
00010f08 t __frame_dummy_init_array_entry
00000498 r __FRAME_END__
0000044c T func_shm
00011000 a _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
000002e4 t _init
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
00000390 t register_tm_clones
         U shm_open@@GLIBC_2.4
0001102c d __TMC_END__

As it can see, at the second line to last, shm_open is a undefined symbol even though -lrt is appended.

As per shm_open(3) — Linux manual page; However, the version of glibc shown in the nm is 2.4.

These functions are provided in glibc 2.2 and later.

My expectation are

  1. libshm.so will have a definition of shm_open, because -lrt is appended at the end of command; Therefore shm_open will not be an undefined symbol.

  2. Any application that invokes func_shm only needs to link to libshm.so without specifying -lrt

What should be done to get this problem fixed?


Solution

  • As it can see, at the second line to last, shm_open is a undefined symbol even though -lrt is appended.

    This is expected: you are linking against librt.so. The definition of shm_open is in librt.so, and not in your library.

    My expectation is that after linking process, libshm.so will have a definition of shm_open, so shm_open should not be an undefined symbol.

    This expectation is wrong.

    What you described is what would have happened if you linked with librt.a (archive library). In that case, the linker would have pulled the object implementing shm_open() into libshm.so.

    But since you are linking against librt.so (which provides the definition), the linker simply records that librt.so is required at runtime, and that shm_open() will need to come from some external shared library at runtime. The reference to shm_open() in libshm.so remains unresolved.

    In addition, any application that invokes func_shm only needs to link to libshm.so without specifying -lrt

    This is indeed what should already happen (provided you link libshm.so against -lrt, like your command line shows).

    If the application itself doesn't call anything from librt.so, and only calls func_shm(), then linking it with gcc main.o -L/... -lshm should work.

    I tried this on Linux/x86_64, and it worked:

    gcc -fPIC -shared -o libshm.so shm.c -lrt
    
    # Verify that libshm.so requires librt.so:
    readelf -d libshm.so | grep NEEDED
     0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]
    
    gcc main.c -L. -lshm
    # success
    

    Now, you might be confused because the application linked as above will not actually run:

    ./a.out
    ./a.out: error while loading shared libraries: libshm.so: cannot open shared object file: No such file or directory
    

    But that is an entirely different problem -- the application doesn't know which directory to find libshm.so. To fix this, add -Wl,-rpath=/path/to/dir (which /path/to/dir is the directory in which libshm.so is to be found at runtime).