返回

符号表的黑科技:SysV Hash 和 Gnu Hash 深度剖析

Android

SysV Hash 和 Gnu Hash:ELF 文件中符号查找的双雄争霸

背景

ELF(可执行和可链接格式)文件是 Linux 和其他类 Unix 系统中可执行程序和共享库的基本格式。为了高效地加载和执行这些程序,ELF 文件包含了一种机制来查找符号(例如函数和变量)。有两种主要的符号查找机制:SysV Hash 和 Gnu Hash。

SysV Hash

SysV Hash 是一个简单的哈希表,它将符号名称映射到符号地址。哈希表由一个数组和一个链表组成。当查找一个符号时,系统会先计算符号名称的哈希值,然后根据哈希值找到对应的哈希桶。在哈希桶中,系统会遍历链表,逐个比较符号名称,直到找到要查找的符号。

SysV Hash 的优点在于简单高效。但它的缺点是,当符号表中的符号数量过多时,查找速度会变慢。

代码示例:

typedef struct {
  const char *name;
  void *addr;
} SymTabEntry;

/* Hashes a symbol name to an index into the hash table */
unsigned int hash(const char *name) {
  unsigned int h = 0;
  while (*name) {
    h = (h << 5) - h + *name++;
  }
  return h;
}

/* Finds a symbol in the hash table */
SymTabEntry *lookup(SymTabEntry *table, const char *name) {
  unsigned int h = hash(name);
  SymTabEntry *entry = table[h % TABLE_SIZE];
  while (entry != NULL) {
    if (strcmp(entry->name, name) == 0) {
      return entry;
    }
    entry = entry->next;
  }
  return NULL;
}

Gnu Hash

Gnu Hash 是一个更复杂的哈希表,它专为处理大规模的符号表而设计。Gnu Hash 使用双重哈希函数、桶溢出机制和符号排序机制来提高查找速度。

Gnu Hash 的优点在于,即使处理大规模的符号表,也能保持很高的查找速度。但它的缺点是,实现起来比 SysV Hash 更复杂。

代码示例:

typedef struct {
  const char *name;
  GElf_Sym sym;
  unsigned int hash;
} GnuHashEntry;

/* Hashes a symbol name to an index into the hash table */
unsigned int hash(const char *name) {
  unsigned int h = 5381;
  while (*name) {
    h = ((h << 5) + h) + *name++;
  }
  return h;
}

/* Finds a symbol in the hash table */
GnuHashEntry *lookup(GnuHashEntry *table, const char *name) {
  unsigned int h = hash(name);
  GnuHashEntry *entry = table[h % TABLE_SIZE];
  while (entry != NULL) {
    if (strcmp(entry->name, name) == 0) {
      return entry;
    }
    entry = entry->next;
  }
  return NULL;
}

SysV Hash 和 Gnu Hash 的对比

特性 SysV Hash Gnu Hash
复杂性 简单 复杂
效率 适用于小符号表 适用于大符号表
适用性 小程序 大型程序
实现 数组和链表 双重哈希、桶溢出、符号排序

如何选择

在实践中,程序员通常会根据符号表的大小来选择合适的符号查找机制。如果符号表较小,则可以使用 SysV Hash。如果符号表较大,则可以使用 Gnu Hash。

常见问题解答

  1. 什么时候使用 SysV Hash?
    当符号表较小时使用 SysV Hash。

  2. 什么时候使用 Gnu Hash?
    当符号表较大时使用 Gnu Hash。

  3. SysV Hash 和 Gnu Hash 的主要区别是什么?
    SysV Hash 使用线性哈希函数,而 Gnu Hash 使用双重哈希函数。此外,Gnu Hash 还有桶溢出机制和符号排序机制。

  4. 哪种符号查找机制更好?
    这取决于符号表的大小。SysV Hash 适用于小符号表,而 Gnu Hash 适用于大符号表。

  5. 如何实现 SysV Hash 或 Gnu Hash?
    可以使用文章中提供的代码示例来实现 SysV Hash 或 Gnu Hash。