Android中的SYSCALL_内联

Android中的SYSCALL_内联,android,assembly,android-ndk,system-calls,multiplatform,Android,Assembly,Android Ndk,System Calls,Multiplatform,我需要在androidndk内部使用syscall来防止包装器函数挂起。 在Linux中,有像SYSCALL_INLINE这样的宏,它允许在不使用包装函数的情况下使用SYSCALL。因此,宏将系统调用程序集代码直接嵌入到项目中 我在Android NDK中找不到类似的宏 也许我可以像这样编写自己的函数 但我需要有相同功能的arm、arm_64、x86和x86_64版本 你能帮我吗?如何找到解决方案?Android的Linux内核仍然使用与普通Linux相同的系统调用号和ABI,不是吗?(因此)您

我需要在androidndk内部使用syscall来防止包装器函数挂起。 在Linux中,有像SYSCALL_INLINE这样的宏,它允许在不使用包装函数的情况下使用SYSCALL。因此,宏将系统调用程序集代码直接嵌入到项目中

我在Android NDK中找不到类似的宏

也许我可以像这样编写自己的函数

但我需要有相同功能的arm、arm_64、x86和x86_64版本


你能帮我吗?如何找到解决方案?

Android的Linux内核仍然使用与普通Linux相同的系统调用号和ABI,不是吗?(因此)您应该能够使用常规方法,使用
中的呼叫号码。对于不同数量的arg,它有不同的arg,而不是一个大arg


MUSL拥有适用于、AARC64、i386和x86-64的
syscall_arch.h
版本,以及它支持的其他体系结构。它是在下授权的,所以您可以只复制这些标题

例如,他们的ARM版本

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
}
不幸的是,这并不是严格安全的:这不会告诉编译器指针操作数被取消引用,因此它可能会在
write()
之前将存储视为死存储并对其进行优化

这很容易解决:添加一个
“内存”
clobber.

IDK,如果这是glibc删除其类似系统调用宏并仅提供非内联系统调用函数的动机的一部分的话。或者,他们可能不想鼓励人们将系统调用ABI嵌入到他们的程序中,这样在理论上它可以在将来变得更高效

你会像这样使用它

#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);
}
当然,这个函数可以内联到调用者中,这样整个函数的
r7
保存/恢复只发生一次


(编辑):如果内联到调用程序中,死存储可以优化掉,那么这将是不安全的一个更好的暴力选项是在内联asm语句上使用内存缓冲,或者更多的工作是为读取或写入用户空间内存的系统调用添加虚拟内存操作数(请参阅)。或为
munmap
添加虚拟内存操作数,以确保页面中没有存储被释放的过程会经过它,并在内存被取消映射后发生。

您希望保护什么样的威胁?通常在Android上,你的应用程序运行在一个单独的沙箱中,没有不受信任的代理可以钩住syscall包装函数。我可以想象这个()或这个()甚至这个()@alexcohnou是传奇!回答得很好。什么是系统调用和系统调用宏?我需要关心LP64吗?@Phillip:AFAIK,头文件就可以了。我还没看过AArch64,我想那就是你找到的
\uuu LP64
?这将为
long
和指针为64位的ABI设置,或者不为ILP32模型定义(64位模式下的32位指针)。如果Android NDK没有在需要的时候定义它,你只需要担心它。非常感谢你,你是最好的。我看到LP64已经在android NDK头文件中定义了。我在i386
函数my_write(int,void const*,unsigned int)中得到了这个错误:错误:未定义对“u vsyscall”的引用。
我已经放置了#if i386指令来禁用其他cpu的代码。你有什么想法吗?哦,我没有看MUSL对i386做了什么。但是,是的,在32位x86上,进行系统调用的最佳方法是
调用
,进入内核映射到用户空间进程的虚拟内存的代码页(使用ELF共享库元数据)。有关VDSO的更多信息,请参阅,以防您需要采取措施使其链接到i386上。但为什么要在其他体系结构中包含i386定义呢?您希望只包含一个头部版本,即目标体系结构的版本。
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