Linux系统调用详解:从原理到实践的完整指南
一说到服务,很多人首先想到的可能是服务器。假设客户端是浏览器,浏览器发送HTTP请求,服务器接收请求后解析并调用相应的handler。从本质上讲,这就是客户端触发了服务器端某个函数的执行,这时我们便说客户端请求了服务器端上的服务。
系统调用与普通的函数调用并无本质区别。普通函数调用通常调用我们编写的函数或其他库函数,而系统调用则是调用了内核中的函数。更学术一点的说法是:所谓系统调用,是指用户态程序请求操作系统提供的服务。
一提到服务,大家最先想到的通常是服务器。假设客户端是浏览器,浏览器发送HTTP请求,服务器接收到请求后进行解析,然后调用相应的handler。本质上,这是客户端触发了服务器端某个函数的运行,此时我们就可以说客户端请求了服务器端上的服务。
而系统调用与此类似,只不过用户态程序并非通过HTTP来触发操作系统中某个函数的执行,而是通过机器指令来实现的。因为用户态的App和操作系统运行在同一台计算机系统中,而客户端和服务器端则运行在不同的计算机系统里(绝大多数情况下),因此客户端只能通过网络协议HTTP与服务器进行通信。
 图片
图片
更通俗的说法是这样的:所谓系统调用,指的是用户态的某个函数调用内核中的某个函数。
接下来,我们用一段简单的hello world程序来看看系统调用,这段程序需要运行在x86_64架构下:
.section .datamsg:    .ascii "Hello, world!
"    # 字符串定义,包含换行符    len = . - msg              # 计算字符串长度(包含换行符).section .text.global _start_start:    # 调用 write(1, msg, len)    movq  $1, %rax             # syscall 1 (write)    movq  $1, %rdi             # fd = 1 (stdout)    movq  $msg, %rsi           # 字符串地址    movq  $len, %rdx           # 字符串长度    syscall    # 调用 exit(0)    movq  $60, %rax            # syscall 60 (exit)    xorq  %rdi, %rdi           # status = 0    syscall
使用以下命令编译:
$ gcc -c test.S$ ld -o test test.o
然后执行:
./testHello, world!
这段汇编代码成功地打印出了hello world。那么这段代码具体是什么意思呢?
我们来看.data这一段,这里说的是程序定义了哪些数据,而.text段则包含了程序的执行部分。我们之前提到进程的内存布局时,总是会谈到数据段和代码段,这里的数据段指的就是汇编中的.data段,代码段就是汇编中的.text段。现在你应该明白了吧。
 图片
图片
在.text段中,我们看到了一条略显奇怪的指令——syscall,这条指令到底是什么意思呢?
我们来查阅一下Intel的开发手册:
SYSCALL invokes an OS system-call handler at privilege level 0. It does so by loading RIP from the IA32_LSTAR MSR (after saving the address of the instruction following SYSCALL into RCX). (The WRMSR instruction ensures that the IA32_LSTAR MSR always contain a canonical address.)
这段话告诉我们,Intel处理器在执行syscall指令时,会在内核态调用操作系统的某个函数,即syscall-call handler。那么CPU是如何知道某个syscall-call handler在内存中的地址呢?
原来,syscall-call handler所在的内存地址存储在MSR寄存器中。那么又是谁将这个地址存储在了MSR寄存器中呢?很显然,是操作系统。接下来我们以Linux为例进行说明。
Linux内核在初始化时会将syscall-call handler,也就是Linux内核中entry_SYSCALL_64函数的地址写入MSR寄存器中:
wrmsrl(MSR_LSTAR, entry_SYSCALL_64);
其中,syscall-call handler也就是entry_SYSCALL_64定义在Linux源码中的arch/x86/entry/entry_64.S中。上述初始化MSR寄存器的代码定义在了arch/x86/kernel/cpu/common.c中。
现在我们知道了,当CPU执行syscall时会无条件跳转到MSR寄存器中保存的函数地址,也就是entry_SYSCALL_64函数。那么很显然,所有系统调用的入口都是entry_SYSCALL_64函数。那么操作系统该如何区分到底是调用的read系统调用还是write等系统调用呢?
原来,操作系统中给每种系统调用分配了一个序号,就像Linux中这样:
0common  read      sys_read1common  write     sys_write2common  open      sys_open3common  close     sys_close4common  stat      sys_newstat5common  fstat     sys_newfstat6common  lstat     sys_newlstat7common  poll      sys_poll8common  lseek     sys_lseek9common  mmap      sys_mmap...
可以看到,0号系统调用表示的是内核中的read函数,1号系统调用表示的是内核中的write函数。在进行系统调用时,会表示系统调用类别的序号写入通用寄存器中。
从上面这个表格可以看到,write系统调用的序号是1,因此在hello world程序中我们将1写入寄存器rax中:
movq  $1, %rax
这条指令表示我们将要调用第1号系统调用,也就是sys_write。hello world程序中后续三条机器指令的功能分别是:
# 写入文件描述符1movq  $1, %rdi# 保存指向字符串的指针movq  $msg, %rsi# 写入数据的大小movq  $len, %rdx
实际上,这四条机器指令都是为执行syscall进行的铺垫,即执行syscall所需要的参数。可以看到,我们进行系统调用传递参数时都是通过寄存器来完成的。
这样当CPU执行syscall指令时,就会跳转到Linux内核中的write函数,同时在执行该函数时也能知晓write函数所需要的参数是什么。
相关攻略
 
			
            team是Linux内核3 3引入的一种链路聚合驱动,它的功能和bonding类似,但是更灵活、可扩展性更强。 team是Linux内核3 3引入的一种链路聚合驱动,它的功能和bonding类似,但
 
			
            在docker容器化平台安装过程中,我们遇到一个典型问题:容器启动过程中,访问镜像仓库服务失败,重试40次依然无果。 在docker容器化平台安装过程中,我们遇到一个典型问题:容器启动过程中,访问镜
 
			
            一提到服务,大家最先想到的一定是服务器,假设客户端是浏览器,浏览器发送http请求,服务器接收到请求后进行解析然后调用相应的hander,从本质上讲就是客户端触发了服务器端的某个函数的运行,这时我们
 
			
            Linux 内核中的完全公平调度器中每个逻辑核都有一个调度队列 struct cfs_rq。每个调度队列中都是用红黑树来组织的。红黑树的节点是 struct sched_entity, sched_
 
			
            10 月 26 日消息,Fedora 项目团队宣布 Fedora Linux 43 最终版本已于 10 月 23 日通过评审,正式进入发行阶段,预计将于当地时间 10 月 28 日正式发布。若出现
热门专题
 
					
					 
					
					最新APP
 
               
               
               
               
              热门推荐
 
			
            寻找泰达币交易平台:安全便捷的选择 对于数字货币爱好者来说,泰达币(Tether, 通常以USDT表示)是一种重要的稳定币,它与美元挂钩,价
 
			
            KuCoin网页版入口一键直达 还在苦苦寻找KuCoin的网页版入口吗?别担心,今天就为你奉上KuCoin网页版入口的一键直达方式,省去你到处搜索的
 
			
            找到那扇正确的门 这事儿说起来有点意思,我上周帮一个朋友弄他那摊子事儿,他就死活找不到官网入口,最后点进了一个界面特别像但就是不对
 
			
            2025年欧易(OE)官方安卓最新版下载指南 各位数字资产爱好者,想要体验最新的欧易(OE)交易平台吗? 随着2025年的到来,欧易(OE)也进行了更

