0

I have a simple c code:

#include <stdlib.h>

static int x = 4;

static int *p;
int *s;

struct B
{
int *s;
int j;
};

void foo()
{
  static int *pointer;
  static struct B *c;
  c =  malloc(sizeof(struct B));
  x = 5;
  p = &x;
  p = s;
  pointer = p;
  static struct B b;
  b.s = &x;
  b.j = 9;
}
int main(int argc, char *argv[])
{
  static   char buf[10] = "";
  static char b;
  x = 5;
  /*  OK  */
  buf[9] = 'A';
  b = 'C';

  return 0;
}

I get the objdump of this and following is the foo function:

00000000004004e6 <foo>:
  4004e6:       55                      push   rbp
  4004e7:       48 89 e5                mov    rbp,rsp
  4004ea:       bf 10 00 00 00          mov    edi,0x10
  4004ef:       e8 fc fe ff ff          call   4003f0 <malloc@plt>
  4004f4:       48 89 05 4d 0b 20 00    mov    QWORD PTR [rip+0x200b4d],rax        # 601048 <c.2532>
  4004fb:       c7 05 1f 0b 20 00 05    mov    DWORD PTR [rip+0x200b1f],0x5        # 601024 <x>
  400502:       00 00 00 
  400505:       48 c7 05 30 0b 20 00    mov    QWORD PTR [rip+0x200b30],0x601024        # 601040 <p>
  40050c:       24 10 60 00 
  400510:       48 8b 05 69 0b 20 00    mov    rax,QWORD PTR [rip+0x200b69]        # 601080 <s>
  400517:       48 89 05 22 0b 20 00    mov    QWORD PTR [rip+0x200b22],rax        # 601040 <p>
  40051e:       48 8b 05 1b 0b 20 00    mov    rax,QWORD PTR [rip+0x200b1b]        # 601040 <p>
  400525:       48 89 05 24 0b 20 00    mov    QWORD PTR [rip+0x200b24],rax        # 601050 <pointer.253
1>
  40052c:       48 c7 05 29 0b 20 00    mov    QWORD PTR [rip+0x200b29],0x601024        # 601060 <b.2533
>
  400533:       24 10 60 00 
  400537:       c7 05 27 0b 20 00 09    mov    DWORD PTR [rip+0x200b27],0x9        # 601068 <b.2533+0x8>
  40053e:       00 00 00 
  400541:       90                      nop
  400542:       5d                      pop    rbp
  400543:       c3                      ret    

Now, I can relate this assembly code with c code (i.e. I didn't have any difficulties understanding the logic). I also know that the static/ global variables are stored in the data section and not on the stack (correct me if I'm wrong here). But, I don't get why the address arithmetic (offset related to rpi) is different every time. For e.g. consider these two instructions:

mov    QWORD PTR [rip+0x200b22],rax        # 601040 <p>
mov    rax,QWORD PTR [rip+0x200b1b]        # 601040 <p>

Both of these corresponds to the operation related to the pointer p. Now, my question is why the addresses are different in both of the cases: i.e. rip+0x200b22 and rip+0x200b1b yet, both of them are accessing the pointer p (I believe the static location of p is 601040)?

R4444
  • 2,016
  • 2
  • 19
  • 30

1 Answers1

1

RIP is the instruction pointer. (R = 64-bit register name).

The two instructions are at different addresses so their distance to a BSS variable is different. x86-64 prefers RIP-relative addressing for static storage. objdump is showing you the RIP-relative addressing mode, and decoding it to the final absolute address as # 601040 <p>

(p and s should be in the BSS because they don't have a non-zero static initializer. But yes, static storage.)

Related:

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • forgive my ignorance, but why doesn't rip + add up to the pointer's location - for example, in the above case it adds up to 601039 and not 601040, also I observed the same in some different cases. – R4444 Aug 12 '19 at 02:11
  • 1
    @Ruturaj: RIP-relative addressing is relative to the *end* of the instruction. `0x601039 + 7 = 0x601040` Or just look at the address of the next instruction to get the address of the current. – Peter Cordes Aug 12 '19 at 02:15