syscall功能说明
- 在Linux平台,可以使用syscall()函数调用系统提供的函数。使用系统调用编号调用对应的系统接口。
- 通常,常用的系统调用都有C语言的运行时封装,可以直接调用对应的C函数即可。例如:open、write等都是封装的系统调用。(fopen、fwrite是C标准库函数,这些是可移植的。)
- 有些系统调用没有提供C函数,只能通过syscall调用。例如:gettid,获取线程id。
- 如果自己开发新增了一些系统接口,也可以使用syscall来调用。
示例代码
下面例子演示用syscall的方式调用对应的系统调用。
#include <sys/syscall.h> /* For SYS_xxx definitions */
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#define PATH "/tmp/"
#define MESSAGE "hello\n"
void write_file() {
char* filename = PATH"/test-open-write.txt";
int fd = open(filename, O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG);
if (fd < 0) {
printf("failed to open file (%S): [%d-%s]\n", filename, errno, strerror(errno));
return;
}
int ret = write(fd, MESSAGE, sizeof(MESSAGE));
printf("write: ret=%d\n", ret);
close(fd);
}
void write_file_syscall() {
char* filename = PATH"/test-syscall.txt";
// int fd = open(PATH"/syscall-a.txt", O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG);
int fd = syscall(SYS_open, filename, O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG); // syscall替换open
if (fd < 0) {
printf("failed to open file (%S): [%d-%s]\n", filename, errno, strerror(errno));
return;
}
// int ret = write(fd, msg, sizeof(msg));
int ret = syscall(SYS_write, fd, MESSAGE, sizeof(MESSAGE)); // syscall替换write
printf("write: ret=%d\n", ret);
// close(fd);
syscall(SYS_close, fd); // syscall替换close
}
int main() {
write_file();
write_file_syscall();
return 0;
}
syscall的arm64实现
#include <private/bionic_asm.h>
ENTRY(syscall)
/* Move syscall No. from x0 to x8 */
mov x8, x0
/* Move syscall parameters from x1 thru x6 to x0 thru x5 */
mov x0, x1
mov x1, x2
mov x2, x3
mov x3, x4
mov x4, x5
mov x5, x6
svc #0
/* check if syscall returned successfully */
cmn x0, #(MAX_ERRNO + 1)
cneg x0, x0, hi
b.hi __set_errno_internal
ret
END(syscall)
syscall的x86_64实现
看上去比arm的指令可读性更好…
#include <private/bionic_asm.h>
ENTRY(syscall)
# All arguments are passed via registers.
# (Not all will be valid, depending on the syscall.)
mov %edi, %eax
mov %rsi, %rdi
mov %rdx, %rsi
mov %rcx, %rdx
mov %r8, %r10
mov %r9, %r8
mov 8(%rsp), %r9
# Make the system call.
syscall
cmpq $-MAX_ERRNO, %rax
jb 1f
negl %eax
movl %eax, %edi
call __set_errno_internal
1:
ret
END(syscall)