Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么gdb在RIP相对模式下显示的地址与绝对地址不同?_C_Debugging_Gdb_Disassembly - Fatal编程技术网

C 为什么gdb在RIP相对模式下显示的地址与绝对地址不同?

C 为什么gdb在RIP相对模式下显示的地址与绝对地址不同?,c,debugging,gdb,disassembly,C,Debugging,Gdb,Disassembly,在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; } nop-相对地址未使用绝对地址,而x变量实际存储在绝对地址中(0x55558055!=0x558044),差异为17个字节。它

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;
}
nop-相对地址未使用绝对地址,而
x
变量实际存储在绝对地址中(
0x55558055
!=
0x558044
),差异为17个字节。它是指令本身的字节数(
lea
+操作数)?我不知道,但我不这么认为。那么,为什么相对寻址和绝对寻址在gdb中不同呢

PS,生成的程序集:

.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
此处,使用相对撕裂模式:

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

0x00005555165:lea0x2ed8(%rip),%rsi#0x558044
0x0000555516C:lea 0xe9a(%rip),%rdi#0x55600D
指令中的RIP相对地址与当前指令后的地址(即指令地址加上指令大小,或下一条指令的地址)相对。这是因为,当指令加载到处理器中时,RIP寄存器在执行前会按当前指令的大小前进。(尽管现代处理器在幕后使用各种技巧来加快执行速度,但至少这是遵循的模型。)(注意:上述情况适用于几种CPU体系结构,包括x86变体,但其他一些CPU体系结构在测量PC相对地址的点上有所不同1。)

上面的第一条指令位于地址0x555165,下面的指令位于地址0x55516C(指令长度为7字节)。在第一条指令中,RIP相对地址
0x2ed8(%RIP)
指的是0x2ed8+0x0000555516C=0x558044

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



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

如果我不知道源代码,如何确定下一个处理器的大小instruction@autistic456x86指令长度可变,取决于寻址模式。您需要查阅处理器的指令集参考,以确定指令的大小。我已经更改了我的答案,以澄清RIP寄存器何时更新。Abbot,RIP将指向当前指令,而不是下一条指令,因为当前指令尚未执行,
RIP
在调试器中显示当前指令,因为调试器显示尚未执行,但在程序流中,“real”
rip
显示下一条指令,因为执行的是内联指令。那么,调试程序中的rip是误导性的,因为我理解执行前的停止,但我现在有两个
rip
引用,有两种含义(调试程序
rip
和“真实的”-可执行
rip
),它是一个功能还是一个bug?@autistic456是的,一开始让人困惑,但大多数处理器都是这样做的。(我想不出有哪一个是不需要的。)对于使用固定大小指令的处理器来说,这更容易处理!RISC处理器设计通常使用固定的指令长度,尽管其中一些后来引入了特殊模式来执行压缩指令集(例如ARM“Thumb”模式)以节省内存;这段对话已经结束。
x $rip+0x2ed8
0x555555558055: 0x00000000
.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
# a.c:6:    scanf("%i",&x);
    leaq    x(%rip), %rsi   #,
   0x0000555555555165 <+16>:    lea    0x2ed8(%rip),%rsi        # 0x555555558044 <x>
   0x000055555555516c <+23>:    lea    0xe9a(%rip),%rdi        # 0x55555555600d