如何让 MASM 程序集在 Linux .so 文件中工作

问题描述 投票:0回答:0

我有一个独特的问题。我有一个使用 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)

Linux内存中的表(RIP: 0x00007f24fc59a5a8)

从表中跳转后显示RIP,显示它正在正确读取值,它只是值是错误的。

c gcc shared-libraries masm
© www.soinside.com 2019 - 2024. All rights reserved.