我知道系统调用号作为ARM OABI(旧应用程序二进制接口)上的“svc(或swi)”指令的立即操作数传递。立即操作数为“0x900000 +(系统调用次数)”例如,EXIT系统调用按如下方式发出。
svc #0x900001 @ sys_exit
我对syscall()函数的实现感到好奇,因为sycall()获取系统调用号作为其参数。我想如果参数值是动态创建的,那么syscall()的二进制代码就不能轻易创建。 但是,glibc的syscall()的二进制代码很简单。它将系统调用次数设置为“寄存器r0”,并将参数设置为“寄存器r1-r6”。之后,执行“svc#0x900071”。
测试环境是Debian lenny ARM OABI,Linux 2.6.26,gcc 4.2,glibc 2.7.18。 syscall()的二进制代码如下。
00012560 <syscall>:
12560: e1a0c00d mov ip, sp
12564: e92d0070 push {r4, r5, r6}
12568: e89c0070 ldm ip, {r4, r5, r6}
1256c: ef900071 svc 0x00900071
12570: e8bd0070 pop {r4, r5, r6}
12574: e3700a01 cmn r0, #4096 ; 0x1000
12578: 31a0f00e movcc pc, lr
1257c: ea000547 b 13aa0 <__syscall_error>
系统调用的调用方式如下。这是“syscall(SYS_getuid)”的示例。
8270: e3a00609 mov r0, #9437184 ; 0x900000
8274: e2800018 add r0, r0, #24 ; 0x18
8278: eb0028b8 bl 12560 <syscall>
什么是“svc#0x900071”?它可以作为超级系统调用。
答案 0 :(得分:1)
http://man7.org/linux/man-pages/man2/syscall.2.html
在进行真正的系统调用之前/之后还有一些工作要做,例如:注册保存/恢复。
所以,syscall()
是帮助你做到这一点。
syscall() is a small library function that invokes the system call
whose assembly language interface has the specified number with the
specified arguments. Employing syscall() is useful, for example,
when invoking a system call that has no wrapper function in the C
library.
syscall() saves CPU registers before making the system call, restores
the registers upon return from the system call, and stores any error
code returned by the system call in errno(3) if an error occurs.
看看这里:
https://w3challs.com/syscalls/?arch=arm_strong
在这里:
https://chromium.googlesource.com/native_client/nacl-newlib/+/master/libgloss/arm/linux-syscall.h
# define SYS_BASE 0x900000
#define SYS_syscall (SYS_BASE+113)
好吧,0x900000 + 113 == 0x900071。
因此,syscall()
调用真正的系统调用:)
答案 1 :(得分:0)
谢谢你,肖恩!
我检查了&#34; /usr/include/asm/unistd.h"提交并找到以下句子。
#define __NR_syscall (__NR_SYSCALL_BASE+113) /* syscall to call a syscall! */
我还检查了ARM Debian EABI(即ARMEL)上的相同文件并找到了相同的句子。然而,&#34;系统调用&#34;的手册页没有系统调用&#34;系统调用&#34;。我知道对人的解释是不可靠的。
所以,我在EABI Linux上检查了syscall()的二进制代码。它正在跟随。
00014670 <syscall>:
14670: e1a0c00d mov ip, sp
14674: e92d00f0 push {r4, r5, r6, r7}
14678: e1a07000 mov r7, r0
1467c: e1a00001 mov r0, r1
14680: e1a01002 mov r1, r2
14684: e1a02003 mov r2, r3
14688: e89c0078 ldm ip, {r3, r4, r5, r6}
1468c: ef000000 svc 0x00000000
14690: e8bd00f0 pop {r4, r5, r6, r7}
14694: e3700a01 cmn r0, #4096 ; 0x1000
14698: 312fff1e bxcc lr
1469c: ea00061b b 15f10 <__syscall_error>
有趣的是因为 EABI glibc不使用系统调用(113)。系统调用的调用方式如下。这是&#34;系统调用(SYS_getuid)&#34;。
的示例826c: e3a00014 mov r0, #20
8270: eb0030fe bl 14670 <syscall>
系统调用号由寄存器&#34; r0&#34;传递。到&lt;系统调用&gt;,然后将其移动到注册&#34; r7&#34;在&lt;系统调用&gt;,遵循EABI定义的规则&#34; man syscall&#34;。
arch/ABI instruction syscall # retval Notes
-------------------------------------------------------------------
arm/OABI swi NR - a1 NR is syscall #
arm/EABI swi 0x0 r7 r0
是的,OABI上的syscall()也遵循使用特殊系统调用&#34; __ NR_syscall&#34;的规则。
所以,是&#34; __ NR_syscall&#34;是OABI的特殊系统调用吗?
然而,EABI Linux保留了&#34; __ NR_syscall&#34;。是兼容性吗?我知道EABI Linux内核可以运行OABI二进制文件。