6

So I was messing with gdb and came across something rather interesting. I ran the following code into gdb:

int i, g = 1;
for (i = 0; i < 100; i++)
          g++;

Before execution, disas main yields:

   0x000000000000064a <+0>: push   %rbp
   0x000000000000064b <+1>: mov    %rsp,%rbp
   0x000000000000064e <+4>: sub    $0x10,%rsp
   0x0000000000000652 <+8>: movl   $0x1,-0x4(%rbp)
   0x0000000000000659 <+15>:    movl   $0x0,-0x8(%rbp)
   0x0000000000000660 <+22>:    jmp    0x66a <main+32>
   0x0000000000000662 <+24>:    addl   $0x1,-0x4(%rbp)
   0x0000000000000666 <+28>:    addl   $0x1,-0x8(%rbp)
   0x000000000000066a <+32>:    cmpl   $0x63,-0x8(%rbp)
   0x000000000000066e <+36>:    jle    0x662 <main+24>
   0x0000000000000670 <+38>:    mov    -0x4(%rbp),%eax
   ...

Interestingly, after run, things look different:

   0x000055555555464a <+0>: push   %rbp
   0x000055555555464b <+1>: mov    %rsp,%rbp
   0x000055555555464e <+4>: sub    $0x10,%rsp
   0x0000555555554652 <+8>: movl   $0x1,-0x4(%rbp)
   0x0000555555554659 <+15>:    movl   $0x0,-0x8(%rbp)
   0x0000555555554660 <+22>:    jmp    0x55555555466a <main+32>
   0x0000555555554662 <+24>:    addl   $0x1,-0x4(%rbp)
   0x0000555555554666 <+28>:    addl   $0x1,-0x8(%rbp)
   0x000055555555466a <+32>:    cmpl   $0x63,-0x8(%rbp)
   0x000055555555466e <+36>:    jle    0x555555554662 <main+24>
   0x0000555555554670 <+38>:    mov    -0x4(%rbp),%eax
   ...

What is going on here? Why the addresses are different before execution?

Edit:

Output of info proc mappings:

      Start Addr           End Addr       Size     Offset objfile
  0x555555554000     0x555555555000     0x1000        0x0 /tmp/test
  0x555555754000     0x555555755000     0x1000        0x0 /tmp/test
  0x555555755000     0x555555756000     0x1000     0x1000 /tmp/test
  0x7ffff7a21000     0x7ffff7bcf000   0x1ae000        0x0 /usr/lib/libc-2.26.so
  0x7ffff7bcf000     0x7ffff7dce000   0x1ff000   0x1ae000 /usr/lib/libc-2.26.so
  0x7ffff7dce000     0x7ffff7dd2000     0x4000   0x1ad000 /usr/lib/libc-2.26.so
  0x7ffff7dd2000     0x7ffff7dd4000     0x2000   0x1b1000 /usr/lib/libc-2.26.so
  0x7ffff7dd4000     0x7ffff7dd8000     0x4000        0x0 
  0x7ffff7dd8000     0x7ffff7dfd000    0x25000        0x0 /usr/lib/ld-2.26.so
  0x7ffff7fcc000     0x7ffff7fce000     0x2000        0x0 
  0x7ffff7ff7000     0x7ffff7ffa000     0x3000        0x0 [vvar]
  0x7ffff7ffa000     0x7ffff7ffc000     0x2000        0x0 [vdso]
  0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x24000 /usr/lib/ld-2.26.so
  0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x25000 /usr/lib/ld-2.26.so
  0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0 
  0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]

maint info section:

file type elf64-x86-64.
 [0]     0x00000238->0x00000254 at 0x00000238: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS
 [1]     0x00000254->0x00000274 at 0x00000254: .note.ABI-tag ALLOC LOAD READONLY DATA HAS_CONTENTS
 [2]     0x00000274->0x00000298 at 0x00000274: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS
 [3]     0x00000298->0x000002b4 at 0x00000298: .gnu.hash ALLOC LOAD READONLY DATA HAS_CONTENTS
 [4]     0x000002b8->0x00000360 at 0x000002b8: .dynsym ALLOC LOAD READONLY DATA HAS_CONTENTS
 [5]     0x00000360->0x000003e4 at 0x00000360: .dynstr ALLOC LOAD READONLY DATA HAS_CONTENTS
 [6]     0x000003e4->0x000003f2 at 0x000003e4: .gnu.version ALLOC LOAD READONLY DATA HAS_CONTENTS
 [7]     0x000003f8->0x00000418 at 0x000003f8: .gnu.version_r ALLOC LOAD READONLY DATA HAS_CONTENTS
 [8]     0x00000418->0x000004f0 at 0x00000418: .rela.dyn ALLOC LOAD READONLY DATA HAS_CONTENTS
 [9]     0x000004f0->0x00000508 at 0x000004f0: .rela.plt ALLOC LOAD READONLY DATA HAS_CONTENTS
 [10]     0x00000508->0x0000051f at 0x00000508: .init ALLOC LOAD READONLY CODE HAS_CONTENTS
 [11]     0x00000520->0x00000540 at 0x00000520: .plt ALLOC LOAD READONLY CODE HAS_CONTENTS
 [12]     0x00000540->0x00000702 at 0x00000540: .text ALLOC LOAD READONLY CODE HAS_CONTENTS
 [13]     0x00000704->0x0000070d at 0x00000704: .fini ALLOC LOAD READONLY CODE HAS_CONTENTS
 [14]     0x00000710->0x00000718 at 0x00000710: .rodata ALLOC LOAD READONLY DATA HAS_CONTENTS
 [15]     0x00000718->0x0000074c at 0x00000718: .eh_frame_hdr ALLOC LOAD READONLY DATA HAS_CONTENTS
 [16]     0x00000750->0x00000840 at 0x00000750: .eh_frame ALLOC LOAD READONLY DATA HAS_CONTENTS
 [17]     0x00200de0->0x00200de8 at 0x00000de0: .init_array ALLOC LOAD DATA HAS_CONTENTS
 [18]     0x00200de8->0x00200df0 at 0x00000de8: .fini_array ALLOC LOAD DATA HAS_CONTENTS
 [19]     0x00200df0->0x00200fd0 at 0x00000df0: .dynamic ALLOC LOAD DATA HAS_CONTENTS
 [20]     0x00200fd0->0x00201000 at 0x00000fd0: .got ALLOC LOAD DATA HAS_CONTENTS
 [21]     0x00201000->0x00201020 at 0x00001000: .got.plt ALLOC LOAD DATA HAS_CONTENTS
 [22]     0x00201020->0x00201030 at 0x00001020: .data ALLOC LOAD DATA HAS_CONTENTS
 [23]     0x00201030->0x00201038 at 0x00001030: .bss ALLOC
 [24]     0x00000000->0x00000011 at 0x00001030: .comment READONLY HAS_CONTENTS
9

Seems like relocation. If you look at the addresses in your first listing, you will notice that these addresses are unusually low. That's probably because gdb displays file offsets there (although I have no idea why that is the case for you).

When you run the file, the loader kicks in and maps the sections to the virtual address space of the program, and thats where the 0x0000555555554000 section offset comes from.

You can see the file offsets of each section using maint info sections. You can get information about the actual mapped memory sections using info proc mappings at runtime.

edit:

Based on the output of the commands above, everything seems to be alright.

[12]     0x00000540->0x00000702 at 0x00000540: .text ALLOC LOAD READONLY CODE HAS_CONTENTS

This line states that the .text section of your code starts at file offset 0x540 and ends at 0x702 containing code. If your compare it with your first disassembly starting at offset 0x64a, this is a decent fit.

0x555555554000     0x555555555000     0x1000        0x0 /tmp/test

This line states that the executable itself was mapped to the base address 0x555555554000. Given the offset from before, that means your main function should be at 0x555555554000 + 0x64a. Your second disassembly confirms that.

  • 2
    yes, gdb can't know where the relocation will be at, so before execution it displays from 0x0. – Olivier Dulac Oct 10 '17 at 9:38
  • 1
    another thing is the executable was compiled with -fPIE which activates ASLR on the .text section too – sudhackar Oct 11 '17 at 4:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.