G++与NASM代码在Rocky 9运行报错,CentOS 7编译运行正常
问题根源定位
你遇到的段错误看似触发在mov r8, rdi指令,但寄存器间的移动本身不会引发内存错误,实际问题大概率是内存越界访问,或是新系统/编译器的内存保护机制更严格,导致之前隐藏的问题暴露。
核心问题1:指针类型与内存偏移不匹配
你的C++代码中,函数参数为unsigned long *(x86-64下为8字节指针),但汇编代码中却以4字节(dword)为单位、8字节步长写入数据:
mov dword [r8], eax mov dword [r8+8], ebx mov dword [r8+16], ecx mov dword [r8+24], edx
如果CPUIDreg.reg是用于存储CPUID 4个32位结果的unsigned int[4]数组(总大小16字节),那么[r8+16]和[r8+24]已经越界访问数组外的内存。CentOS 7的内存布局或栈保护机制宽松,越界未触发错误;但Rocky 9/CentOS Stream 9的内存保护更严格,或启用的-lefence(Electric Fence)工具检测到了越界,直接触发段错误。
核心问题2:Electric Fence兼容性
Rocky 9中的Electric Fence版本对现代编译选项(如默认启用的PIE)支持不佳,可能误判或放大内存访问问题。
解决方案
方案1:修正内存偏移(推荐)
既然CPUID返回的是4个32位寄存器值,应将汇编中的内存偏移改为4字节步长,对应unsigned int[4]数组:
Global get_cpuid_info get_cpuid_info: mov r8, rdi ;# array addr mov r9, rsi ;# leaf mov r10, rdx ;# subleaf push rax push rbx push rcx push rdx mov rax, r9 mov rcx, r10 cpuid mov dword [r8], eax mov dword [r8+4], ebx ; 改为+4 mov dword [r8+8], ecx ; 改为+8 mov dword [r8+12], edx ; 改为+12 pop rdx pop rcx pop rbx pop rax ret
同时调整C++函数声明的参数类型,匹配实际数组类型:
extern "C" void get_cpuid_info(unsigned int *, const unsigned long func, const unsigned long subfunc);
方案2:确保数组大小足够
如果坚持使用unsigned long *参数,需保证CPUIDreg.reg是至少包含4个unsigned long元素的数组(总大小32字节),确保[r8+24]的访问在数组范围内:
// 定义足够大的数组 unsigned long CPUIDreg_reg[4]; get_cpuid_info(CPUIDreg_reg, 0, 0);
方案3:移除Electric Fence测试
暂时去掉编译命令中的-lefence选项,验证是否是工具兼容性问题:
g++ -L../../lib -ltsx64 -pthread -o cpuinfo cpuinfo.o test1.o
方案4:显式关闭PIE编译(可选)
Rocky 9的GCC默认启用PIE(位置无关可执行文件),如果汇编代码对PIE兼容性不佳,可显式添加-no-pie编译选项:
g++ -c -Wall -g -D_DEBUG -Dx86_64 -pthread -no-pie -o cpuinfo.o cpuinfo.cpp g++ -L../../lib -ltsx64 -pthread -no-pie -o cpuinfo cpuinfo.o test1.o
内容的提问来源于stack exchange,提问作者Jonathan

