SYSCALL_INLINE in Android

非 Y 不嫁゛ 提交于 2019-12-24 00:45:14

问题


I need to use syscall internally in Android NDK to prevent hooking of the wrapper functions. In Linux there are macros like SYSCALL_INLINE which allows using syscall without wrapper function. Thus the macro embeds the syscall assembly code into the project directly.

I could not find similar macro in Android NDK.

Maybe I can write my own functions like this one; https://git.busybox.net/uClibc/tree/libc/sysdeps/linux/arm/syscall.c

But I need to have arm, arm_64, x86 and x86_64 versions of the same function.

Can you help me? How can I find a solution?


回答1:


Android's Linux kernel still uses the same system-call numbers and ABI as regular Linux, doesn't it? (So How to access the system call from user-space?) So you should be able to use the normal methods, with call numbers from <asm/unistd.h>.

You could use the MUSL libc syscall inline functions in arch/x86_64/syscall_arch.h. It has different ones for each different number of args, instead of one big one.


MUSL has versions of syscall_arch.h for ARM, AArch64, i386, and x86-64, as well as other architectures it supports. It's licensed under a permissive MIT license, so you can just copy those headers.

For example, their ARM version has

static inline long __syscall3(long n, long a, long b, long c)
{
    register long r7 __ASM____R7__ = n;  // macro trickery for not clobbering r7 in thumb mode (where it may be the frame pointer)
    register long r0 __asm__("r0") = a;
    register long r1 __asm__("r1") = b;
    register long r2 __asm__("r2") = c;
    __asm_syscall(R7_OPERAND, "0"(r0), "r"(r1), "r"(r2));
 // FIXME: add a "memory" clobber because pointed-to memory can be an input or output
}

Unfortunately this is not strictly safe: this doesn't tell the compiler that pointer operands are dereferenced, so it might treat stores into a buffer before write() as dead stores and optimize them away!

This is trivial to fix: add a "memory" clobber.

IDK if that was part of glibc's motivation for removing its similar syscall macros and only providing a non-inline syscall function. Or maybe they didn't want to encourage people to embed the system-call ABI into their program so it could in theory change to become more efficient in the future.

You'd use it like

#include <asm/unistd.h>   // for __NR_write
#include <stdlib.h>       // for ssize_t
#include "syscall_arch.h"

// doesn't set errno or force all error returns to -1
// return values from -1 to -4095 are errors, e.g. -EBADF or -EFAULT

__attribte__((noinline))  // hack for inline asm unsafety
ssize_t my_write(int fd, const void *buf, size_t count) {
    return __syscall3(__NR_write, fd, (long)buf, count);
}

I put this on the Godbolt compiler explorer with enough of ARM syscall_arch.h copied in to make this compile. Some of Godbolt's ARM gcc installs have missing <asm/unistd.h>, but gcc5.4 has a working one. The result in ARM mode is:

my_write:
    str     r7, [sp, #-4]!
    mov     r7, #4
@ system-calling convention mostly matches function-calling convention
@ so args are in the right registers already
    svc 0
    ldr     r7, [sp], #4
    bx      lr

And of course this function can inline into a caller so the save/restore of r7 happens once for the whole function.

(edit): this would be unsafe if inlined into a caller where dead stores could optimize away. A better brute-force option would be a memory clobber on the inline asm statement, or more work would be to add a dummy memory operand for system calls that read or write user-space memory (see at&t asm inline c++ problem). Or for munmap to make sure no stores into the page(s) being freed sink past it and happen after the memory is unmapped.



来源:https://stackoverflow.com/questions/50576767/syscall-inline-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!