No, in fact you misunderstood something. :-)
The address 0x0000000000000520
is the offset from the beginning of the ELF file from the section .text
where the _start
procedure lies. And, the address 0x0000555555554520
correspond to the address where the section .text
has been mapped by the operating system plus the offset of the procedure: 0x0000555555554000 + 0x0000000000000520
(.text
section address + main procedure offset).
gdb
(without a run
) will only have the offset of the .text
section as if it was starting at zero. Then, after running the _start
procedure, the .text
section will be remapped within the virtual memory by the OS. This remapping happen when the loader is called.
And, if you observe a difference between the two breakpoints, it is mainly because the first breakpoint has been set onto the symbol _start
and the other one has been set onto the address. The remapping of the symbol will be taken into account by gdb
but, an address is an address and it will not change anymore.
For example, just after loading the executable file in 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
We can see the _start
procedure is located exactly at the beginning of the .text
section:
(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
...
And, once we hit the 'start' command (corresponding to a 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
....
You can see that all sections have been remapped by the loader (and some sections have been added to handle the dynamic libraries).
If you want to know more about the loading process of executable under Linux, I would strongly advise you to take a look at this excellent article from Patrick Horgan. I think it will cover most of the questions you might have about this process.
Hope this helped.