x86_64 程序集 %rsp 与 %esp

x86_64 assembly %rsp vs %esp

最近一直在玩汇编,在我的程序中遇到了一个奇怪的错误。我发现如果我通过 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    , %esp      # bug here if I use this (32 bit math)
    subq    , %rsp      # works fine if I use this (64 bit math)
    call    bob
    addq    , %rsp

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

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

在 x86_64 中,地址是 64 位的,那么您怎么能指望在其上进行 32 位数学运算并且还能正常工作呢?此外,x86_64 上的大多数 32 位操作会将前 32 位清零,使地址无效

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