为什么gdb在RIP相对模式下显示的地址与绝对地址不同? [英] Why gdb shows different addresses in RIP-relative mode from absolute address?

查看:299
本文介绍了为什么gdb在RIP相对模式下显示的地址与绝对地址不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

c 中具有此功能:

#include <stdio.h>
#include <stdlib.h>
int x;
int main(){
    printf("eneter x\n");   
    scanf("%i",&x);
    printf("you enetered: %i\n", x);
    return 0;
}

在gdb中:

starti
disas main

0x0000555555555155 <+0>:    push   %rbp
   0x0000555555555156 <+1>: mov    %rsp,%rbp
   0x0000555555555159 <+4>: lea    0xea4(%rip),%rdi        # 0x555555556004
   0x0000555555555160 <+11>:    callq  0x555555555030 <puts@plt>
   0x0000555555555165 <+16>:    lea    0x2ed8(%rip),%rsi        # 0x555555558044 <x>
   0x000055555555516c <+23>:    lea    0xe9a(%rip),%rdi        # 0x55555555600d
   0x0000555555555173 <+30>:    mov    $0x0,%eax
   0x0000555555555178 <+35>:    callq  0x555555555050 <__isoc99_scanf@plt>
   0x000055555555517d <+40>:    mov    0x2ec1(%rip),%eax        # 0x555555558044 <x>
   0x0000555555555183 <+46>:    mov    %eax,%esi
   0x0000555555555185 <+48>:    lea    0xe84(%rip),%rdi        # 0x555555556010
   0x000055555555518c <+55>:    mov    $0x0,%eax
   0x0000555555555191 <+60>:    callq  0x555555555040 <printf@plt>
   0x0000555555555196 <+65>:    mov    $0x0,%eax
   0x000055555555519b <+70>:    pop    %rbp
   0x000055555555519c <+71>:    retq 

其中 x 变量的相对地址为 $ rip + 0x2ed8 (来自指令 lea 0x2ed8(%rip),%rsi#0x555555558044 )。但是,正如您在注释中看到的那样,绝对地址为 0x555555558044 。好吧,当您尝试从亲戚那里读时,我会得到那个地址吗?让我们看看:

here the relative address of x variable is $rip+0x2ed8 (from instruction lea 0x2ed8(%rip),%rsi # 0x555555558044). But as you can see in the comment #, the absolute address is 0x555555558044. Ok will I get that address when try to read from the relative one? Lets see:

x $rip+0x2ed8
0x555555558055: 0x00000000

nop-相对地址未使用绝对地址,而 x var实际存储在其中( 0x555555558055 != 0x555555558044 ),相差17个字节。它是指令本身的字节数( lea +操作数)吗?我不知道,但不这么认为。那么为什么相对寻址和绝对寻址在gdb中有所不同?

nop - relative address did not use the absolute address, where the x var is really stored (0x555555558055 != 0x555555558044) the difference is 17 bytes. Is it the number of bytes of the instruction itself (lea + operands)? I do not know, but do not think so. So why does relative and absolute addressing differ in gdb?

PS,生成的程序集:

PS, generated assembly:

.file   "a.c"
    .comm   x,4,4
    .section    .rodata
.LC0:
    .string "eneter x"
.LC1:
    .string "%i"
.LC2:
    .string "you enetered: %i\n"
    .text
    .globl  main
    .type   main, @function
main:
    pushq   %rbp    #
    movq    %rsp, %rbp  #,
# a.c:5:    printf("eneter x\n");   
    leaq    .LC0(%rip), %rdi    #,
    call    puts@PLT    #
# a.c:6:    scanf("%i",&x);
    leaq    x(%rip), %rsi   #,
    leaq    .LC1(%rip), %rdi    #,
    movl    $0, %eax    #,
    call    __isoc99_scanf@PLT  #
# a.c:7:    printf("you enetered: %i\n", x);
    movl    x(%rip), %eax   # x, x.0_1
    movl    %eax, %esi  # x.0_1,
    leaq    .LC2(%rip), %rdi    #,
    movl    $0, %eax    #,
    call    printf@PLT  #
# a.c:8:    return 0;
    movl    $0, %eax    #, _6
# a.c:9: }
    popq    %rbp    #
    ret 
    .size   main, .-main
    .ident  "GCC: (Debian 8.3.0-6) 8.3.0"
    .section    .note.GNU-stack,"",@progbits

在这里,使用相对于RIP的模式

Here, the RIP-relative mode is used:

# a.c:6:    scanf("%i",&x);
    leaq    x(%rip), %rsi   #,

其中 x x 符号的位置。但是有人在评论中说, $ rip + 0x2ed8 是不一样的,偏移量 0x2ed8 不会导致到 x 的地址。但是为什么这两个不同?但应为RIP相对模式寻址,并且两者都应获得相同的偏移量(并因此获得地址)。

where the x is position of the x symbol. But in comments, someone said, that $rip+0x2ed8 is not the same, and the offset 0x2ed8 does not lead to the address of the x. But why those two differ? but should be RIP-relative mode addressing and both should gain the same offset (and thus address).

推荐答案

   0x0000555555555165 <+16>:    lea    0x2ed8(%rip),%rsi        # 0x555555558044 <x>
   0x000055555555516c <+23>:    lea    0xe9a(%rip),%rdi        # 0x55555555600d

RIP相对指令中的地址是相对于当前指令之后的地址(即指令的地址加上指令的大小,或后一条指令的地址)。这是因为当指令已加载到处理器中时,RIP寄存器将在执行前将当前指令的大小提前。 (即使现代处理器在后台使用各种技巧来加快执行速度,也至少要遵循该模型。)(注:上面的内容适用于包括x86变体在内的几种CPU架构,但其他一些CPU架构也有所不同

A RIP relative address in an instruction is relative to the address just after the current instruction (i.e. the address of the instruction plus the size of the instruction, or the address of the following instruction). This is because when the instruction has been loaded into the processor, the RIP register is advanced by the size of the current instruction just before it is executed. (At least that is the model that is followed even though modern processors use all sorts of tricks behind the scenes to speed up execution.) (Note: The above is true for several CPU architectures, including x86 variants, but some other CPU architectures differ in the point from which PC-relative addresses are measured1.)

上面的第一条指令在地址0x555555555165上,下一条指令在地址0x55555555516c(指令的长度为7个字节)。在第一条指令中,RIP相对地址 0x2ed8(%rip)表示0x2ed8 + 0x000055555555516c = 0x555555558044。

The first instruction above is at address 0x555555555165 and the following instruction is at address 0x55555555516c (the instruction is 7 bytes long). In the first instruction, the RIP relative address 0x2ed8(%rip) refers to 0x2ed8 + 0x000055555555516c = 0x555555558044.

请注意,如果您在调试器中的一条指令上设置断点,并在到达断点时显示寄存器,RIP将指向当前指令,而不是下一条指令,因为当前指令尚未执行。

Note that if you set a breakpoint on an instruction in a debugger and show the registers when the breakpoint is reached, RIP will point to the current instruction, not the next one, because the current instruction is not being executed yet.

1 感谢Peter Cordes提供了有关ARM和RISC-V CPU体系结构的PC相对寻址的详细信息。

1 Thanks to Peter Cordes for details about PC-relative addressing for ARM and RISC-V CPU architectures.

这篇关于为什么gdb在RIP相对模式下显示的地址与绝对地址不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆