我有一个独特的问题。我有一个使用 VC++ 和 MASM 编写的
.dll
。 (ml64 14.34.31942)
C 部分只是一个包装器,因此 C# (.net6) 应用程序可以调用一个函数。只有一个入口点,它传递一个指向大状态对象的指针。该函数返回一个 int32 作为结果代码。
我想让这个应用程序在 Linux 上运行。我认为 C# 应用程序可以工作,但我的问题是调用非托管
.dll
.
如果我使用
ml64.exe
创建的目标文件,我可以将它包装在 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 -shared -o EmulatorCore.so -fPIC core.c core.obj -Wall -g -m64
(core.obj是MASM目标文件)
生成的
.so
文件像任何其他非托管 dll 一样被引用:
[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
...
所有其他跳跃和引用似乎都很好。
关于如何进行的建议?根据
pe-x86-64
,MASM生成的object文件是objdump
。但是objcopy
似乎无法将其转换为elf64-x86-64
.
那么为什么 Linux 不“重新定位”这些表呢?是通过一些 gcc 优化吗?或者 dotnet 没有正确加载库?或者只是
pe-coff
文件没有正确公开它们?如果是这样,我该如何解决?
我无法从 MASM 更改原始代码,但是有什么可以将其转换为 NASM 或类似的东西以便我可以交叉编译吗? (不是谷歌搜索发现任何东西..)
我可能会将表更改为适当的“跳转表”,但这会损害性能并且可能存在其他问题,因此在第一个实例中我宁愿尝试保持 ASM 源原样......
编辑:
使用
nm -gC EmulatorCore.so | grep opcode_00
不返回任何内容,这意味着引用未包含在 .so
文件中,因此无法正确重定位? (表中的过程确实出现了,这就是应用程序的其余部分似乎可以工作的原因)
编辑2:
为了说明这个问题,请比较这两张图片。一个来自 Windows,它显示了库在内存中的范围内的表,在 Linux 中,这些值都非常低,表明它们是库入口点的偏移量。
Windows内存中的表(RIP:0x00007FFE043C5817)