我想编写一个代码来存储原始 .elf 文件中的符号表和字符串表。我的代码实现了这一点,但缺少地址和名称:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
// ELF header structure
typedef struct {
uint8_t e_ident[16];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint64_t e_entry;
uint64_t e_phoff;
uint64_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} Elf64_Ehdr;
// Section header structure
typedef struct {
uint32_t sh_name;
uint32_t sh_type;
uint64_t sh_flags;
uint64_t sh_addr;
uint64_t sh_offset;
uint64_t sh_size;
uint32_t sh_link;
uint32_t sh_info;
uint64_t sh_addralign;
uint64_t sh_entsize;
} Elf64_Shdr;
// Symbol table entry structure
typedef struct {
uint32_t st_name;
uint8_t st_info;
uint8_t st_other;
uint16_t st_shndx;
uint32_t st_value; // normally it was uint64_t
uint64_t st_size;
uint32_t st_name2; // Extended name field
} Elf64_Sym;
Elf64_Sym* symbol_table;
char* string_table;
uint64_t stringSize;
size_t num_symbols;
struct SymbolEntry {
char name[256];
unsigned long address;
};
// Comparison function for sorting symbols based on their addresses
int compare_symbols(const void* a, const void* b) {
const Elf64_Sym* symbol_a = (const Elf64_Sym*)a;
const Elf64_Sym* symbol_b = (const Elf64_Sym*)b;
if (symbol_a->st_value < symbol_b->st_value) return -1;
if (symbol_a->st_value > symbol_b->st_value) return 1;
return 0;
}
int findTables(){
FILE* file = fopen("trace.elf", "rb");
if (!file) {
printf("Error opening file\n");
return 1;
}
// Read the ELF header
Elf64_Ehdr elf_header;
if (fread(&elf_header, sizeof(Elf64_Ehdr), 1, file) != 1) {
printf("Error reading ELF header\n");
fclose(file);
return 1;
}
// Get the section header table offset from the ELF header
fseek(file, elf_header.e_shoff, SEEK_SET);
// Read the section header table
Elf64_Shdr section_headers[elf_header.e_shnum];
if (fread(section_headers, sizeof(Elf64_Shdr), elf_header.e_shnum, file) != elf_header.e_shnum) {
printf("Error reading section headers\n");
fclose(file);
return 1;
}
// Find the symbol table and the associated string table (for symbol names)
Elf64_Shdr* symbol_table_header = NULL;
Elf64_Shdr* string_table_header = NULL;
for (int i = 0; i < elf_header.e_shnum; i++) {
if (section_headers[i].sh_type == 0x2) { // SHT_SYMTAB
symbol_table_header = §ion_headers[i];
} else if (section_headers[i].sh_type == 0x3) { // SHT_STRTAB
string_table_header = §ion_headers[i];
}
if (symbol_table_header && string_table_header) {
break; // Both tables found, exit the loop
}
}
if (!symbol_table_header || !string_table_header) {
printf("Symbol table or string table not found\n");
fclose(file);
return 1;
}
// Calculate the number of symbols in the symbol table
num_symbols = symbol_table_header->sh_size / sizeof(Elf64_Sym);
// Read the symbol table
symbol_table = (Elf64_Sym*)malloc(symbol_table_header->sh_size);
if (!symbol_table) {
printf("Error allocating memory for symbol table\n");
fclose(file);
return 1;
}
fseek(file, symbol_table_header->sh_offset, SEEK_SET);
if (fread(symbol_table, sizeof(Elf64_Sym), num_symbols, file) != num_symbols) {
printf("Error reading symbol table\n");
free(symbol_table);
fclose(file);
return 1;
}
// Read the string table
string_table = (char*)malloc(string_table_header->sh_size);
if (!string_table) {
printf("Error allocating memory for string table\n");
free(symbol_table);
fclose(file);
return 1;
}
fseek(file, string_table_header->sh_offset, SEEK_SET);
if (fread(string_table, 1, string_table_header->sh_size, file) != string_table_header->sh_size) {
printf("Error reading string table\n");
free(symbol_table);
free(string_table);
fclose(file);
return 1;
}
stringSize = string_table_header->sh_size;
fclose(file);
}
void printTables(){
printf("Address\t\tName\n");
printf("-------\t\t----\n");
// Print all symbols with their addresses and names
for (size_t j = 0; j < num_symbols; j++) {
// Check if the symbol name is valid (inside the string table)
if (symbol_table[j].st_name < stringSize) {
char* symbol_name = &string_table[symbol_table[j].st_name];
printf("0x%08x\t%s\n", symbol_table[j].st_value, symbol_name);
}
}
}
void freeSpaces(){
free(symbol_table);
free(string_table);
}
int main() {
if(findTables() == 1){
printf("Exiting...");
return 0;
}
// Sort the symbol table based on addresses
qsort(symbol_table, num_symbols, sizeof(Elf64_Sym), compare_symbols);
printTables();
freeSpaces();
return 0;
}
这是trace.elf 代码的一些输出:
0x004016d0 __do_global_dtors_aux
0x00401ac1 trace_return_values
0x00401b0c foo
0x00401b36 main
0x00401b50 handle_zhaoxin
0x00401fb0 get_common_indices.constprop.0
0x00402df0 __libc_start_main_impl
但是当使用“nm -n trace.elf”命令并以相同部分的方式获取符号表时:
00000000004016d0 t __do_global_dtors_aux
0000000000401710 t frame_dummy
0000000000401745 T get_address
0000000000401ac1 T trace_return_values
0000000000401b0c T foo
0000000000401b21 T bar
0000000000401b36 T main
0000000000401b50 t handle_zhaoxin
0000000000401d20 t handle_amd
0000000000401ed0 t call_fini
0000000000401f10 t __libc_start_call_main
您可以看到第一个输出中缺少一些地址和名称。尤其是“酒吧”。是我的代码错误还是有其他问题?
原始 .elf 文件中的符号表和字符串表。
您应该知道,带有
.e_type
为 ET_DYN
或 ET_EXEC
的 ELF 文件可能有 两个 符号表——“常规”符号表和“动态”符号表:
readelf -WS /tmp/a.out | egrep 'symtab|dynsym'
[ 7] .dynsym DYNSYM 0000000000000410 000410 000120 18 A 8 1 8
[30] .symtab SYMTAB 0000000000000000 003080 000468 18 31 21 8
最多 三
SYMTAB
部分,例如
readelf -WS /tmp/a.out | egrep 'STRTAB'
[ 8] .dynstr STRTAB 0000000000000530 000530 000139 00 A 0 0 1
[31] .strtab STRTAB 0000000000000000 0034e8 00035a 00 0 0 1
[32] .shstrtab STRTAB 0000000000000000 003842 00012c 00 0 0 1
您的代码是错误的,因为它选择了它找到的第一个
STRTAB
部分,这可能不是 SYMTAB
实际引用的部分。
例如,对于上面的可执行文件,您的代码将选择
.dynstr
而不是 .strtab
(这正是您的意图)。
找到
SYMTAB
部分后,您必须查看 symbol_table_header->sh_link
以找到您的 STRTAB
引用的正确 SYMTAB
部分(sh_link
是上面的第 9 列;您可以看到 .dynsym
链接)参见第 8 节,以及 .symtab
参见第 31 节。
附注除非您的程序是在没有
/usr/include/elf.h
的系统上构建的,否则这样做是一个非常糟糕的主意™:
// ELF header structure
typedef struct {
uint8_t e_ident[16];
uint16_t e_type;
uint16_t e_machine;
...
您应该使用系统提供的
<elf.h>
来代替。
如果您在没有
<elf.h>
的系统上构建此系统,那么这样做 仍然 是一个非常糟糕的主意:
if (section_headers[i].sh_type == 0x2) { // SHT_SYMTAB
相反,编写这样的代码:
#ifndef SHT_SYMTAB
#define SHT_SYMTAB 2
#endif
...
if (section_headers[i].sh_type == SHT_SYMTAB) {
...