Android 的 Linux 内核仍然使用与常规 Linux 相同的系统调用号和 ABI,不是吗? (所以如何从用户空间访问系统调用? https://stackoverflow.com/questions/11609110/how-to-access-the-system-call-from-user-space)所以你应该能够使用正常的方法,电话号码来自<asm/unistd.h>
.
您可以使用 MUSL libc 系统调用内联函数arch/x86_64/syscall_arch.h http://git.musl-libc.org/cgit/musl/tree/arch/x86_64/syscall_arch.h。对于每个不同数量的参数,它都有不同的参数,而不是一个大的参数。
MUSL 有以下版本syscall_arch.h
for ARM http://git.musl-libc.org/cgit/musl/tree/arch/arm/syscall_arch.h、AArch64、i386 和 x86-64,以及它支持的其他架构。它已获得许可宽松的麻省理工学院许可证 http://www.musl-libc.org/intro.html,因此您只需复制这些标头即可。
例如,他们的 ARM 版本定义了__asm_syscall
作为一个宏(在非 Thumb 模式下)asm volatile("svc 0" : "=r"(r0) : inputs);
return r0;
,并定义包装器,例如:
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));
// includes "=r0"(r0) and return r0
// FIXME: add a "memory" clobber because pointed-to memory can be an input or output
}
不幸的是,这并不安全:这不会告诉编译器指针操作数已被取消引用,因此它可能会在之前将存储处理到缓冲区中write()
作为死店并优化它们!
解决这个问题很简单:添加一个"memory"
破坏。或者看如何指示可以使用内联 ASM 参数*指向*的内存? https://stackoverflow.com/questions/56432259/how-can-i-indicate-that-the-memory-pointed-to-by-an-inline-asm-argument-may-be对于仅告诉编译器一个操作数的方法,对于特定的系统调用,您知道哪些操作数是指针以及它们是输入、输出还是两者。
我不知道这是否是 glibc 删除类似系统调用宏并仅提供非内联系统调用的动机的一部分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);
}
我把这个在 Godbolt 编译器资源管理器上 https://gcc.godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,lang:c%2B%2B,source:%27%23define+__SYSCALL_LL_E(x)+%5C%0D%0A((union+%7B+long+long+ll%3B+long+l%5B2%5D%3B+%7D)%7B+.ll+%3D+x+%7D).l%5B0%5D,+%5C%0D%0A((union+%7B+long+long+ll%3B+long+l%5B2%5D%3B+%7D)%7B+.ll+%3D+x+%7D).l%5B1%5D%0D%0A%23define+__SYSCALL_LL_O(x)+0,+__SYSCALL_LL_E((x))%0D%0A%0D%0A%23ifdef+__thumb__%0D%0A%0D%0A/*+Avoid+use+of+r7+in+asm+constraints+when+producing+thumb+code,%0D%0A+*+since+it!%27s+reserved+as+frame+pointer+and+might+not+be+supported.+*/%0D%0A%23define+__ASM____R7__%0D%0A%23define+__asm_syscall(...)+do+%7B+%5C%0D%0A%09__asm__+__volatile__+(+%22mov+%251,r7+%3B+mov+r7,%252+%3B+svc+0+%3B+mov+r7,%251%22+%5C%0D%0A%09:+%22%3Dr%22(r0),+%22%3D%26r%22((int)%7B0%7D)+:+__VA_ARGS__+:+%22memory%22)%3B+%5C%0D%0A%09return+r0%3B+%5C%0D%0A%09%7D+while+(0)%0D%0A%0D%0A%23else%0D%0A%0D%0A%23define+__ASM____R7__+__asm__(%22r7%22)%0D%0A%23define+__asm_syscall(...)+do+%7B+%5C%0D%0A%09__asm__+__volatile__+(+%22svc+0%22+%5C%0D%0A%09:+%22%3Dr%22(r0)+:+__VA_ARGS__+:+%22memory%22)%3B+%5C%0D%0A%09return+r0%3B+%5C%0D%0A%09%7D+while+(0)%0D%0A%23endif%0D%0A%0D%0A/*+For+thumb2,+we+can+allow+8-bit+immediate+syscall+numbers,+saving+a%0D%0A+*+register+in+the+above+dance+around+r7.+Does+not+work+for+thumb1+where%0D%0A+*+only+movs,+not+mov,+supports+immediates,+and+we+can!%27t+use+movs+because%0D%0A+*+it+doesn!%27t+support+high+regs.+*/%0D%0A%23ifdef+__thumb2__%0D%0A%23define+R7_OPERAND+%22rI%22(r7)%0D%0A%23else%0D%0A%23define+R7_OPERAND+%22r%22(r7)%0D%0A%23endif%0D%0A%0D%0A%0D%0Astatic+inline+long+__syscall3(long+n,+long+a,+long+b,+long+c)%0D%0A%7B%0D%0A%09register+long+r7+__ASM____R7__+%3D+n%3B%0D%0A%09register+long+r0+__asm__(%22r0%22)+%3D+a%3B%0D%0A%09register+long+r1+__asm__(%22r1%22)+%3D+b%3B%0D%0A%09register+long+r2+__asm__(%22r2%22)+%3D+c%3B%0D%0A%09__asm_syscall(R7_OPERAND,+%220%22(r0),+%22r%22(r1),+%22r%22(r2))%3B%0D%0A%7D%0D%0A%0D%0A%23include+%3Cstdlib.h%3E%0D%0A%23include+%3Casm/unistd.h%3E%0D%0A//%23include+%22syscall_arch.h%22%0D%0A//+doesn!%27t+set+errno+or+force+all+error+returns+to+-1%0D%0A//+return+values+from+-1+to+-4095+are+errors,+e.g.+-EBADF+or+-EFAULT%0D%0Assize_t+my_write(int+fd,+const+void+*buf,+size_t+count)+%7B%0D%0A++++return+__syscall3(__NR_write,+fd,+(long)buf,+count)%3B%0D%0A%7D%0D%0A%27),l:%275%27,n:%270%27,o:%27C%2B%2B+source+%231%27,t:%270%27)),k:52.32368921824802,l:%274%27,n:%270%27,o:%27%27,s:0,t:%270%27),(g:!((g:!((h:compiler,i:(compiler:armhfg54,filters:(b:%270%27,binary:%271%27,commentOnly:%270%27,demangle:%270%27,directives:%270%27,execute:%271%27,intel:%270%27,trim:%271%27),lang:c%2B%2B,libs:!(),options:%27-xc+-O3+-std%3Dgnu11+-Wall+-Wextra+-mcpu%3Dcortex-a53+-marm%27,source:1),l:%275%27,n:%270%27,o:%27ARM+gcc+5.4+(linux)+(Editor+%231,+Compiler+%231)+C%2B%2B%27,t:%270%27)),k:47.67631078175198,l:%274%27,m:50,n:%270%27,o:%27%27,s:0,t:%270%27),(g:!((h:output,i:(compiler:1,editor:1,wrap:%271%27),l:%275%27,n:%270%27,o:%27%231+with+ARM+gcc+5.4+(linux)%27,t:%270%27)),header:(),l:%274%27,m:50,n:%270%27,o:%27%27,s:0,t:%270%27)),k:47.67631078175198,l:%273%27,n:%270%27,o:%27%27,t:%270%27)),l:%272%27,n:%270%27,o:%27%27,t:%270%27)),version:4有足够的ARMsyscall_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
整个函数发生一次。
(编辑):如果内联到调用者中,这将是不安全的,死存储可能会被优化掉。更好的强力选项是在内联 asm 语句上使用内存破坏器,或者更多的工作是为读取或写入用户空间内存的系统调用添加虚拟内存操作数(请参阅).或者为了munmap
确保没有存储到正在释放的页面中并在内存取消映射后发生。
即使没有内联,它的过程间优化也使得这不是严格安全的,所以__attribute__((noinline,noipa))
,或者只是使用"memory"
破坏在asm
陈述!