I would like to call ARM/ARM64 ASM code from C++. ASM code contains syscall and a relocation to external function. ARM architecture here is not so important, I just want to understand how to solve my problem conceptually.
I have following ASM syscall (output from objdump -d
) which is called inside shared library:
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
This piece of code calls fstatat64
syscall and sets errno
through external __set_errno_internal
function.
readelf -r
shows following relocation for __set_errno_internal
function:
00000000000001a8 R_AARCH64_CONDBR19 __set_errno_internal
I want to call this piece of code from C++, so I converted it to buffer:
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";
EDIT: Important detail - I chose to use buffer (not inline assembly etc) because I want to run extra processing on this buffer (for example decryption function on string literal as a software protection mechanism but that's not important here) before it gets evaluated as machine code.
Afterwards, buffer can be cast to function and called directly to execute machine code. Obviously there is a problem with relocation, it's not fixed automatically and I have to fix it manually. But during run-time I can't do it because .text
section is read-only & executable.
Although I have almost full control over source code I must not turn off stack protection & other features to make that section writable (don't ask why). So it seems that relocation fix should be performed during link stage somehow. As far as I know shared library contains relative offsets (for similar external function calls) after relocations are fixed by linker and binary *.so file should contain correct offsets (without need of run-time relocation work), so fixing that machine_code
buffer during linking should be possible.
I'm using manually built Clang 7 compiler and I have full control over LLVM passes so I thought maybe it's possible to write some kind of LLVM pass which executes during link time. Though it looks like ld
is called in the end so maybe LLVM passes will not help here (not an expert here).
Different ideas would be appreciated also. As you can see problem is pretty complicated. Maybe you have some directions/ideas how to solve this? Thanks!