不,事实上你误解了一些东西。:-)
该地址0x0000000000000520
是从 ELF 文件开头.text
与_start
过程所在部分的偏移量。并且,地址0x0000555555554520
对应于其中的部分的地址.text
已经由操作系统映射加程序的偏移量:0x0000555555554000 + 0x0000000000000520
(.text
段地址+主过程偏置)。
gdb
(没有 a run
)将只有该.text
部分的偏移量,就好像它从零开始一样。然后,在运行该_start
程序后,该.text
部分将被操作系统重新映射到虚拟内存中。这种重新映射在调用加载器时发生。
而且,如果您观察到两个断点之间的差异,主要是因为第一个断点已设置在符号上_start
,而另一个断点已设置在地址上。gdb
但是,符号的重新映射将被考虑在内,地址是一个地址,它不会再改变。
例如,在gdb
(no run
) 中加载可执行文件后:
(gdb) info files
Symbols from "/tmp/a".
Local exec file:
`/tmp/a', file type elf64-x86-64.
Entry point: 0x1050
0x00000000000002a8 - 0x00000000000002c4 is .interp
0x00000000000002c4 - 0x00000000000002e4 is .note.ABI-tag
0x00000000000002e4 - 0x0000000000000308 is .note.gnu.build-id
0x0000000000000308 - 0x000000000000032c is .gnu.hash
0x0000000000000330 - 0x00000000000003d8 is .dynsym
0x00000000000003d8 - 0x000000000000045a is .dynstr
0x000000000000045a - 0x0000000000000468 is .gnu.version
0x0000000000000468 - 0x0000000000000488 is .gnu.version_r
0x0000000000000488 - 0x0000000000000548 is .rela.dyn
0x0000000000000548 - 0x0000000000000560 is .rela.plt
0x0000000000001000 - 0x0000000000001017 is .init
0x0000000000001020 - 0x0000000000001040 is .plt
0x0000000000001040 - 0x0000000000001048 is .plt.got
0x0000000000001050 - 0x00000000000011c2 is .text
0x00000000000011c4 - 0x00000000000011cd is .fini
0x0000000000002000 - 0x0000000000002008 is .rodata
0x0000000000002008 - 0x0000000000002044 is .eh_frame_hdr
0x0000000000002048 - 0x0000000000002150 is .eh_frame
0x0000000000003de8 - 0x0000000000003df0 is .init_array
0x0000000000003df0 - 0x0000000000003df8 is .fini_array
0x0000000000003df8 - 0x0000000000003fd8 is .dynamic
0x0000000000003fd8 - 0x0000000000004000 is .got
0x0000000000004000 - 0x0000000000004020 is .got.plt
0x0000000000004020 - 0x0000000000004030 is .data
0x0000000000004030 - 0x0000000000004038 is .bss
我们可以看到该_start
过程正好位于本.text
节的开头:
(gdb) disas 0x0000000000001050, 0x00000000000011c2
Dump of assembler code from 0x1050 to 0x11c2:
0x0000000000001050 <_start+0>: xor %ebp,%ebp
0x0000000000001052 <_start+2>: mov %rdx,%r9
0x0000000000001055 <_start+5>: pop %rsi
0x0000000000001056 <_start+6>: mov %rsp,%rdx
0x0000000000001059 <_start+9>: and $0xfffffffffffffff0,%rsp
0x000000000000105d <_start+13>: push %rax
0x000000000000105e <_start+14>: push %rsp
0x000000000000105f <_start+15>: lea 0x15a(%rip),%r8 # 0x11c0 <__libc_csu_fini>
0x0000000000001066 <_start+22>: lea 0xe3(%rip),%rcx # 0x1150 <__libc_csu_init>
0x000000000000106d <_start+29>: lea 0xc1(%rip),%rdi # 0x1135 <main>
0x0000000000001074 <_start+36>: callq *0x2f66(%rip) # 0x3fe0
0x000000000000107a <_start+42>: hlt
0x000000000000107b: nopl 0x0(%rax,%rax,1)
0x0000000000001080 <deregister_tm_clones+0>: lea 0x2fa9(%rip),%rdi
0x0000000000001087 <deregister_tm_clones+7>: lea 0x2fa2(%rip),%rax
...
而且,一旦我们点击“开始”命令(对应于tbreak main
+ run
):
(gdb) start
Temporary breakpoint 1 at 0x1139
Starting program: /tmp/a
Temporary breakpoint 1, 0x0000555555555139 in main ()
(gdb) info files
Symbols from "/tmp/a".
Native process:
Using the running image of child process 22585.
While running this, GDB does not access memory from...
Local exec file:
`/tmp/a', file type elf64-x86-64.
Entry point: 0x555555555050
0x00005555555542a8 - 0x00005555555542c4 is .interp
0x00005555555542c4 - 0x00005555555542e4 is .note.ABI-tag
0x00005555555542e4 - 0x0000555555554308 is .note.gnu.build-id
0x0000555555554308 - 0x000055555555432c is .gnu.hash
0x0000555555554330 - 0x00005555555543d8 is .dynsym
0x00005555555543d8 - 0x000055555555445a is .dynstr
0x000055555555445a - 0x0000555555554468 is .gnu.version
0x0000555555554468 - 0x0000555555554488 is .gnu.version_r
0x0000555555554488 - 0x0000555555554548 is .rela.dyn
0x0000555555554548 - 0x0000555555554560 is .rela.plt
0x0000555555555000 - 0x0000555555555017 is .init
0x0000555555555020 - 0x0000555555555040 is .plt
0x0000555555555040 - 0x0000555555555048 is .plt.got
0x0000555555555050 - 0x00005555555551c2 is .text
0x00005555555551c4 - 0x00005555555551cd is .fini
0x0000555555556000 - 0x0000555555556008 is .rodata
0x0000555555556008 - 0x0000555555556044 is .eh_frame_hdr
0x0000555555556048 - 0x0000555555556150 is .eh_frame
0x0000555555557de8 - 0x0000555555557df0 is .init_array
0x0000555555557df0 - 0x0000555555557df8 is .fini_array
0x0000555555557df8 - 0x0000555555557fd8 is .dynamic
0x0000555555557fd8 - 0x0000555555558000 is .got
0x0000555555558000 - 0x0000555555558020 is .got.plt
0x0000555555558020 - 0x0000555555558030 is .data
....
您可以看到加载器重新映射了所有部分(并且添加了一些部分来处理动态库)。
如果你想了解更多关于 Linux 下可执行文件的加载过程,我强烈建议你看看Patrick Horgan 的这篇优秀文章。我认为它将涵盖您可能对这个过程提出的大部分问题。
希望这有帮助。