vs2022 x64 C/C++和汇编混编 遇到的坑


遇到的问题

0x00007FFFFAE24A29 (msvcp140.dll)处(位于 TestCompileConsoleApp.exe 中)引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突。
查阅资料发现:异常 0xC0000005: Access Violation 表示程序试图访问一个无效的内存地址。在你的情况下,读取地址 0xFFFFFFFFFFFFFFFF 发生了访问冲突。这通常意味着你试图访问一个无效的指针或未初始化的指针。

— # 一、pandas是什么?
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、问题复现

1.出错代码

代码如下(示例):

capp proc
    sub rsp, 28h             ; 为局部变量和寄存器保存空间

    ; 保存所有需要的寄存器
    push rax
    push rcx
    push rdx
    push r8
    push r9
    push r10
    push r11

    ; 自定义代码
    mov rcx, 10              ; 将参数传递给RCX寄存器
    call hookFunc            ; 调用hookFunc函数

    ; 恢复所有寄存器
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    pop rcx
    pop rax

    add rsp, 28h             ; 恢复堆栈指针
    ret
capp endp

2.问题分析

2.1 堆栈对齐问题

在 x64 汇编中,函数调用时堆栈指针(RSP)必须是 16 字节对齐的。如果你在调用函数前通过 push 指令保存了寄存器,堆栈指针会减少 8 个字节,这可能会导致堆栈不对齐。

3.解决方案

 capp proc
    sub rsp, 28h             ; 为局部变量和寄存器保存空间

    ; 保持堆栈对齐
    sub rsp, 8

    ; 保存寄存器
    push rax
    push rcx
    push rdx
    push r8
    push r9

    ; 调用你的函数
    mov rcx, 10
    call hookFunc

    ; 恢复寄存器
    pop r9
    pop r8
    pop rdx
    pop rcx
    pop rax

    ; 恢复堆栈对齐
    add rsp, 8

    add rsp, 28h             ; 恢复堆栈指针
    ret
capp endp

如果保存寄存器的数量是奇数个,可以通过手动调整来保证堆栈对齐。例如,使用 sub rsp, 8 手动调整堆栈指针,使其对齐到 16 字节。


总结

在 x64 汇编中,堆栈的对齐要求是函数调用时堆栈指针(RSP)必须是 16 字节对齐的。为了确保这一点,我们需要根据保存的寄存器数量来决定是否要调整堆栈指针。

奇数和偶数个寄存器的影响

  1. 奇数个寄存器:

    • 每个 push 指令都会将堆栈指针减少 8 个字节
    • 如果你保存奇数个寄存器(例如1、3、5个寄存器),堆栈指针会减少一个不是 16 字节的倍数的值(如 8、24、40 个字节)。
    • 这时,堆栈指针的对齐就会被破坏,从而导致后续函数调用时堆栈不是 16 字节对齐的。
  2. 偶数个寄存器:

    • 如果你保存偶数个寄存器(例如 2、4、6 个寄存器),堆栈指针减少的值会是 16 字节的倍数(如16、32、48个字节)。
    • 在这种情况下,堆栈指针的对齐不会被破坏,因此不需要进行额外的调整。

为什么 sub rsp, 8 对奇数个寄存器有用?

当你保存奇数个寄存器时,堆栈指针被推到一个不是 16 字节对齐的地址。通过在保存寄存器之前执行 sub rsp, 8,你可以先手动将堆栈指针调整到一个不对齐的状态,接下来每次 push 操作都会在最终使堆栈指针回到对齐的状态。

具体来说:

  • sub rsp, 8 手动将 RSP 移动 8 个字节,使其暂时不对齐。
  • 然后,每次 push 操作都会进一步移动 RSP 8 个字节。
  • 如果你总共 push 奇数个寄存器,RSP 将恢复到对齐的状态。

结论

  • 奇数个寄存器: 你需要通过 sub rsp, 8 手动调整堆栈指针,以确保保存和恢复寄存器后堆栈指针是 16 字节对齐的。
  • 偶数个寄存器: 由于堆栈指针在保存和恢复寄存器前后仍然是 16 字节对齐的,所以不需要进行额外的调整。

这个技巧帮助你在函数调用时确保堆栈的对齐性,从而避免潜在的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值