如何让MASM汇编代码在Linux的.so文件中正常运行
PE格式MASM目标文件迁移Linux后函数指针表重定位失败问题
背景
原有项目使用VC++ + MASM(ml64 14.34.31942)编写.dll,其中C部分作为C#(.NET6)程序的调用包装器,仅提供一个入口点,传递大型状态对象指针并返回int32结果码。现需将该非托管部分迁移至Linux环境,C#程序可正常运行,但非托管库调用出现异常。
迁移尝试方案
- C包装器代码:为适配Linux x86-64调用约定,编写C包装器调整寄存器,代码如下(core.c):
#include <stdint.h> extern int32_t asm_func(void* state); int wrapper(void *state) { __asm__ volatile( "mov %rdi, %rsi \t\n" "call asm_func \t\n"); return 0; } int32_t fnEmulatorCode(void* state) { return wrapper(state); }
注:返回码暂未确定
- 编译命令:使用gcc将C代码与ml64生成的PE格式core.obj链接为Linux共享库:
gcc -shared -o EmulatorCore.so -fPIC core.c core.obj -Wall -g -m64
- C#引用方式:通过DllImport加载生成的.so文件:
[DllImport(@"./EmulatorCore/EmulatorCore.so")] private static extern int fnEmulatorCode(ref CpuState state);
故障细节
调用时入口点可正常找到,C包装器的寄存器调整逻辑也能正常工作,但汇编代码中的函数指针表无法在Linux下完成重定位,触发段错误(Windows环境下无此问题)。相关汇编代码片段如下:
lea rax [opcode_00] lea rax, qword ptr [rax + rbx * 8] ; rbx is the instruction jmp qword ptr [rax] ; was original jmp qword ptr [rax + rbx * 8] ... opcode_00 qword x00_brk ; $00 opcode_01 qword x01_ora_indx ; $01 opcode_02 qword noinstruction ; $02 ...
其他跳转和符号引用均正常,仅该函数指针表存在问题:
- 执行
nm -gC EmulatorCore.so | grep opcode_00无输出,说明opcode_00等符号未被导出到.so文件中,无法完成重定位(表中指向的函数过程已存在,程序其他部分可运行)。 - 内存对比显示:Windows下指针表位于库的内存范围内,Linux下表中值均为低偏移量,跳转时读取的地址错误。
待解决问题与需求
- Linux环境下无法重定位该函数指针表的原因是什么?是gcc优化导致、.NET加载库逻辑错误,还是PE格式目标文件的符号未正确暴露?
- 无法修改原MASM代码,是否存在工具可将MASM代码转换为NASM等可在Linux下交叉编译的格式?
- 优先保留原ASM代码,不希望改为标准跳转表(会影响性能且可能引入其他问题)。
内容的提问来源于stack exchange,提问作者BJury
相关产品推荐
相关产品推荐

