I compiled a simple helloworld and took a look at the disassembly using objdump.

At the beginning there is the _init:

0000000000400600 <_init>:
  400600:   48 83 ec 08             sub    rsp,0x8
  400604:   48 8b 05 ed 09 20 00    mov    rax,QWORD PTR [rip+0x2009ed]        # 600ff8 <_DYNAMIC+0x1e0>
  40060b:   48 85 c0                test   rax,rax
  40060e:   74 05                   je     400615 <_init+0x15>
  400610:   e8 1b 00 00 00          call   400630 <__gmon_start__@plt>
  400615:   48 83 c4 08             add    rsp,0x8
  400619:   c3                      ret    

What is _DYNAMIC? Using -x I can see the section details:

Dynamic Section:
  NEEDED               libstdc++.so.6
  NEEDED               libc.so.6
  INIT                 0x0000000000400600
  FINI                 0x0000000000400864
  INIT_ARRAY           0x0000000000600df8
  INIT_ARRAYSZ         0x0000000000000010
  FINI_ARRAY           0x0000000000600e08
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000000400298
  STRTAB               0x00000000004003c8
  SYMTAB               0x00000000004002c0
  STRSZ                0x000000000000011c
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000000601000
  PLTRELSZ             0x0000000000000090
  PLTREL               0x0000000000000007
  JMPREL               0x0000000000400570
  RELA                 0x0000000000400540
  RELASZ               0x0000000000000030
  RELAENT              0x0000000000000018
  VERNEED              0x0000000000400500
  VERNEEDNUM           0x0000000000000002
  VERSYM               0x00000000004004e4

However, I am not sure which entry is rip+0x2009ed referring to. Considering that the next line is a call to gmon, does it have anything to do with a GPROF hook?

1 Answer 1


This is a trick that's used by the initialization code to support monitoring when it's compiled in, and omit it when it isn't compiled in.

When i compile a small test program using gcc -pg, then invoke objdump -Mintel -d on it, i get:

00000000004004c0 <_init>:
  4004c0:   48 83 ec 08             sub    rsp,0x8
  4004c4:   48 8d 05 c5 00 00 00    lea    rax,[rip+0xc5]        # 400590 <__gmon_start__>
  4004cb:   48 85 c0                test   rax,rax
  4004ce:   74 05                   je     4004d5 <_init+0x15>
  4004d0:   e8 bb 00 00 00          call   400590 <__gmon_start__>
  4004d5:   48 83 c4 08             add    rsp,0x8
  4004d9:   c3                      ret    

If i omit the -pg when compiling, this changes to:

0000000000400418 <_init>:
  400418:   48 83 ec 08             sub    rsp,0x8
  40041c:   48 8b 05 d5 0b 20 00    mov    rax,QWORD PTR [rip+0x200bd5]        # 600ff8 <_DYNAMIC+0x1d0>
  400423:   48 85 c0                test   rax,rax
  400426:   74 05                   je     40042d <_init+0x15>
  400428:   e8 43 00 00 00          call   400470 <__gmon_start__@plt>
  40042d:   48 83 c4 08             add    rsp,0x8
  400431:   c3                      ret    

So you see that, with monitoring enabled, the code checks if __gmon_start__ is not null before calling the function. With monitoring disabled, it checks some variable, and if it is 0, it skips the call to __gmon_start__.

But wait. Why do we have a lea in the first case, and a mov in the second one? And why does the name end in @plt ? Because, even if your program doesn't have profiling compiled in, maybe some of your dynamic libraries do, and maybe you're running against a profiling-enabled version of the C library. So the C library may provide a dynamic version of __gmon_start__, and it provides a flag to mark if it does so. This function and flag are defined in the GOT and GOTPLT sections.

And indeed, if you note the address that's used, 600FF8, and scroll down the objdump -x output a bit from your section details, you'll see:

 21 .got          00000008  0000000000600ff8  0000000000600ff8  00000ff8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got.plt      00000038  0000000000601000  0000000000601000  00001000  2**3
                  CONTENTS, ALLOC, LOAD, DATA

you'll see the code accesses a GOT table entry (which, for a small test program, is the only entry in the GOT there is, which is why GOT is just 8 bytes in size).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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