How to export symbols from POSIX shared library and load using dlopen, dlsym - linux

We are using dlopen to read in a dynamic library on Mac OS X. Update:
This is a posix problem, the same thing fails under cygwin.
First the compile. On cygwin:
extern "C" void foo() { }
g++ -shared foo.c -o libfoo.so
nm -D libfoo.so
displays no public symbols. This appears to be the problem. If I could make them public, nm -D should display them.
Using:
nm libfoo.so | grep foo
000000x0xx0x00x0x0 T _foo
you can see the symbol is there. In Linux, this does seem to work:
nm -D foo.so
0000000000201020 B __bss_start
w __cxa_finalize
0000000000201020 D _edata
0000000000201028 B _end
0000000000000608 T _fini
0000000000000600 T foo
w __gmon_start__
00000000000004c0 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
However, even in Linux, we cannot seem to connect to the library. Here is the source code:
include
include
using namespace std;
int main() {
void* so = dlopen("foo.so", RTLD_NOW);
if (so = nullptr) {
cerr << "Can't open shared library\n";
exit(-1);
}
#if 0
const void* sym = dlsym(so, "foo");
if (sym == nullptr) {
cout << "Symbol not found\n";
}
#endif
dlclose(so);
}
If we remove the #ifdef, the above code prints "Symbol not found"
but it crashes on the dlclose.
We tried exporting LD_LIBRARY_PATH=. just to see if the library cannot be reached. And the dlopen call seems to work in any case, the return is not nullptr.
So to summarize, the library does not seem to work on Mac and Cygwin. On Linux nm -D shows the symbol in the library, but the code to load the symbol does not work.

In your example, you wrote if (so = nullptr) {, which assigns nullptr to so, and the condition is always false. -Wall is a good idea when debugging!
This alone explains why you can't load the symbol, but I also found that I needed to do dlopen("./foo.so", RTLD_NOW); because dlopen otherwise searches library paths, not the current directory.

Related

dlopen with higher precedence than link time on linux

I am compiling a C program on linux with gcc. The program itself links libc (and not much else) at build-time, so that ldd gives this output :
$ ldd myprogram
linux-vdso.so.1 => (0x00007fffd31fe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7a991c0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7a99bba000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f7a98fbb000)
At run-time this program dlopen()s library B, which dependes on a library A, which of course dlopen also loads before returning. A exports a function called re_exec, which B invokes (B is linked against A). libc also exports a function called re_exec. readelf output :
$ readelf -as A.so | grep re_exec
104: 00000000000044ff 803 FUNC GLOBAL PROTECTED 11 re_exec
469: 00000000000044ff 803 FUNC GLOBAL PROTECTED 11 re_exec
$ readelf -as /lib/x86_64-linux-gnu/libc.so.6 | grep re_exec
2165: 00000000000e4ae0 39 FUNC WEAK DEFAULT 12 re_exec##GLIBC_2.2.5
The problem is that when B invokes re_exec, the re_exec inside libc is called, NOT the re_exc inside of A.
If, when I invoke the program, I include LD_LIBRARY_PRELOAD=/path/to/A.so, then everything works as expected : Bs invocation of re_exec correctly calls A, and not libc.
The dlopen call passes RTLD_NOW | RTLD_GLOBAL. I have tried with and without DEEPBIND, and get the same behavior in either case.
I have also tried dlopen()ing A directly, before B, both with and without DEEPBIND, which did not affect the behavior.
The question : is it possible to dlopen A/B with higher precedence than libraries that were included at link-time (libc, in this case) ?
(please don't suggest that I rename the call to something other than re_exec ; not useful)
Well, you know, I can't reproduce your error. Please take a look:
puts.c:
#include <stdio.h>
int puts(const char* _s) {
return printf("custom puts: %s\n", _s);
}
built with:
cc -Wall -fPIC -c puts.c -o puts.o
cc -shared -o libputs.so -fPIC -Wl,-soname,libputs.so puts.o
foo.c:
#include <stdio.h>
void foo() {
puts("Hello, world! I'm foo!");
}
built with:
cc -Wall -fPIC -c foo.c -o foo.o
cc -L`pwd` -shared -o libfoo.so -fPIC -Wl,-soname,libfoo.so foo.o -lputs
and rundl.c:
#include <dlfcn.h>
#include <assert.h>
#include <stdio.h>
typedef void (*FooFunc)();
int main(void) {
void *foolib = dlopen("./libfoo.so", RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND);
assert(foolib != NULL);
FooFunc foo = (FooFunc)dlsym(foolib, "foo");
assert(foo != NULL);
foo();
return 0;
}
built with:
cc -c -Wall rundl.c -o rundl.o
cc -o rundl rundl.o -ldl
now we can run rundl with LD_LIBRARY_PATH=$(pwd) (it's needed because libputs.so isn't in the ld.so known paths so libfoo.so can't be loaded w/ dlopen() & Co):
alex#rhyme ~/tmp/dynlib $ LD_LIBRARY_PATH=`pwd` ./rundl
custom puts: Hello, world! I'm foo!
alex#rhyme ~/tmp/dynlib $ _
if we move libputs.so to a directory known to ld.so and (re)run ldconfig to update caches then the code runs without any special environment variables:
alex#rhyme ~/tmp/dynlib $ ldd ./libfoo.so
linux-vdso.so.1 (0x00007fff48db8000)
libputs.so => /usr/local/lib64/libputs.so (0x00007f8595450000)
libc.so.6 => /lib64/libc.so.6 (0x00007f85950a0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8595888000)
alex#rhyme ~/tmp/dynlib $ ./rundl
custom puts: Hello, world! I'm foo!
If I link libfoo.so w/o -lputs foo() invokes the standard puts() from libc. That's it.

Linking cuda object file

I have one .cu file that contains my cuda kernel, and a wrapper function that calls the kernel. I have a bunch of .c files as well, one of which contains the main function. One of these .c files calls the wrapper function from the .cu to invoke the kernel.
I compile these files as follows:
LIBS=-lcuda -lcudart
LIBDIR=-L/usr/local/cuda/lib64
CFLAGS = -g -c -Wall -Iinclude -Ioflib
NVCCFLAGS =-g -c -Iinclude -Ioflib
CFLAGSEXE =-g -O2 -Wall -Iinclude -Ioflib
CC=gcc
NVCC=nvcc
objects := $(patsubst oflib/%.c,oflib/%.o,$(wildcard oflib/*.c))
table-hash-gpu.o: table-hash.cu table-hash.h
$(NVCC) $(NVCCFLAGS) table-hash.cu -o table-hash-gpu.o
main: main.c $(objects) table-hash-gpu.o
$(CC) $(CFLAGSEXE) $(objects) table-hash-gpu.o -o udatapath udatapath.c $(LIBS) $(LIBDIR)
So far everything is fine. table-hash-gpu.cu calls a function from one of the .c files. When linking for main, I get the error that the function is not present. Can someone please tell me what is going on?
nvcc compiles both device and host code using the host C++ compiler, which implies name mangling. If you need to call a function compiled with a C compiler in C++, you must tell the C++ compiler that it uses C calling conventions. I presume that the errors you are seeing are analogous to this:
$ cat cfunc.c
float adder(float a, float b, float c)
{
return a + 2.f*b + 3.f*c;
}
$ cat cumain.cu
#include <cstdio>
float adder(float, float, float);
int main(void)
{
float result = adder(1.f, 2.f, 3.f);
printf("%f\n", result);
return 0;
}
$ gcc -m32 -c cfunc.c
$ nvcc -o app cumain.cu cfunc.o
Undefined symbols:
"adder(float, float, float)", referenced from:
_main in tmpxft_0000b928_00000000-13_cumain.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Here we have code compiled with nvcc (so the host C++ compiler) trying to call a C function and getting a link error, because the C++ code expects a mangled name for adder in the supplied object file. If the main is changed like this:
$ cat cumain.cu
#include <cstdio>
extern "C" float adder(float, float, float);
int main(void)
{
float result = adder(1.f, 2.f, 3.f);
printf("%f\n", result);
return 0;
}
$ nvcc -o app cumain.cu cfunc.o
$ ./app
14.000000
It works. Using extern "C" to qualify the declaration of the function to the C++ compiler, it will not use C++ mangling and linkage rules when referencing adder and the resulting code links correctly.

What is the command in Linux related to structure size

Hello sometime back I came across a command in Linux which prints in a file with the same name as that of the sourcecode filename but different extension,the detailed usage of sizes of the structures defined in the source code ...please let me know about any such commands
Thanks
My best guess is you are talking about nm which lists symbols from object files. A quick example:
file test.c
int int_array[10];
double double_array[10];
int main()
{
int_array[0] = 0;
double_array[0] = 0;
return 0;
}
Build an object file :
$ gcc -c test.c
Now list symbols with size information:
$ nm -S test.o
This prints something like this on my macbook:
0000000000000040 n EH_frame0
0000000000000050 C _double_array
0000000000000028 C _int_array
0000000000000000 T _main
0000000000000058 N _main.eh
Check the nm manpage for further information (http://linux.about.com/library/cmd/blcmdl1_nm.htm)

gcc, static library, external assembly function becomes undefined symbol

I have a problem with g++ building an application which links to a static library, where the latter shall contain some global functions written in external asm-files, compiled with yasm. So in the library, I have
#ifdef __cplusplus
extern "C" {
#endif
extern void __attribute__((cdecl)) interp1( char *pSrc );
extern void __attribute__((cdecl)) interp2( char *pSrc );
#ifdef __cplusplus
}
#endif
which I reference elsewhere inside the library. Then, there is the implementation in an asm-file, like this:
section .data
; (some data)
section .text
; (some text)
global _interp1
_interp1:
; (code ...)
ret
global _interp2
_interp2:
; (code ...)
ret
Compiling and Linking work fine for the library, I do
yasm -f elf32 -O2 -o interp.o interp.asm
and then
ar -rc libInterp.a objs1.o [...] objsN.o interp.o
ranlib libInterp.a
Now finally, to link the library to the main application, I do
g++ -O4 -ffast-math -DNDEBUG -fomit-frame-pointer -DARCH_X86 -fPIC -o ../bin/interp this.o that.o -lboost_thread -lpthread ./libInterp.a
and I get the errors
undefined reference to `interp1'
undefined reference to `interp2'
What am I doing wrong here? any help is appreciated.
Depending on the target type, gcc will not prepend a leading underscore to external symbols. It appears that this is the case in your scenario.
The simple fix is probably to remove the underscores from the names in your assembly file.
A couple alternatives you might consder might be to use something like one of the following macros for your symbols in the assembly file:
from http://svn.xiph.org/trunk/oggdsf/src/lib/codecs/webm/libvpx/src/vpx_ports/x86_abi_support.asm
; sym()
; Return the proper symbol name for the target ABI.
;
; Certain ABIs, notably MS COFF and Darwin MACH-O, require that symbols
; with C linkage be prefixed with an underscore.
;
%ifidn __OUTPUT_FORMAT__,elf32
%define sym(x) x
%elifidn __OUTPUT_FORMAT__,elf64
%define sym(x) x
%elifidn __OUTPUT_FORMAT__,x64
%define sym(x) x
%else
%define sym(x) _ %+ x
%endif
from http://www.dcs.warwick.ac.uk/~peter/otherstuff.html
%macro public_c_symbol 1
GLOBAL %1,_%1
%1:
_%1:
%endmacro
public_c_symbol my_external_proc:
; ...
RET

Building 16 bit os - character array not working

I am building a 16 bit operating system. But character array does not seem to work.
Here is my example kernel code:
asm(".code16gcc\n");
void putchar(char);
int main()
{
char *str = "hello";
putchar('A');
if(str[0]== 'h')
putchar('h');
return 0;
}
void putchar(char val)
{
asm("movb %0, %%al\n"
"movb $0x0E, %%ah\n"
"int $0x10\n"
:
:"m"(val)
) ;
}
It prints:
A
that means putchar function is working properly but
if(str[0]== 'h')
putchar('h');
is not working.
I am compiling it by:
gcc -fno-toplevel-reorder -nostdinc -fno-builtin -I./include -c -o ./bin/kernel.o ./source/kernel.c
ld -Ttext=0x9000 -o ./bin/kernel.bin ./bin/kernel.o -e 0x0
What should I do?
Your data segment is probably not loaded in to the target. What are you doing after the link with your brand new kernel.bin file, which is in fact an elf file ?

Resources