dlsym 是如何工作的?

How does the dlsym work?

很容易找到如何使用 dlsym() 和该系列的其他函数,但它在内部是如何工作的?是否可以自己编写简单的 dlsym() 实现?

我想知道是否有可能实现类似的行为,但是没有 与 -ldl 链接(假设我不能这样做)。

how does it work internally?

正如 this answer 所解释的,在 GLIBC 中第一个参数实际上是指向 struct link_map 的指针,它包含足够的信息来定位共享库的动态符号 table。一旦找到符号 table 和 DT_HASHDT_GNU_HASHdlsym 使用一个或另一个散列 table 来查找给定的符号名称。

Is it possible to write own, easy implementation of dlsym()?

是的。如果你不关心查找速度,你可以简单地对动态符号table进行线性搜索。这样做的代码非常简单,特别是如果共享库有(可选)部分 header:您需要做的就是在内存中找到 .dynsym.dynstr 部分的位置,并且然后(假设您正在寻找符号 "foo"

const char *strtab = ... /* locate .dynstr */
const ElfW(Sym) *sym = ... /* locate .dynsym */

for (; sym < end_of_dynsym; ++sym) {
  if (strcmp(strtab + sym->st_name, "foo") == 0) {
    /* found it */
    return load_address + sym->st_value;
  }
}
/* symbol not found */
return NULL;

如果您确实关心查找速度(dlsym 当然关心),您将需要解码 .hash.gnu_hash,这有点复杂。你可以开始 here.