我想从C++调用ARM / ARM64 ASM代码。 ASM代码包含syscall和重定位到外部函数。
这里的ARM体系结构不是那么重要,我只想了解如何从概念上解决问题。
我有以下在共享库中调用的ASM syscall(从objdump -d
输出):
198: d28009e8 mov x8, #0x4f // #79
19c: d4000001 svc #0x0
1a0: b140041f cmn x0, #0x1, lsl #12
1a4: da809400 cneg x0, x0, hi
1a8: 54000008 b.hi 0 <__set_errno_internal>
1ac: d65f03c0 ret
这段代码调用
fstatat64
syscall,并通过外部errno
函数设置__set_errno_internal
。readelf -r
显示了__set_errno_internal
函数的以下重定位:00000000000001a8 R_AARCH64_CONDBR19 __set_errno_internal
我想从C++调用这段代码,所以我将其转换为缓冲区:
unsigned char machine_code[] __attribute__((section(".text"))) =
"\xe8\x09\x80\xd2"
"\x01\x00\x00\xd4"
"\x1f\x04\x40\xb1"
"\x00\x94\x80\xda"
"\x08\x00\x00\x54" // Here we have mentioned relocation
"\xc0\x03\x5f\xd6";
编辑:重要细节-我选择使用缓冲区(而不是内联汇编等),因为我想对该缓冲区进行额外的处理(例如,字符串字面量的解密函数作为一种软件保护机制,但这在这里并不重要),然后才被评估为机器代码。
之后,可以将缓冲区转换为函数并直接调用以执行机器代码。显然,重定位存在问题,它不是自动修复的,我必须手动修复。但是在运行时我无法做到这一点,因为
.text
部分是只读的且可执行的。尽管我几乎可以完全控制源代码,但是我一定不能关闭堆栈保护和其他功能以使该部分可写(不要问为什么)。因此,似乎应该以某种方式在链接阶段执行重定位修复。据我所知,在链接器和二进制文件* .so修复了重定位后,共享库包含相对偏移量(用于类似的外部函数调用),因此文件应包含正确的偏移量(无需运行时重定位工作),因此请在运行时修复
machine_code
缓冲区链接应该是可能的。我正在使用手动构建的Clang 7编译器,并且可以完全控制LLVM传递,因此我认为也许可以编写某种在链接时间内执行的LLVM传递。尽管看起来
ld
最终被调用了,所以LLVM传递可能对这里没有帮助(这里不是专家)。也将理解不同的想法。
如您所见,问题非常复杂。也许您有一些指导/想法如何解决这个问题?谢谢!
最佳答案
已经有一种有效的打包机制来处理重定位。它称为dlsym()
。尽管它没有直接为您提供函数指针,但是所有主要的C++编译器都支持reinterpret_cast
,将dlsym
的结果存储到任何普通函数指针中。 (成员函数完全是另一个问题,但这与这里无关)