1

I have the following piece of C code:

#include <stdio.h>

int main()
{
    int i;
    for(i=0; i<10; i++)
        puts("hello, friend");

    return 0;
}

which I compiled this way: gcc firstprog.c -o firstprog

Then, when using gdb to disassemble it, I see:

(gdb) disassemble 
Dump of assembler code for function main:
=> 0x0000555555555149 <+0>: endbr64 
   0x000055555555514d <+4>: push   rbp
   0x000055555555514e <+5>: mov    rbp,rsp
   0x0000555555555151 <+8>: sub    rsp,0x10
   0x0000555555555155 <+12>:    mov    DWORD PTR [rbp-0x4],0x0
   0x000055555555515c <+19>:    jmp    0x55555555516e <main+37>
   0x000055555555515e <+21>:    lea    rdi,[rip+0xe9f]        # 0x555555556004
   0x0000555555555165 <+28>:    call   0x555555555050 <puts@plt>
   0x000055555555516a <+33>:    add    DWORD PTR [rbp-0x4],0x1
   0x000055555555516e <+37>:    cmp    DWORD PTR [rbp-0x4],0x9
   0x0000555555555172 <+41>:    jle    0x55555555515e <main+21>
   0x0000555555555174 <+43>:    mov    eax,0x0
   0x0000555555555179 <+48>:    leave  
   0x000055555555517a <+49>:    ret    
End of assembler dump.

So my question is: what is rip+0xe9f referring to at <main+21> ?

If I use objdump on the same file, I've got the following output:

$ objdump -M intel -D firstprog | grep -A16 main.:
0000000000001149 <main>:
    1149:   f3 0f 1e fa             endbr64 
    114d:   55                      push   rbp
    114e:   48 89 e5                mov    rbp,rsp
    1151:   48 83 ec 10             sub    rsp,0x10
    1155:   c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
    115c:   eb 10                   jmp    116e <main+0x25>
    115e:   48 8d 3d 9f 0e 00 00    lea    rdi,[rip+0xe9f]        # 2004 <_IO_stdin_used+0x4>
    1165:   e8 e6 fe ff ff          call   1050 <puts@plt>
    116a:   83 45 fc 01             add    DWORD PTR [rbp-0x4],0x1
    116e:   83 7d fc 09             cmp    DWORD PTR [rbp-0x4],0x9
    1172:   7e ea                   jle    115e <main+0x15>
    1174:   b8 00 00 00 00          mov    eax,0x0
    1179:   c9                      leave  
    117a:   c3                      ret    
    117b:   0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]

It seems that it's related to file descriptors, but as puts write to stdout, I was not expecting to see IO_stdin.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
hacb
  • 175
  • 2
  • 10
  • 6
    It loads the address of the `"hello, friend"` string into `rdi`. The address is `_IO_stdin_used+0x4` which is the dword of memory after `_IO_stdin_used`. It's likely your string is there (use `objdump -s` to check). The string doesn't have a symbol associated with it, so `objdump` wrongly guesses that it's related to the string just prior to this one. – fuz Dec 25 '20 at 11:45
  • Look at GCC asm output like [How would you explain this disassembly listing?](https://stackoverflow.com/a/59782333) - you'll clearly see it's a RIP-relative load from a local label in `.rodata`. Or [Whay rip is used here in a Hello world assembly?](https://stackoverflow.com/q/60133542). Also related: [Why are global variables in x86-64 accessed relative to the instruction pointer?](https://stackoverflow.com/q/56262889) but your concern is that there's no label on the target address, and a named global `char foo[] = "...";` var would have one. – Peter Cordes Dec 25 '20 at 19:47

1 Answers1

5

So my question is: what is rip+0xe9f referring to at <main+21> ?

You can look: x/s 0x555555556004 will give you the answer.

(gdb) x/s 0x555555556004
0x555555556004: "hello, friend"
Employed Russian
  • 199,314
  • 34
  • 295
  • 362