Open arthur-zhang opened 3 years ago
计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同时运行的多个进程都需要访问这些资源,为了更好的管理这些资源进程是不允许直接操作的,所有对这些资源的访问都必须有操作系统控制。也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(System Call),系统调用和普通库函数调用非常相似,只是系统调用由操作系统核心提供,运行于内核态,而普通的函数调用由函数库或用户自己提供,运行于用户态。
在linux中系统调用是用户空间访问内核的唯一手段,除异常和陷入外,他们是内核唯一的合法入口。操作系统一般是通过中断从用户态切换到内核态。中断就是一个硬件或软件请求,要求CPU暂停当前的工作,去处理更重要的事情。
系统调用在用户空间进程和硬件设备之间添加了一个中间层。该层主要作用有三个:
strace 在linux系统中某个程序执行时进行的系统调用可以通过strace命令来查看,多线程的线程必须加上 -f 参数
- 通过int 0x80(128)号软中断触发系统调用
- 触发系统调用的时候,eax寄存器存储了系统调用的编号,而其他的几个寄存器用来传递参数的
32汇编语言 代码:helloworld.s(寄存器为 eax,ebx,ecx,edx,esi,edi,ebp)
syscall table http://shell-storm.org/shellcode/files/syscalls.html
.section .data
msg:
.ascii "Hello, World!\n"
.section .text
.globl _start
# 32位的汇编系统调用,寄存器为 eax,ebx,ecx,edx,esi,edi,ebp
_start:
# write 的第 3个参数 count: 14
movl $14, %edx
# write 的第 2 个参数 buffer: "Hello, World!\n"
movl $msg, %ecx
# write 的第 1 个参数 fd: 1
movl $1, %ebx
# write 系统调用本身的数字标识:4
movl $4, %eax
# 执行系统调用: write(fd, buffer, count)
int $0x80
# status: 0
movl $0, %ebx
# 函数: exit
movl $1, %eax
# system call: exit(status)
int $0x80
Makefile:
make:
as helloworld.s -o helloworld.o
ld helloworld.o -o helloworld
clean:
rm -rf helloworld.o
rm -rf helloworld
64位汇编语言代码:helloworld2.s 寄存器换成了 rax, rdi, rsi, rdx, r10 ,r8 ,r9
syscall table https://filippo.io/linux-syscall-table/
.section .data
msg:
.ascii "Hello, World!\n"
.section .text
.globl _start
# 64位的汇编系统调用,寄存器换成了 rax, rdi, rsi, rdx, r10 ,r8 ,r9
_start:
# write 的第 3个参数 count: 14
mov $14, %rdx
# write 的第 2 个参数 buffer: "Hello, World!\n"
mov $msg, %rsi
# write 的第 1 个参数 fd: 1
mov $1, %rdi
# write 系统调用本身的数字标识:4
mov $1, %rax
# 执行系统调用: write(fd, buffer, count) 函数编号 1
syscall
# status: 0
mov $0, %rdi
# 函数: exit 函数编号 60
mov $60, %rax
# system call: exit(status)
syscall
Makefile
.section .data
msg:
.ascii "Hello, World!\n"
.section .text
.globl _start
# 64位的汇编系统调用,寄存器换成了 rax, rdi, rsi, rdx, r10 ,r8 ,r9
_start:
# write 的第 3个参数 count: 14
mov $14, %rdx
# write 的第 2 个参数 buffer: "Hello, World!\n"
mov $msg, %rsi
# write 的第 1 个参数 fd: 1
mov $1, %rdi
# write 系统调用本身的数字标识:4
mov $1, %rax
# 执行系统调用: write(fd, buffer, count) 函数编号 1
syscall
# status: 0
mov $0, %rdi
# 函数: exit 函数编号 60
mov $60, %rax
# system call: exit(status)
syscall
1 #include <stdio.h>
2 #include <sys/mman.h>
3
4 int main() {
5
6 printf("map_private: %ld", MAP_PRIVATE);
7 char *addr = mmap(NULL, (size_t)8192 * 1024,PROT_READ , MAP_PRIVATE , -1, 0);
8 getchar();
9
10 return 0;
}
编译 gcc -g mmap_assembly_test.c -o mmap_assembly_test
gdb 调试 gdb mmap_assembly_test
b __mmap
:断点到glibc的 __mmap方法 (真正调用系统调用的的方法)并执行到这行代码处
__ptr_t
__mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
{
if (offset & ((1 << MMAP_PAGE_SHIFT) - 1))
{
__set_errno (EINVAL);
return MAP_FAILED;
}
return (__ptr_t) INLINE_SYSCALL (mmap2, 6, addr, len, prot, flags, fd,
offset >> MMAP_PAGE_SHIFT);
disassemble
显示汇编代码b *0x00007ffff7b05e28
再次断点到真正的mmap系统调用处,输出各个寄存器的值
作业:用汇编使用 int 0x80 和 syscall 分别写一个输出 hello world 的程序