假设我有一个函数
fn
,它位于 ELF64 可执行文件的.text
节中。有没有办法知道从 ELF 文件的开头算起,fn
函数所在的偏移量(以字节为单位)?请注意,我不需要知道链接时它被重定位到哪个虚拟地址,只需要知道它在 ELF 文件中的位置。fn
,它位于 ELF64 可执行文件的.text
节中。有没有办法知道从 ELF 文件的开头算起,fn
函数所在的偏移量(以字节为单位)?请注意,我不需要知道链接时它被重定位到哪个虚拟地址,只需要知道它在 ELF 文件中的位置。通常来说,可以通过直接解析ELF文件或者将objdump和readelf等工具的输出结合起来来实现。
更具体地说, 您可以使用 'readelf -S file' 命令获取您的 .text 部分的偏移量和虚拟地址-请记下这些信息。此外,您可以使用 'readelf -s file' 命令列出符号,只要可执行文件没有被剥离并且您的函数是可见的(不是静态函数或匿名命名空间中的函数),那么您应该能够找到您的函数及其虚拟地址。
因此,您可以通过以下方式计算出偏移量:
fn symbol offset = fn symbol VA - .text VA + .text offset
假设您想要使用常用工具进行“离线”操作。如果您无法访问未剥离的ELF文件,则更加困难,并且由于仅有部分ELF文件留存在内存中,因此可能需要使用“离线”技巧添加一些信息才能完成操作。
只需使用 objdump -F 选项
user@phoenix-amd64:~$ objdump -D -F /opt/phoenix/i486/heap-xxx -D | grep main
08048630 <__libc_start_main@plt> (File Offset: 0x630):
8048679: e8 b2 ff ff ff call 8048630 <__libc_start_main@plt> (File
Offset: 0x630)
080487d5 <main> (File Offset: 0x7d5):
Norbert Lange的回答适用于列在ELF文件符号表中的函数。但是static
函数不会出现在其中,因此即使例如GDB可以通过使用DWARF调试信息找到它们,readelf -s
也不会。
在这种情况下,您可以使用GDB。例如,让我们查找/usr/bin/xfsettingsd
中xfce_displays_helper_normalize_crtc
的偏移量(这是我的实际用例,因此选择了这个晦涩的示例)。
$ gdb -q -ex 'p &xfce_displays_helper_normalize_crtc' -ex q xfsettingsd
Reading symbols from xfsettingsd...
Reading symbols from /usr/lib/debug/.build-id/b2/2ad9713642253d4d7a6f94acf0174ccfe3d487.debug...
$1 = (void (*)(XfceRRCrtc *, XfceDisplaysHelper *)) 0x11e80 <xfce_displays_helper_normalize_crtc>
p
命令(完整形式为print
)获取地址。所以在我的情况下,该函数的偏移量为0x11e80
。start
或starti
程序之前,GDB也会将偏移解析为虚拟地址。这种情况特别发生在x86-32上。在这种情况下,我们可以简单地减去由readelf -l
给出的文件映像的虚拟地址:$ readelf -l /bin/sleep | grep ' VirtAddr \|\<LOAD *0x[0-9a-f]\+\>'
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x05230 0x05230 R E 0x1000
0x8048000
,如果GDB输出虚拟地址而不是偏移量,则需要从函数的虚拟地址中减去该值。