为什么符号绑定要保存在动态符号表中?

问题描述 投票:0回答:1

我的理解是-

(1) 符号绑定(全局/本地/弱)由链接器使用,将符号的范围限制为其定义的目标文件或链接在一起的其他目标文件/库,并确定是否可以从它们中覆盖它.

(2) 符号 可见性(默认/受保护/内部/隐藏)由 loader 使用来控制链接的二进制文件中的符号是否可见或可从不同的二进制文件中插入。

仍然,可执行文件/共享库(即链接的二进制文件)中的符号表维护符号绑定:

$ readelf --all /usr/bin/ls
...
Symbol table '.dynsym' contains 139 entries:
   Num:    Value          Size Type    **Bind**   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __ctype_toupper_loc@GLIBC_2.3 (2)
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND getenv@GLIBC_2.2.5 (3)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sigprocmask@GLIBC_2.2.5 (3)
...

我的理解正确吗?符号绑定是否以某种方式在加载/运行时使用,我缺少什么?

linker ld elf loader
1个回答
0
投票

加载/运行时是否以某种我缺少的方式使用了符号绑定?

确实如此。

通常您只会在动态符号表中看到

GLOBAL
WEAK
符号——没有理由将
PROTECTED
HIDDEN
符号放入其中。

如果您有一个 unresolved

WEAK
符号,并且该符号没有其他定义,并获取它的地址,则加载程序会将此类符号解析为
NULL

但是,如果符号是 unresolved

GLOBAL
,您将收到致命的加载器错误。

示例:

// x.c
#include <stdio.h>
extern int foo() WEAK;
void fun() {
  printf("In fun: &foo = %p\n", &foo);
}

// main.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
  void *h = dlopen("./x.so", RTLD_LAZY);
  if (h == NULL) {
    printf("Failure: %s\n", dlerror());
    return 1;
  }

  void (*fun)(void) = dlsym(h, "fun");
  printf("Success, calling fun() @%p\n", fun);
  fun();
  return 0;
}
gcc main.c -ldl

gcc -DWEAK="" -fPIC -shared -o x.so x.c &&
./a.out

Failure: ./x.so: undefined symbol: foo

现在有一个弱符号:

gcc -DWEAK="__attribute__((weak))" -fPIC -shared -o x.so x.c &&
./a.out

Success, calling fun() @0x7f6d37988109
In fun: &foo = (nil)
© www.soinside.com 2019 - 2024. All rights reserved.