Understanding %rip register in intel assembly

68,507

RIP addressing is always relative to RIP (64bit Instruction Pointer) register. So it can be use for global variables only. The 0 offset is equal to address of the following instruction after the RIP-addressed instruction. For example:

   mov  al,[rip+2]                     al=53
   jmp  short next   (length=2 bytes)   
db 53
next:
   mov  bl,[rip-7]   (length=6 bytes)  bl=53

You wouldn't normally mix data right in with your code, except as an immediate, but this shows what would happen if you actually ran code with very small offsets.

In your code you cannot see and check offsets (you see four zeros) because you disassembled a .o. Use objdump -drwC to show symbol names / relocations when disassembling. They will be filled by the linker when you link this object into an executable.


Example for accessing locals relative to `rbp:

push rbp      ;save rbp
mov rbp,rsp   ;rbp = pointer to return address (8 bytes)
sub rsp,64    ;reserve 64 bytes for local variables
mov rax,[rbp+8];  rax = the last stack-passed qword parameter (if any)
mov rdx,[rbp];    rdx = return address
mov rcx,[rbp-8];  rcx = first qword local variable (this is undefined now)
mov r8, [rbp-16];  r8  = second qword local variable (this is undefined now)
.
.
mov rsp,rbp
pop rbp
ret
Share:
68,507

Related videos on Youtube

youpilat13
Author by

youpilat13

Updated on July 09, 2022

Comments

  • youpilat13
    youpilat13 2 months

    Concerning the following small code, which was illustrated in another post about the size of structure and all the possibilities to align data correctly :

    struct
    {
     char Data1;
     short Data2;
     int Data3;
     char Data4;
    } x;
    unsigned fun ( void )
    {
        x.Data1=1;
        x.Data2=2;
        x.Data3=3;
        x.Data4=4;
        return(sizeof(x));
    }
    

    I get the corresponding disassembly (with 64 bits)

    0000000000000000 <fun>:
       0:   55                      push   %rbp
       1:   48 89 e5                mov    %rsp,%rbp
       4:   c6 05 00 00 00 00 01    movb   $0x1,0x0(%rip)        # b <fun+0xb>
       b:   66 c7 05 00 00 00 00    movw   $0x2,0x0(%rip)        # 14 <fun+0x14>
      12:   02 00 
      14:   c7 05 00 00 00 00 03    movl   $0x3,0x0(%rip)        # 1e <fun+0x1e>
      1b:   00 00 00 
      1e:   c6 05 00 00 00 00 04    movb   $0x4,0x0(%rip)        # 25 <fun+0x25>
      25:   b8 0c 00 00 00          mov    $0xc,%eax
      2a:   5d                      pop    %rbp
      2b:   c3                      retq   
    

    I don't know how to calculate the terms located on the right which seems to be the address of local variables used. Moreover, I don't know to calculate it with %rip register

    Could you give an example which shows the link between %rip and %rsp or %rbp, i.e especially in the computation of address when I use move instructions.

    • Jester
      Jester over 5 years
      There is no such relation, rip is the instruction pointer (hence the name). You can't address locals relative to it. Note that x is not a local. Also note that you used objdump on an intermediate object file hence you did not get the correct offsets. You might want to run it on a linked executable and/or use -r option to see relocation entries.
    • Ped7g
      Ped7g over 5 years
      movb $0x4,0x0 will store byte value 4 into memory at absolute address 0. movb $0x4,0x0(%rip) will store byte value 4 into memory at absolute address rip + 0, ie. at relative-to-RIP address 0. It's same as using other registers for addressing, like movb $4,0(%edi). The difference is, that the rip points at the time of evaluation to the beginning of next instruction. So the usage of rip for relative addressing allows the compiler to produce "PIC" Position Independent Code. The OS then needs to load the data + code together to maintain their relative position to each other.
  • Peter Cordes
    Peter Cordes over 4 years
    Actually they will be filled at link time; looks like the OP disassembled a .o rather than a linked executable. Position-independent code doesn't need runtime fixups every time it's loaded; this is one of the big advantages of RIP-relative addressing.

Related