从一个简单的汇编程序学习linux下的系统调用机制

上节从一个简单的汇编程序学习汇编程序的结构以及编译链接的过程中,打印hello world的汇编程序的详细解释为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
global _start

section .data
msg db "hello,world",0xa ;设置要输出的字符
len equ $ - msg ;$代表当前行的内存地址,$ - msg 代表msg的长度

section .text

_start: ;链接器从这里开始执行
mov eax,4 ;write 调用号
mov ebx,1 ;stdout =>1
mov ecx,msg ;msg的内容
mov edx,len ;msg的长度
int 0x80 ;write(1,msg,len)
mov eax,1 ;exit的调用号
mov ebx,0 ;exit(0)
int 0x80

在这个hello world的汇编代码中,可以看到,其中关键之处在于:
一、write(1,msg,len)exit(0)
二、int 0x80
那么,什么是调用号,以及int 0x80是什么意思呢?

系统调用-实现应用与内核的隔离

1、什么是系统调用?

这部分内容可参考【Linux编程】中的一篇文章–《Linux架构》https://mp.weixin.qq.com/s/xpCLPfotCqWZ_PDagK0ERA

这是一张Linux的架构图:


最内层为硬件、
最外层为用户常用的应用、
硬件之上为内核,内核为一段计算机程序,直接管理硬件,所有计算机操作都要通过内核传递给硬件、
内核之上为系统调用,为方便调用内核,Linux将内核功能接口制作为系统调用(system call),其类似C语言中的函数,可在程序中直接调用,也即write(1,msg,len)exit(0)。Linux系统有两百多个系统调用,其对应着不同的系统调用号、
在系统调用之上为库函数和shell,由于系统调用提供的功能非常基础,使用起来需要多个组合,故将一些常用或者特殊等功能的多个系统调用相组合就形成了库函数、
而对于shell,其为一个特殊的应用,叫命令解释器,shell通过系统调用直接调用内核。

2、如何查询系统调用号?
32位Linux系统调用号:

1
2
/usr/include/x86_64-linux-gnu/asm/unistd_32.h

64位Linux系统调用号:

1
/usr/include/x86_64-linux-gnu/asm/unistd_64.h

系统中断-操控内核的关键

1、什么是系统中断?
任何CPU在检测到从外部发来或内部产生的中断信息的时候,都需要立即处理所接受到的信息,而CPU在不再接着向下执行刚才的指令,转而去处理中断信息的过程就叫中断。
中断有内中断和外中断之分。
内中断又有以下几种情况:

1
2
3
4
除法错误
单步执行
执行into指令
执行int指令

2、int 0x80是什么?

在CPU设计之初,中断信息中包含有标识中断源的类型码。中断类型码的作用是用来定位中断处理程序的。
执行int指令,int n的n为中断类型码,其功能为引发中断过程。

int 0x80,即中断号为0x80,其是上层应用程序与内核进行交互通信的唯一接口。
0x80与系统调用(system_call)绑定,通过int 0x80即可调用内核。

以下为linux0.11内核源代码中于kernel/sched.c里面的内容:


linux0.11内核源代码

系统调用和系统中断的组合-汇编程序的实现

那么如何通过汇编程序将系统调用和系统中断结合实现目的功能呢?

以下为一个汇编程序的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
global _start
section .data
msg db "please enter something: "
msglen equ $-msg
display db "you have enter:"
displaylen equ $-display

section .bss
num resb 5

section .text
_start:
mov eax, 4 ;write(1,msg,msglen)
mov ebx,1
mov ecx,msg
mov edx,msglen
int 0x80

mov eax, 3 ;read(0,num,5)
mov ebx, 0
mov ecx, num
mov edx, 5
int 0x80

mov eax, 4 ;write(1,dispaly,displaylen)
mov ebx,1
mov ecx,display
mov edx,displaylen
int 0x80

mov eax, 4
mov ebx,1
mov ecx,num
mov edx,5
int 0x80

mov eax,1 ;exit(0)
mov ebx,0
int 0x80

汇编程序的框架:
设定入口、bss、data、text,
设计汇编指令代码
设置系统调用号和系统中断号

下期预告

程序在内存中的分布