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 字节对齐的。为了确保这一点,我们需要根据保存的寄存器数量来决定是否要调整堆栈指针。
奇数和偶数个寄存器的影响
-
奇数个寄存器:
- 每个
push
指令都会将堆栈指针减少 8 个字节
。 - 如果你保存奇数个寄存器(例如
1、3、5
个寄存器),堆栈指针会减少一个不是 16 字节
的倍数的值(如8、24、40
个字节)。 - 这时,
堆栈指针的对齐就会被破坏
,从而导致后续函数调用时堆栈不是16 字节对齐
的。
- 每个
-
偶数个寄存器:
- 如果你保存偶数个寄存器(例如
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 字节对齐的,所以不需要进行额外的调整。
这个技巧帮助你在函数调用时确保堆栈的对齐性,从而避免潜在的问题。
标签:字节,x64,C++,push,vs2022,寄存器,堆栈,对齐,指针 From: https://blog.csdn.net/zsr154278963/article/details/141124499