我正在尝试通过 buildroot 交叉编译包。该包可以通过
dlopen
调用 .so 共享库的路径来调用自定义代码。但是,自定义代码需要来自调用 dlopen 的父可执行文件的符号。因此,共享库是通过包含 -I
指令到父可执行文件的源代码目录以及 -shared -fPIC
来构建的。
在 Debian 上,父可执行文件打开共享库,并根据
LD_DEBUG=all
通过搜索父可执行文件的路径找到符号并正确加载库。
在 buildroot 上,父可执行文件打开共享库,但在尝试从可执行文件本身动态链接符号时失败。根据
LD_DEBUG=all
,有一个symbol lookup error: undefined symbol
。
在我的测试中,我发现 debian 二进制文件可以从 debian 和 buildroot 系统加载共享库,并在 debian 和 buildroot 系统上运行。因此,问题很可能在于两个父可执行文件之间的差异。
我已经比较了 readelf -a 输出(下面的头),并且没有看到 debian 和 buildroot 二进制文件之间有任何真正的区别。最值得注意的是,buildroot 库找不到的符号出现在两个二进制文件中(也在下面)
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: AArch64
Version: 0x1
Entry point address: 0x34a00
Start of program headers: 64 (bytes into file)
Start of section headers: 1933304 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
失败的符号:
5964: 0000000000049714 288 FUNC GLOBAL DEFAULT 13 plugin_hook_register
此外,我已经尝试/检查过:
LD_LIBRARY_PATH
任何关于如何进一步检查二进制文件以确定为什么无法找到该符号的想法都非常感谢。
编辑:
nm -D
每个二进制的符号输出:
错误的二进制文件(GNU nm 2.40,完整输出)-->
U abort@GLIBC_2.17
U accept@GLIBC_2.17
U access@GLIBC_2.17
U arc4random@GLIBC_2.36
U atof@GLIBC_2.17
U atoi@GLIBC_2.17
U atol@GLIBC_2.17
U atoll@GLIBC_2.17
U backtrace@GLIBC_2.17
U backtrace_symbols@GLIBC_2.17
U bind@GLIBC_2.17
U calloc@GLIBC_2.17
U chdir@GLIBC_2.17
U chmod@GLIBC_2.17
U clearerr@GLIBC_2.17
U clock_gettime@GLIBC_2.17
U close@GLIBC_2.17
U closedir@GLIBC_2.17
U closelog@GLIBC_2.17
U connect@GLIBC_2.17
U __ctype_b_loc@GLIBC_2.17
U __ctype_tolower_loc@GLIBC_2.17
U __ctype_toupper_loc@GLIBC_2.17
w __cxa_finalize@GLIBC_2.17
U dlclose@GLIBC_2.34
U dlerror@GLIBC_2.34
U dlopen@GLIBC_2.34
U dlsym@GLIBC_2.34
U dup2@GLIBC_2.17
U epoll_create1@GLIBC_2.17
U epoll_ctl@GLIBC_2.17
U epoll_wait@GLIBC_2.17
U __errno_location@GLIBC_2.17
U eventfd@GLIBC_2.17
U exit@GLIBC_2.17
U fchmod@GLIBC_2.17
U fchown@GLIBC_2.17
U fclose@GLIBC_2.17
U fcntl64@GLIBC_2.28
U feof@GLIBC_2.17
U ferror@GLIBC_2.17
U fflush@GLIBC_2.17
U fgets@GLIBC_2.17
U fileno@GLIBC_2.17
U fopen64@GLIBC_2.17
U fork@GLIBC_2.17
U fprintf@GLIBC_2.17
U fputc@GLIBC_2.17
U fputs@GLIBC_2.17
U fread@GLIBC_2.17
U free@GLIBC_2.17
U freeaddrinfo@GLIBC_2.17
U fstat64@GLIBC_2.33
U fsync@GLIBC_2.17
U ftruncate64@GLIBC_2.17
U fwrite@GLIBC_2.17
U getaddrinfo@GLIBC_2.17
U __getauxval@GLIBC_2.17
U getc@GLIBC_2.17
U getcwd@GLIBC_2.17
U getenv@GLIBC_2.17
U geteuid@GLIBC_2.17
U getline@GLIBC_2.17
U getpagesize@GLIBC_2.17
U getpeername@GLIBC_2.17
U getpgid@GLIBC_2.17
U getpid@GLIBC_2.17
U getsockname@GLIBC_2.17
U getsockopt@GLIBC_2.17
U gettimeofday@GLIBC_2.17
w __gmon_start__
U isatty@GLIBC_2.17
U __isoc23_sscanf@GLIBC_2.38
U __isoc23_strtol@GLIBC_2.38
U __isoc23_strtoull@GLIBC_2.38
U __isoc99_fscanf@GLIBC_2.17
U __isoc99_sscanf@GLIBC_2.17
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U kill@GLIBC_2.17
U __libc_start_main@GLIBC_2.34
U listen@GLIBC_2.17
U localtime@GLIBC_2.17
U localtime_r@GLIBC_2.17
U lockf64@GLIBC_2.17
U lseek64@GLIBC_2.17
U lstat64@GLIBC_2.33
U malloc@GLIBC_2.17
U memcmp@GLIBC_2.17
U memcpy@GLIBC_2.17
U __memcpy_chk@GLIBC_2.17
U memmove@GLIBC_2.17
U memset@GLIBC_2.17
U __memset_chk@GLIBC_2.17
U mkdir@GLIBC_2.17
U mmap64@GLIBC_2.17
U mremap@GLIBC_2.17
U MsQuicClose@msquic
U MsQuicOpenVersion@msquic
U munmap@GLIBC_2.17
U nanosleep@GLIBC_2.17
U open64@GLIBC_2.17
U opendir@GLIBC_2.17
U openlog@GLIBC_2.17
U perror@GLIBC_2.17
U pipe@GLIBC_2.17
U printf@GLIBC_2.17
U pthread_attr_destroy@GLIBC_2.17
U pthread_attr_init@GLIBC_2.17
U pthread_condattr_destroy@GLIBC_2.17
U pthread_condattr_init@GLIBC_2.17
U pthread_condattr_setclock@GLIBC_2.34
U pthread_cond_broadcast@GLIBC_2.17
U pthread_cond_destroy@GLIBC_2.17
U pthread_cond_init@GLIBC_2.17
U pthread_cond_signal@GLIBC_2.17
U pthread_cond_timedwait@GLIBC_2.17
U pthread_cond_wait@GLIBC_2.17
U pthread_create@GLIBC_2.34
U pthread_join@GLIBC_2.34
U pthread_mutexattr_destroy@GLIBC_2.34
U pthread_mutexattr_init@GLIBC_2.34
U pthread_mutexattr_settype@GLIBC_2.34
U pthread_mutex_destroy@GLIBC_2.17
U pthread_mutex_init@GLIBC_2.17
U pthread_mutex_lock@GLIBC_2.17
U pthread_mutex_trylock@GLIBC_2.34
U pthread_mutex_unlock@GLIBC_2.17
U pthread_rwlock_destroy@GLIBC_2.34
U pthread_rwlock_init@GLIBC_2.34
U pthread_rwlock_rdlock@GLIBC_2.34
U pthread_rwlock_unlock@GLIBC_2.34
U pthread_rwlock_wrlock@GLIBC_2.34
U pthread_self@GLIBC_2.17
U pthread_setname_np@GLIBC_2.34
U pthread_sigmask@GLIBC_2.32
U putchar@GLIBC_2.17
U puts@GLIBC_2.17
U read@GLIBC_2.17
U readdir64@GLIBC_2.17
U readlink@GLIBC_2.17
U readv@GLIBC_2.17
U realloc@GLIBC_2.17
U __register_atfork@GLIBC_2.17
U remove@GLIBC_2.17
U rename@GLIBC_2.17
U rewind@GLIBC_2.17
U rmdir@GLIBC_2.17
U sendmsg@GLIBC_2.17
U setsid@GLIBC_2.17
U setsockopt@GLIBC_2.17
U shutdown@GLIBC_2.17
U sigaction@GLIBC_2.17
U sigaddset@GLIBC_2.17
U sigemptyset@GLIBC_2.17
U sleep@GLIBC_2.17
U snprintf@GLIBC_2.17
U socket@GLIBC_2.17
U socketpair@GLIBC_2.17
U sprintf@GLIBC_2.17
U __sprintf_chk@GLIBC_2.17
U __stack_chk_fail@GLIBC_2.17
U __stack_chk_guard@GLIBC_2.17
U stat64@GLIBC_2.33
U stderr@GLIBC_2.17
U stdin@GLIBC_2.17
U stdout@GLIBC_2.17
U strcasecmp@GLIBC_2.17
U strcat@GLIBC_2.17
U __strcat_chk@GLIBC_2.17
U strchr@GLIBC_2.17
U strcmp@GLIBC_2.17
U strcpy@GLIBC_2.17
U __strcpy_chk@GLIBC_2.17
U strcspn@GLIBC_2.17
U strdup@GLIBC_2.17
U strerror@GLIBC_2.17
U strftime@GLIBC_2.17
U strlcpy@GLIBC_2.38
U strlen@GLIBC_2.17
U strncasecmp@GLIBC_2.17
U strncmp@GLIBC_2.17
U strncpy@GLIBC_2.17
U __strncpy_chk@GLIBC_2.17
U strnlen@GLIBC_2.17
U strrchr@GLIBC_2.17
U strstr@GLIBC_2.17
U strtod@GLIBC_2.17
U strtok@GLIBC_2.17
U strtok_r@GLIBC_2.17
U syscall@GLIBC_2.17
U sysconf@GLIBC_2.17
U system@GLIBC_2.17
U time@GLIBC_2.17
U unlink@GLIBC_2.17
U utimes@GLIBC_2.17
U vfprintf@GLIBC_2.17
U vprintf@GLIBC_2.17
U vsnprintf@GLIBC_2.17
U __vsyslog_chk@GLIBC_2.17
U write@GLIBC_2.17
U writev@GLIBC_2.17
良好的二进制(GNU nm 2.40,过滤输出)
0000000000049714 T plugin_hook_register
buildroot 二进制文件缺少这些符号,但仅来自 nm 而不是 readelf。
如何进一步检查二进制文件以确定找不到该符号的原因
该符号存在于“常规”符号表中,但不存在于动态符号表中。只有动态符号表中存在的符号才会参与动态链接。
动态符号表中缺少的已定义符号必须已被有意隐藏(默认情况下,所有符号均已导出)。
这可以通过多种方式发生:
__attribute__((visibility("hidden"))
或 "protected"
-fvisibility=hidden
标志因此请在两个构建环境中寻找上述差异。换句话说,比较链接和编译命令行、比较链接器脚本(如果有)、比较预处理的源。其中至少有一个必须不同。