【问题标题】:x86_64 assembly %rsp vs %espx86_64 程序集 %rsp 与 %esp
【发布时间】:2015-10-07 19:42:20
【问题描述】:

我最近一直在玩汇编,在我的程序中遇到了一个奇怪的错误。我发现如果我通过执行 64 位数学修改 %rsp,那么一切正常,但是如果我修改 %esp 相同的数量,除了 32 位数学,我会遇到分段错误。我试过把%esp%rsp都打印出来,每次运行都是一样的。

问题:当整个寄存器只使用 32 位时,为什么我做 64 位数学还是 32 位数学很重要?

.cstring
    _format: .asciz "%d\n"

.text
.globl _main
_main:
    # program setup
    pushq   %rbp
    movq    %rsp, %rbp

    # program - 16 byte aligned at this point
    # print stack pointer memory
    movq    %rsp, %rax
    call    bob            # prints the same value as the next call to bob
    xorq    %rax, %rax
    movl    %esp, %eax
    call    bob            # prints the same value as previous call to bob

    # this code breaks
    subl    $16, %esp      # bug here if I use this (32 bit math)
    subq    $16, %rsp      # works fine if I use this (64 bit math)
    call    bob
    addq    $16, %rsp

    # program cleanup
    movq    %rbp, %rsp
    popq    %rbp
    ret

# assumes 16 byte aligned when called. Prints %rax
 bob:
    subq    $8, %rsp
    movq    %rax, %rsi
    lea     _format(%rip), %rdi
    call    _printf
    addq    $8, %rsp
    ret

【问题讨论】:

标签: assembly x86-64 cpu-registers


【解决方案1】:

在 x86_64 中,地址是 64 位的,那么你怎么能期望在它上面做 32 位的数学运算并且仍然可以正常工作呢?此外,x86_64 上的大多数 32 位操作会将前 32 位清零,导致地址无效

【讨论】:

  • 不只是大多数。每条使用 32 位 %esomething 寄存器作为输出的指令都将高位 32 归零。因此,它们不依赖于寄存器的先前值,用于乱序执行。
【解决方案2】:

在与KerrekSB 交谈的帮助下,差异的原因是打印错误。当我说我打印了 RSP 和 ESP 时,我在 _printf 调用中使用了 %d,它打印了一个 4 字节的值。当应用于 RSP 时,它只打印低 4 个字节(相当于 ESP),让我相信 RSP 只有在低 4 个字节中有有意义的数据。当我将其更改为打印%lu 时,我发现 RSP 和 ESP 确实不等价,并且 RSP 使用高 4 个字节。这就是 32 位数学导致分段错误的原因。

【讨论】:

猜你喜欢
  • 2017-07-18
  • 1970-01-01
  • 2016-06-30
  • 2014-05-02
  • 2017-07-15
  • 2017-06-18
  • 1970-01-01
  • 2015-03-23
  • 2021-03-05
相关资源
最近更新 更多