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

从x64汇编调用返回std::string的C++函数出现读取访问违规

问题成因
  • C ABI 不支持非平凡类型传递:extern "C" 仅遵循C语言的ABI约定,而C++的std::string是带自定义构造、析构、拷贝逻辑的非POD类型,C ABI没有定义这类对象的传递规则。按照微软x64调用约定,返回大于8字节的非平凡对象时,要求调用方提前分配返回值内存,并将该内存指针作为隐藏的第一个参数传入被调用方,你当前的汇编代码完全没有处理这个隐藏参数,直接从rax取到的根本不是合法的string对象地址。
  • 对象生命周期管理错误:就算你侥幸拿到了第一次返回的string地址,inputString中定义的局部string会在函数返回后自动触发析构,对应的字符串内存要么被释放,要么在第二次调用inputString时被复用覆盖,后续访问自然会触发读取违规。
  • x64栈对齐不符合约定:微软x64调用约定要求执行call指令前,rsp必须16字节对齐。你进入asm_main时,栈上已经压了8字节的返回地址,此时rsp为16n+8,仅执行sub rsp,20h后rsp为16n-24=16(n-2)+8,调用函数前没有满足16字节对齐要求,会导致C++函数内部的对齐敏感指令直接崩溃。
修复方案

1. 修改C++接口

将接口调整为符合C ABI的平凡类型传递,避免直接传递std::string对象:

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
using namespace std;

extern "C" char* inputString() {
    string strInput;
    cout << "Enter string input: ";
    cin >> strInput;
    // 动态分配内存返回C风格字符串,调用方负责释放
    char* res = (char*)malloc(strInput.size() + 1);
    strcpy_s(res, strInput.size() + 1, strInput.c_str());
    return res;
}

extern "C" int outputStringLen(const char* strInput) {
    if (!strInput) return 0;
    return (int)strlen(strInput);
}

// 用于释放返回的字符串内存
extern "C" void freeString(char* str) {
    free(str);
}

2. 修改汇编代码

修正栈对齐逻辑,正确保存非易失寄存器和返回的字符串指针:

extern inputString : proto C
extern outputStringLen : proto C
extern freeString : proto C

.data 

.CODE
asm_main PROC
    ; 先保存用到的非易失寄存器,符合x64调用约定
    push rbx
    push rsi
    push r12
    push r13
    ; 预留32字节阴影空间,此时rsp刚好满足16字节对齐要求
    sub rsp, 20h                

    ; 第一次获取字符串
    call inputString            
    mov rbx, rax                ; 保存第一个字符串指针
    mov rcx, rax                
    call outputStringLen
    mov r12, rax                ; 保存第一个字符串长度

    ; 第二次获取字符串
    call inputString            
    mov rsi, rax                ; 保存第二个字符串指针
    mov rcx, rax                
    call outputStringLen
    mov r13, rax                ; 保存第二个字符串长度

    ; 此处可添加你的字符串拼接逻辑,直接使用rbx、r12、rsi、r13即可

    ; 释放内存避免泄漏
    mov rcx, rbx
    call freeString
    mov rcx, rsi
    call freeString

    ; 恢复栈和寄存器
    add rsp, 20h
    pop r13
    pop r12
    pop rsi
    pop rbx
    ret                         
asm_main ENDP
END

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 12:54:03