获取可执行文件中文本部分的开始和结束地址

我需要获取可执行文件部分的开始和结束地址。 我怎么才能得到它?

我可以从_init符号或_start符号获取起始地址,但是结束地址呢? 在开始.rodata部分之前,我应该考虑text部分的结束地址是最后一个地址吗?

或者我应该编辑默认的ld脚本并添加我自己的符号来指示文本部分的开头和结尾,并在编译时将其传递给GCC? 在这种情况下,我应该在哪里放置新符号,我应该考虑init和fini部分吗?

获取文本部分的开始和结束地址的好方法是什么?

基于ELF的平台的GNU binutils默认链接描述文件通常定义了许多不同的符号,可用于查找各个部分的开头和结尾。

文本部分的结尾通常由三个不同的符号选择引用: etext_etext__etext ; 开头可以找到__executable_start 。 (请注意,这些符号通常使用PROVIDE()机制导出,这意味着如果可执行文件中的其他内容定义它们而不是仅仅引用它们,它们将被覆盖。特别是这意味着_etext__etext可能是更安全的选择比etext 。)

例:

 $ cat etext.c #include  extern char __executable_start; extern char __etext; int main(void) { printf("0x%lx\n", (unsigned long)&__executable_start); printf("0x%lx\n", (unsigned long)&__etext); return 0; } $ gcc -Wall -o etext etext.c $ ./etext 0x8048000 0x80484a0 $ 

我不相信这些符号中的任何符号都是由任何标准指定的,因此不应该假设它是可移植的(我不知道甚至GNU binutils是否为所有基于ELF的平台提供它们,或者是否符号集提供已经改变了不同的binutils版本),虽然我想如果a)你正在做一些需要这些信息的东西,并且b)你正在考虑被黑客的链接器脚本作为一个选项,那么可移植性并不是一个太大的问题!

要查看在特定平台上构建特定事物时获得的确切符号集,请将--verbose标志赋予ld (或-Wl,--verbosegcc )以打印它选择使用的链接描述文件(有实际上有几个不同的默认链接器脚本,它们根据链接器选项和您正在构建的对象类型而有所不同。

说“文本”段是不正确的,因为可能有多个(保证通常情况下你有共享库,但是单个ELF二进制文件仍然可能有多个具有相同标志的PT_LOAD部分) 。

以下示例程序转储dl_iterate_phr返回的所有信息。 您对PT_LOAD类型的任何段都感兴趣, PT_LOAD带有PF_X标志(请注意, PT_GNU_STACK-z execstack传递给链接器, PT_GNU_STACK将包含该标志,因此您确实必须同时检查两者)。

 #define _GNU_SOURCE #include  #include  #include  #include  const char *type_str(ElfW(Word) type) { switch (type) { case PT_NULL: return "PT_NULL"; // should not be seen at runtime, only in the file! case PT_LOAD: return "PT_LOAD"; case PT_DYNAMIC: return "PT_DYNAMIC"; case PT_INTERP: return "PT_INTERP"; case PT_NOTE: return "PT_NOTE"; case PT_SHLIB: return "PT_SHLIB"; case PT_PHDR: return "PT_PHDR"; case PT_TLS: return "PT_TLS"; case PT_GNU_EH_FRAME: return "PT_GNU_EH_FRAME"; case PT_GNU_STACK: return "PT_GNU_STACK"; case PT_GNU_RELRO: return "PT_GNU_RELRO"; case PT_SUNWBSS: return "PT_SUNWBSS"; case PT_SUNWSTACK: return "PT_SUNWSTACK"; default: if (PT_LOOS <= type && type <= PT_HIOS) { return "Unknown OS-specific"; } if (PT_LOPROC <= type && type <= PT_HIPROC) { return "Unknown processor-specific"; } return "Unknown"; } } const char *flags_str(ElfW(Word) flags) { switch (flags & (PF_R | PF_W | PF_X)) { case 0 | 0 | 0: return "none"; case 0 | 0 | PF_X: return "x"; case 0 | PF_W | 0: return "w"; case 0 | PF_W | PF_X: return "wx"; case PF_R | 0 | 0: return "r"; case PF_R | 0 | PF_X: return "rx"; case PF_R | PF_W | 0: return "rw"; case PF_R | PF_W | PF_X: return "rwx"; } __builtin_unreachable(); } static int callback(struct dl_phdr_info *info, size_t size, void *data) { int j; (void)data; printf("object \"%s\"\n", info->dlpi_name); printf(" base address: %p\n", (void *)info->dlpi_addr); if (size > offsetof(struct dl_phdr_info, dlpi_adds)) { printf(" adds: %lld\n", info->dlpi_adds); } if (size > offsetof(struct dl_phdr_info, dlpi_subs)) { printf(" subs: %lld\n", info->dlpi_subs); } if (size > offsetof(struct dl_phdr_info, dlpi_tls_modid)) { printf(" tls modid: %zu\n", info->dlpi_tls_modid); } if (size > offsetof(struct dl_phdr_info, dlpi_tls_data)) { printf(" tls data: %p\n", info->dlpi_tls_data); } printf(" segments: %d\n", info->dlpi_phnum); for (j = 0; j < info->dlpi_phnum; j++) { const ElfW(Phdr) *hdr = &info->dlpi_phdr[j]; printf(" segment %2d\n", j); printf(" type: 0x%08X (%s)\n", hdr->p_type, type_str(hdr->p_type)); printf(" file offset: 0x%08zX\n", hdr->p_offset); printf(" virtual addr: %p\n", (void *)hdr->p_vaddr); printf(" physical addr: %p\n", (void *)hdr->p_paddr); printf(" file size: 0x%08zX\n", hdr->p_filesz); printf(" memory size: 0x%08zX\n", hdr->p_memsz); printf(" flags: 0x%08X (%s)\n", hdr->p_flags, flags_str(hdr->p_flags)); printf(" align: %zd\n", hdr->p_align); if (hdr->p_memsz) { printf(" derived address range: %p to %p\n", (void *) (info->dlpi_addr + hdr->p_vaddr), (void *) (info->dlpi_addr + hdr->p_vaddr + hdr->p_memsz)); } } return 0; } int main(void) { dl_iterate_phdr(callback, NULL); exit(EXIT_SUCCESS); } 

.rodata不保证总是直接来自.text 。 您可以使用objdump -h filereadelf --sections file来获取更多信息。 使用objdump,您可以获得大小和偏移量。

对于Linux,请考虑使用nm(1)工具检查目标文件提供的符号。 您可以选择这组符号,在那里您可以学习Matthew Slattery在其答案中提供的两个符号。