如何将C++的KeysCpp函数转为x86_64汇编?栈溢出问题排查
问题描述
需要将C中的KeysCpp函数转换为x86_64汇编实现KeysAsm,并在原C文件中调用,保留crim的C实现。以下是原C代码:
#include <iostream> using namespace std; extern "C" void KeysAsm(int arr[], int n, int thetha, int rho); // Keep this and call it from assembler extern "C" void crim(int *xp, int *yp) { int temp = *xp; *xp = *yp; *yp = temp+2; } // Translate this into Intel assembler void KeysCpp(int arr[], int n, int thetha, int rho){ for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { crim(&arr[j], &arr[j + 1]); } } arr[i]= arr[i] + thetha / rho * 2 - 4; } } // Function to print an array void printArray(int arr[], int size){ int i; for (i = 0; i < size; i++) cout << arr[i] << "\n"; cout << endl; } int main() { int gamma1[]{ 9, 270, 88, -12, 456, 80, 45, 123, 427, 999 }; int gamma2[]{ 900, 312, 542, 234, 234, 1, 566, 123, 427, 111 }; printf("Array:\n"); printArray(gamma1, 10); KeysAsm(gamma1, 10, 5, 6); printf("Array Result Asm:\n"); printArray(gamma1, 10); KeysCpp(gamma2, 10, 5, 6); printf("Array Result Cpp:\n"); printArray(gamma2, 10); }
编写的汇编文件如下:
PUBLIC KeysAsm includelib kernel32.lib _DATA SEGMENT EXTERN crim:PROC _DATA ENDS _TEXT SEGMENT KeysAsm PROC push rbp mov rbp, rsp sub rsp, 40 mov QWORD PTR [rbp-24], rdi mov DWORD PTR [rbp-28], esi mov DWORD PTR [rbp-32], edx mov DWORD PTR [rbp-36], ecx mov DWORD PTR [rbp-4], 0 jmp L3 L3: mov eax, DWORD PTR [rbp-28] sub eax, 1 cmp DWORD PTR [rbp-4], eax jl L7 L4: mov eax, DWORD PTR [rbp-28] sub eax, DWORD PTR [rbp-4] sub eax, 1 cmp DWORD PTR [rbp-8], eax jl L6 L5: add DWORD PTR [rbp-8], 1 L6: mov eax, DWORD PTR [rbp-8] cdqe lea rdx, [0+rax*4] mov rax, QWORD PTR [rbp-24] add rax, rdx mov edx, DWORD PTR [rax] mov eax, DWORD PTR [rbp-8] cdqe add rax, 1 lea rcx, [0+rax*4] mov rax, QWORD PTR [rbp-24] add rax, rcx mov eax, DWORD PTR [rax] cmp edx, eax jle L5 mov eax, DWORD PTR [rbp-8] cdqe add rax, 1 lea rdx, [0+rax*4] mov rax, QWORD PTR [rbp-24] add rdx, rax mov eax, DWORD PTR [rbp-8] cdqe lea rcx, [0+rax*4] mov rax, QWORD PTR [rbp-24] add rax, rcx mov rsi, rdx mov rdi, rax call crim L7: mov DWORD PTR [rbp-8], 0 jmp L4 KeysAsm ENDP _TEXT ENDS END
运行时出现错误:
Unhandled exception at 0x00007FF74B0E429C in MatrixMultiplication.exe: Stack cookie instrumentation code detected a stack-based buffer overrun. occurred
问题排查与修复
错误原因分析
- 调用约定不符合MSVC规范:x86_64 MSVC调用约定中,函数前两个参数通过
rcx、rdx传递,但原汇编调用crim时用了rsi、rdi,导致参数传递错误。 - 栈空间分配不足且未对齐:MSVC要求栈保持16字节对齐,原代码
sub rsp,40后栈未满足对齐要求,且局部变量和寄存器保存的空间计算错误,引发栈溢出。 - 循环逻辑缺失且跳转混乱:原汇编未实现外层循环中
arr[i] = arr[i] + thetha / rho *2 -4的核心逻辑,同时循环跳转逻辑错误,导致循环无法正常终止,越界访问内存。 - 寄存器未正确恢复:原代码保存了非易失性寄存器
rdi,但未在函数结束时恢复,破坏了调用者的上下文。
修正后的汇编代码
PUBLIC KeysAsm _DATA SEGMENT EXTERN crim:PROC _DATA ENDS _TEXT SEGMENT ; MSVC x86_64调用约定:rcx=arr, rdx=n, r8=thetha, r9=rho KeysAsm PROC push rbp mov rbp, rsp sub rsp, 32 ; 分配栈空间,满足16字节对齐,用于保存寄存器和局部变量 mov QWORD PTR [rbp-8], rbx ; 保存非易失性寄存器rbx mov QWORD PTR [rbp-16], rsi ; 保存非易失性寄存器rsi mov QWORD PTR [rbp-24], rdi ; 保存非易失性寄存器rdi mov rsi, rcx ; rsi = arr(数组指针) mov ecx, edx ; ecx = n mov r8d, r8d ; r8d = thetha mov r9d, r9d ; r9d = rho mov ebx, 0 ; ebx = i(外层循环计数器) outer_loop: cmp ebx, ecx jge outer_exit ; 如果i >=n,退出外层循环 mov edx, ecx sub edx, ebx sub edx, 1 ; edx = n - i -1 mov edi, 0 ; edi = j(内层循环计数器) inner_loop: cmp edi, edx jge inner_exit ; 如果j >=n-i-1,退出内层循环 ; 比较arr[j]和arr[j+1] mov eax, edi lea rcx, [rsi+rax*4] ; rcx = &arr[j] mov eax, DWORD PTR [rcx] lea rdx, [rsi+rdi*4+4] ; rdx = &arr[j+1] mov r8d, DWORD PTR [rdx] cmp eax, r8d jle inner_inc ; 如果arr[j] <= arr[j+1],跳过交换 ; 调用crim(&arr[j], &arr[j+1]) call crim inner_inc: inc edi jmp inner_loop inner_exit: ; 执行arr[i] = arr[i] + thetha/rho*2 -4 mov eax, r8d ; eax = thetha cdq idiv r9d ; eax = thetha / rho(整数除法) imul eax, 2 ; eax *=2 sub eax,4 ; eax -=4 lea rcx, [rsi+rbx*4] ; rcx = &arr[i] add DWORD PTR [rcx], eax inc ebx jmp outer_loop outer_exit: ; 恢复寄存器 mov rbx, QWORD PTR [rbp-8] mov rsi, QWORD PTR [rbp-16] mov rdi, QWORD PTR [rbp-24] add rsp,32 pop rbp ret KeysAsm ENDP _TEXT ENDS END
修正说明
- 遵循MSVC调用约定:使用
rcx、rdx传递crim的两个参数,符合x86_64 MSVC规范。 - 栈空间正确分配与对齐:分配32字节栈空间,满足16字节对齐要求,同时保存所有需要保留的非易失性寄存器(rbx、rsi、rdi)。
- 补全循环逻辑:实现了外层循环中
arr[i]的计算逻辑,同时修正了循环跳转条件,确保循环正常终止。 - 寄存器正确恢复:函数结束时恢复所有保存的非易失性寄存器,保证调用者上下文不受破坏。
内容的提问来源于stack exchange,提问作者Varun Gujarathi
相关产品推荐
相关产品推荐

