You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows x86-64下机器码调用C++函数触发段错误求助

故障原因及修复方案

故障原因

Windows x86-64平台的官方调用约定(__fastcall)明确要求:调用者必须在栈上预留32字节的影子空间,供被调用函数使用(即使函数参数少于4个)。你的机器码没有分配这个空间,导致test函数内部调用std::cout时,尝试访问栈上的非法地址,最终触发段错误。

修复方法

在调用test函数前,先通过sub rsp, 0x20指令分配32字节的影子空间;函数调用完成后,再用add rsp, 0x20恢复栈指针平衡。

修改后的完整代码如下:

#include <windows.h>
#include <iostream>
#include <cstring>

void test(long long int val) {
    std::cout << "Calling test function:" << val << std::endl;
}

int main() {

    unsigned char code[] = {
            // 分配32字节影子空间
            0x48, 0x83, 0xEC, 0x20, // sub rsp, 0x20
            // 将目标函数地址加载到RAX寄存器
            0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0, // mov rax, imm64
            // 将参数加载到RCX寄存器(x64 Windows下第一个参数用RCX传递)
            0x48, 0xB9, 0, 0, 0, 0, 0, 0, 0, 0, // mov rcx, imm64
            // 调用目标函数
            0xFF, 0xD0, // call rax
            // 恢复栈指针
            0x48, 0x83, 0xC4, 0x20, // add rsp, 0x20
            0xC3 // ret
    };

    // 模拟调用test(12345);
    *((void **) &code[4]) = (void *) &test; // 写入函数地址(偏移因新增指令调整)
    *((long long int *) &code[14]) = 12345L; // 写入参数值(偏移相应后移)

    // 准备可执行内存
    SYSTEM_INFO sys_info;
    GetSystemInfo(&sys_info);
    auto const page_size = sys_info.dwPageSize;
    auto const code_buffer = VirtualAlloc(nullptr, page_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    ::memcpy(code_buffer, code, sizeof(code));

    using func_ptr_t = void (*)();
    auto const func_ptr = reinterpret_cast<func_ptr_t>(code_buffer);
    func_ptr();
    VirtualFree(code_buffer, 0, MEM_RELEASE);

    return 0;
}

关键修改说明

  1. 增加栈操作指令:调用前分配影子空间,调用后恢复栈平衡,保证被调用函数的栈访问合法。
  2. 调整地址和参数的写入偏移:因新增了4字节的栈操作指令,函数地址和参数的写入位置需相应后移。

内容的提问来源于stack exchange,提问作者Alphaharrius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 00:52:49