1. 生成原始动态库的源文件
attr.h
#include <cstdio>
void not_hidden() __attribute__((visibility("default")));
void is_hidden() __attribute__((visibility("hidden")));
void Log(FILE* f, const char* format, ...)
#if defined(__GNUC__) || defined(__clang__)
__attribute__((__format__(__printf__, 2, 3)))
#endif
;
#if defined(__clang__)
#define UNAVAILABLE_ATTRIBUTE __attribute__((__unavailable__))
#else
#define UNAVAILABLE_ATTRIBUTE
#endif
void UnavailableFunc() UNAVAILABLE_ATTRIBUTE;
void StructAligned();
void StructPacked();
attr.cpp
#include "attr.h"
#include <cstdarg>
#include <ctime>
#include <sys/time.h>
void not_hidden() {
printf("export symbol not_hidden\n");
}
void is_hidden() {
printf("export symbol is_hidden\n");
}
static void Logv(FILE* f, const char* format, va_list ap) {
char buffer[256];
char* base = buffer;
char* p = base;
char* limit = p + sizeof(buffer);
struct timeval now_tv;
gettimeofday(&now_tv, NULL);
const time_t seconds = now_tv.tv_sec;
struct tm t;
localtime_r(&seconds, &t);
p += snprintf(p, limit-p,
"%04d-%02d-%02d %02d:%02d:%02d.%06d ",
t.tm_year+1900,
t.tm_mon + 1,
t.tm_mday,
t.tm_hour, t.tm_min, t.tm_sec, static_cast<int>(now_tv.tv_usec));
if (p < limit) {
va_list backup_ap;
va_copy(backup_ap, ap);
p += vsnprintf(p, limit-p, format, backup_ap);
va_end(backup_ap);
}
if (p >= limit) {
p = limit - 1;
}
*p++ = '\n';
fwrite(base, 1, p - base, f);
fflush(f);
}
void Log(FILE* f, const char* format, ...) {
if (f != NULL) {
va_list ap;
va_start(ap, format);
Logv(f, format, ap);
va_end(ap);
}
}
void UnavailableFunc() {
printf("Should not see this message!\n");
}
typedef struct {
char member1_;
int member2_;
short member3_;
} FamilyWithoutAligned;
typedef struct {
char member1_;
int member2_;
short member3_;
} __attribute__((__aligned__(1))) FamilyWithAlignedOne;
typedef struct {
char member1_;
int member2_;
short member3_;
} __attribute__((__aligned__(8))) FamilyWithAligned8;
void StructAligned() {
Log(stderr, "FamilyWithoutAligned size is %u", sizeof(FamilyWithoutAligned));
Log(stderr, "FamilyWithAlignedOne size is %u", sizeof(FamilyWithAlignedOne));
Log(stderr, "FamilyWithAligned8 size is %u", sizeof(FamilyWithAligned8));
}
typedef struct {
char member1_;
int member2_;
short member3_;
} __attribute__((__packed__)) FamilyWithPacked;
void StructPacked() {
Log(stderr, "FamilyWithoutPacked size is %u", sizeof(FamilyWithoutAligned));
Log(stderr, "FamilyWithPacked size is %u", sizeof(FamilyWithPacked));
}
生成libattr_hash.so动态库文件,通过eu-readelf命令查看动态符号表及.gnu.hash节
# eu-readelf -s libattr_hash.so
Symbol table [ 3] '.dynsym' contains 18 entries:
2 local symbols String table: [ 4] '.dynstr'
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UNDEF
1: 00000000000005d0 0 SECTION LOCAL DEFAULT 8
2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UNDEF snprintf
3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UNDEF puts
4: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UNDEF vsnprintf
5: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UNDEF fflush
6: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UNDEF gettimeofday
7: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UNDEF stderr
8: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UNDEF localtime_r
9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UNDEF fwrite
10: 00000000000008cb 76 FUNC GLOBAL DEFAULT 8 _Z12StructPackedv
11: 0000000000201058 0 NOTYPE GLOBAL DEFAULT 13 _edata
12: 0000000000201058 0 NOTYPE GLOBAL DEFAULT 13 _end
13: 0000000000201058 0 NOTYPE GLOBAL DEFAULT 13 __bss_start
14: 000000000000085c 111 FUNC GLOBAL DEFAULT 8 _Z13StructAlignedv
15: 00000000000005d0 18 FUNC GLOBAL DEFAULT 8 _Z10not_hiddenv
16: 000000000000084a 18 FUNC GLOBAL DEFAULT 8 _Z15UnavailableFuncv
17: 0000000000000798 178 FUNC GLOBAL DEFAULT 8 _Z3LogP8_IO_FILEPKcz
# eu-readelf -x .gnu.hash libattr_hash.so
Hex dump of section [2] '.gnu.hash', 68 bytes at offset 0x1b8:
0x00000000 03000000 0a000000 01000000 06000000 ................
0x00000010 c8462201 100002aa 0a000000 0d000000 .F".............
0x00000020 0f000000 64aed74b 4245d5ec bbe3927c ....d..KBE.....|
0x00000030 d871581c 518fb5ee b0032a29 8a915ec0 .qX.Q.....*)..^.
0x00000040 c99fbd68 ...h
2. .gnu.hash节生成程序
//gcc -std=c99 -o elf_hash_test elf_hash_test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
unsigned long
elf_hash(const unsigned char *name)
{
unsigned int h = 0, g;
while (*name)
{
h = (h << 4) + *name++;
if (g = h & 0xf0000000)
h ^= g >> 24;
h &= ~g;
}
return h;
}
uint32_t elf_new_hash(const unsigned char* name) {
uint32_t h = 5381;
for (unsigned char c = *name; c != '\0'; c = *++name) {
h = h*33 + c;
//h = ((h << 5) + h) + c;
}
return h;
}
typedef struct {
uint32_t idx;
uint32_t ndx; //0-UNDEF
unsigned char* symbol;
} Sym;
static int cmpstringp(const void* p1, const void* p2) {
return strcmp(*(char* const*)p1, *(char* const*)p2);
}
static int cmpIndex(const void* p1, const void* p2) {
return ((Sym *)p1)->idx - ((Sym *)p2)->idx;
}
static Sym symbols[] = {
{0, 0, "NULL1"},
{1, 0, "NULL2"},
{2, 0, "snprintf"},
{3, 0, "puts"},
{4, 0, "vsnprintf"},
{5, 0, "fflush"},
{6, 0, "gettimeofday"},
{7, 0, "stderr"},
{8, 0, "localtime_r"},
{9, 0, "fwrite"},
{10, 1, "_Z12StructPackedv"},
{11, 1, "_edata"},
{12, 1, "_end"},
{13, 1, "__bss_start"},
{14, 1, "_Z13StructAlignedv"},
{15, 1, "_Z10not_hiddenv"},
{16, 1, "_Z15UnavailableFuncv"},
{17, 1, "_Z3LogP8_IO_FILEPKcz"}
};
typedef struct {
//const Sym* dyn_sym;
uint32_t nbuckets;
uint32_t first_sym_ndx;
uint32_t maskwords_bm;
uint32_t shift2;
uint64_t *bloom;
uint32_t *buckets;
uint32_t *hash_val;
} obj_state_t;
void DumpObjState(const obj_state_t* obj_state, size_t sym_cnt) {
size_t bloom_size = obj_state->maskwords_bm*sizeof(uint64_t);
size_t bucket_size = obj_state->nbuckets*sizeof(uint32_t);
size_t val_size = sym_cnt*sizeof(uint32_t);
size_t obj_size = 4*4 + bloom_size + bucket_size + val_size;
unsigned char* pObj = (unsigned char*)obj_state;
size_t p_chg_size = 16;
for (size_t i=0; i<obj_size; i++) {
if (i == 16) {
pObj = (unsigned char*)obj_state->bloom;
} else if (i == 16+bloom_size) {
pObj = (unsigned char*)obj_state->buckets;
} else if (i == 16+bloom_size+bucket_size) {
pObj = (unsigned char*)obj_state->hash_val;
}
if (i % 16 == 0)
printf("\n0x%08x ", i);
printf("%02x", *pObj++);
if ((i+1) % 4 == 0)
printf(" ");
}
printf("\n");
}
#define nBucket 3
int main(int argc, char* argv[]) {
size_t count = sizeof(symbols)/sizeof(Sym);
//qsort(symbols, count, sizeof(Sym), cmpIndex);
uint32_t sym_ndx = 0;
for (int i=0; i<count; ++i) {
//unsigned long v = elf_Hash(symbols[i].symbol);
//printf("Hash %s = %lu, bucket idx = %d\n", symbols[i].symbol, v, v%nBucket);
const Sym* sym = &symbols[i];
if (sym->ndx == 0) {
continue;
} else if (sym_ndx == 0) {
sym_ndx = i;
break;
}
//uint32_t h = elf_new_hash(sym->symbol);
}
uint32_t sym_cnt = count - sym_ndx;
obj_state_t obj_state;
obj_state.nbuckets = 3;
obj_state.first_sym_ndx = sym_ndx;
obj_state.maskwords_bm = 1;
obj_state.shift2 = 6;
obj_state.bloom = (uint64_t *)calloc(obj_state.maskwords_bm, sizeof(uint64_t));
obj_state.buckets = (uint32_t *)calloc(obj_state.nbuckets, sizeof(uint32_t));
obj_state.hash_val = (uint32_t *)calloc(sym_cnt, sizeof(uint32_t));
size_t bloom_size = obj_state.maskwords_bm*sizeof(uint64_t);
size_t bucket_size = obj_state.nbuckets*sizeof(uint32_t);
size_t val_size = sym_cnt*sizeof(uint32_t);
printf("Before gen .gnu.hash:");
DumpObjState(&obj_state, sym_cnt);
uint32_t c = sizeof(uint64_t)*8;
for (size_t i=sym_ndx; i<count; ++i) {
const Sym* sym = &symbols[i];
uint32_t h1 = elf_new_hash(sym->symbol);
uint32_t h2 = h1 >> obj_state.shift2;
//printf("Hash %s = %lu, bucket idx = %d\n", symbols[i].symbol, h1, h1%obj_state.nbuckets);
uint32_t n = (h1 / c) % obj_state.maskwords_bm;
uint64_t bitmask = ((uint64_t)1 << (h1 % c)) | ((uint64_t)1 << (h2 % c));
//printf("n = %u, bitmask = %lu, h1 shift = %d, h2 shift = %d\n", n, bitmask, h1%c, h2%c);
obj_state.bloom[n] |= bitmask;
size_t bucket_idx = h1 % obj_state.nbuckets;
n = obj_state.buckets[bucket_idx];
if (n == 0) {
obj_state.buckets[bucket_idx] = i;
}
uint32_t lsb = (i == count - 1) || ((h1 % obj_state.nbuckets) != (elf_new_hash(symbols[i+1].symbol) % obj_state.nbuckets));
uint32_t h_val = (h1 & ~1) | lsb;
//printf("i = %u, h_val = %08x\n", i, h_val);
obj_state.hash_val[i-obj_state.first_sym_ndx] = h_val;
}
printf("After gen .gnu.hash:");
DumpObjState(&obj_state, sym_cnt);
printf("\n");
free(obj_state.bloom);
free(obj_state.buckets);
free(obj_state.hash_val);
return 0;
}
运行结果:
# ./elf_hash_test
Before gen .gnu.hash:
0x00000000 03000000 0a000000 01000000 06000000
0x00000010 00000000 00000000 00000000 00000000
0x00000020 00000000 00000000 00000000 00000000
0x00000030 00000000 00000000 00000000 00000000
0x00000040 00000000
After gen .gnu.hash:
0x00000000 03000000 0a000000 01000000 06000000
0x00000010 c8462201 100002aa 0a000000 0d000000
0x00000020 0f000000 64aed74b 4245d5ec bbe3927c
0x00000030 d871581c 518fb5ee b0032a29 8a915ec0
0x00000040 c99fbd68
3. 参考链接