Android中的SYSCALL_INLINE [英] SYSCALL_INLINE in Android

查看:675
本文介绍了Android中的SYSCALL_INLINE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在Android NDK中内部使用syscall,以防止包装器函数被钩住. 在Linux中,有一些类似SYSCALL_INLINE的宏,这些宏允许在不使用包装函数的情况下使用syscall.因此,宏将syscall程序集代码直接嵌入到项目中.

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

也许我可以像这样编写自己的函数; https://git.busybox.net/uClibc/树/libc/sysdeps/linux/arm/syscall.c

但是我需要具有相同功能的arm,arm_64,x86和x86_64版本.

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

解决方案

Android的Linux内核仍然使用与常规Linux相同的系统调用号和ABI,不是吗? (因此如何从用户空间访问系统调用?)因此您应该能够使用正常的方法,并且呼叫号码来自<asm/unistd.h>.

您可以在 arch/x86_64/syscall_arch.h .每个不同数量的args都有一个不同的参数,而不是一个大参数.


MUSL具有用于syscall_arch.h版本."rel =" nofollow noreferrer > ARM ,AArch64,i386和x86-64 ,以及它支持的其他体系结构.它是根据许可的MIT许可获得的许可,因此您只需复制这些标头即可. >

例如,他们的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()之前的缓冲区中视为无效存储,并对其进行优化!

要解决的问题很简单:添加一个"memory"垃圾桶.

IDK(如果这是glibc删除其相似的syscall宏并仅提供非内联syscall function 的动机的一部分).或者,也许他们不想鼓励人们将系统调用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);
}

我把这个,并复制了足够多的ARM syscall_arch.h进行编译. Godbolt的一些ARM gcc安装缺少<asm/unistd.h>,但是gcc5.4可以正常运行.在ARM模式下的结果是:

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

当然,此函数可以内联到调用者中,因此r7的保存/恢复在整个函数中执行一次.

(edit):如果内联到调用者中,死存储可能会优化掉,这将是不安全的. 更好的暴力选择是在嵌入式asm语句上使用内存破坏器,或者更多的工作是为读取或写入用户空间内存的系统调用添加虚拟内存操作数(请参见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?

解决方案

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.

这篇关于Android中的SYSCALL_INLINE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆