FreeBSD dlopen()

slonishka

имеется app.h:
#ifndef __APP_H__
#define __APP_H__

int func(int arg);

#endif /* __APP_H__ */

app.c:
#include <dlfcn.h>
#include <stdio.h>
#include "app.h"

int func(int arg)
{
return arg;
}

int main(int argc, char **argv)
{
if (2 > argc)
{
fprintf(stderr, "Usage: %s /path/to/library.so\n", argv[0]);
return -1;
}

char *path = argv[1];
int flags = RTLD_NOW;

void *handle = dlopen(path, flags);

if (NULL == handle)
{
fprintf(stderr, "dlopen(%s, %d): %s\n", path, flags, dlerror;
return -1;
}

return 0;
}

lib.c:
#include "app.h"

int lib_handle(int arg)
{
return func(arg);
}

собираем:
app.c -> tmpdynapp
lib.c -> libtmpdynlib.so

запускаем на фрибсд:
freebsd ~ $ tmpdynapp ./libtmpdynlib.so 
dlopen(./libtmpdynlib.so, 2): ./libtmpdynlib.so: Undefined symbol "func"

под линуксом все окейно.
что-то можно сделать или надо func выносить в libtmpdynapp.a, который линковать к libtmpdynlib.so?
Всякие SUSv4 мануалы тоже говорят, что:
Any object loaded by dlopen that requires relocations against global symbols can reference the symbols in the original process image file, any objects loaded at program start-up, from the object itself as well as any other object included in the same dlopen invocation, and any objects that were loaded in any dlopen invocation and which specified the RTLD_GLOBAL flag.
В мануале FreeBSD таких строк нету. Неужели дээльопнутый бинарь под фрей
не может референсить символы дээльопающего приложения?
Еще подумал, что поможет:
dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);

но не помогло.

slonishka

вот символы:
freebsd ~ $ nm tmpdynapp 
0000000000500948 D _DYNAMIC
0000000000500b00 D _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
0000000000500ae0 d __CTOR_END__
0000000000500ad8 d __CTOR_LIST__
0000000000500af0 d __DTOR_END__
0000000000500ae8 d __DTOR_LIST__
0000000000500940 r __FRAME_END__
0000000000500af8 d __JCR_END__
0000000000500af8 d __JCR_LIST__
0000000000500b58 A __bss_start
0000000000400740 t __do_global_ctors_aux
0000000000400620 t __do_global_dtors_aux
00000000005008a8 D __dso_handle
00000000005008a0 D __progname
U @FBSD_1.0
0000000000500b58 A _edata
0000000000500b68 A _end
0000000000400774 T _fini
00000000004004e8 T _init
U @FBSD_1.0
0000000000400580 T _start
00000000004001e0 r abitag
U @FBSD_1.0
0000000000500b58 b completed.5133
U @FBSD_1.0
U @FBSD_1.0
0000000000500b60 B environ
U @FBSD_1.0
U @FBSD_1.0
0000000000400660 t frame_dummy
0000000000400690 T func
00000000004006a0 T main
00000000005008b0 d p.5131
U @FBSD_1.0

freebsd ~ $ nm libtmpdynlib.so 
00000000001008e0 A _DYNAMIC
0000000000100a98 A _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
0000000000100a78 d __CTOR_END__
0000000000100a70 d __CTOR_LIST__
0000000000100a88 d __DTOR_END__
0000000000100a80 d __DTOR_LIST__
00000000001008d8 r __FRAME_END__
0000000000100a90 d __JCR_END__
0000000000100a90 d __JCR_LIST__
0000000000100ad0 A __bss_start
w __cx@FBSD_1.0
0000000000000790 t __do_global_ctors_aux
0000000000000700 t __do_global_dtors_aux
0000000000100898 d __dso_handle
0000000000100ad0 A _edata
0000000000100ad8 A _end
00000000000007c8 T _fini
00000000000006b8 T _init
0000000000100ad0 b completed.5133
0000000000000750 t frame_dummy
U func
0000000000000780 T lib_handle
00000000001008a0 d p.5131

Maurog

может, компилятор выбросил определение функции func, т.к. никто не использует ее в ехе-шнике?
можно еще явно прописать ей visibility

slonishka

при этом возможно, что nm показывает, что она "T"?
freebsd ~ $ nm tmpdynapp 
...
0000000000400690 T func
...

что такое visibility? :)
Upd: попробовал заюзать func(0); перед ретурном в app.c - не помогло.

Maurog

что такое visibility?
имелось в виду это http://gcc.gnu.org/wiki/Visibility
ну да сомневаюсь, что поможет
я никогда не вызывал из .so функции главного ехе-шника :(

doublemother

что такое visibility? :)
Экспортирование символов для окружающих. В линуксах по умолчанию все символы экспортируются, в отличие от винды, где надо об этом говорить. Как во фре с этим — хз, но у гцц можно перед функцией сказать что-то типа:
__attribute__ visibility ("default"

slonishka

фря говорит:
app.h:4: error: visibility argument must be one of "default", "hidden", "protected" or "internal"

с "default" не помогает, остальные наверное еще более скрытые.
ну я тоже в эту штуку не особо верю. если никто ничего более крутого не скажет,
попробую, конечно, почитать вики-ссылку Ужоса.

doublemother

Ну чисто ради поржать попробуй ещё в флаги dlopen добавить RTLD_GLOBAL, вдруг прокатит. Хотя эффект по идее там немножко в противоположную сторону должен работать.
Ещё можно ради поржать попробовать сделать
 dlopen[argv[0], RTLD_NOW|RTLD_GLOBAL);

Но в то, что это прокатит, я верю ещё меньше, всё-таки это не динамическая либа.

doublemother

О, кстати, Бачан, я открыл фрибсдшный ман к dlopen и там прямым текстом сказано:
ELF executables need to be linked using the -export-dynamic option to ld(1) for symbols defined in the executable to become visible to dlsym (.);

Вероятно, поэтому либа и не видит.

slonishka

dlopen[argv[0], RTLD_NOW|RTLD_GLOBAL);
да, это я тоже колдовал, просто не стал в посте упоминать.
ELF executables need to be linked using the -export-dynamic option to ld(1) for symbols defined in the executable to become visible to dlsym (.);
сработало, спасибо! =)
Оставить комментарий
Имя или ник:
Комментарий: