调用"系统调用函数write"的两种实现

我们知道调用“系统调用”有两种方式。
( 1) 将系统调用指令封装为 c库函数,通过库函数进行系统调用,操作简单。
(2)不依赖任何库函数,直接通过汇编指令 int与操作系统通信。

我们平常写的C语言用的就是第一种系统调用,通过函数调用write函数,我们下面用汇编语言来重写一下,利用我们定义的simu_write函数来更好的探究write函数的运作机理

syscall.S

section .data
str_c_lib: db "c library says: hello world",0xa
str_c_lib_len equ $-str_c_lib
section .text
global _start
_start:

;;;模拟c语言;;

	push str_c_lib_len
	push str_c_lib
	push 1     ;是push到标准输出,也是一个参数

	call simu_write
	add esp,12
	
	;;;退出程序,不然会出现段错误;;
	mov eax,1
	int 0x80
	
simu_write:
	push ebp
	mov ebp,esp
	mov eax,4
	mov ebx,[ebp+8]
	mov ecx,[ebp+12]
	mov edx,[ebp+16]

	int 0x80
	pop ebp
	ret

我们简单的来解释一下这一种方法:其先通过函数调用约定,从右向左往栈中压入参数str_c_lib_len,str_c_lib,1,(write(1,str_c_lib,str_c_lib_len))然后调用simu_write函数

在我们的simu_write函数中先保存旧的ebp,然后调用第4号子功能:write系统调用,将其存放在eax中,然后分别放入参数。这里也就是我们所说的第二种系统调用了,不过我们先不在这里说,在下一个程序中说。

完成这些后,通过

mov eax,1
int 0x80

退出程序。其中第1号子功能是exit
int 0x80 发起中断,通知 Linux完成请求的功能,即完成退出请求

好,让我们来看第二种方法,绕过库函数,直接与OS通信

预备知识:
系统调用输入参数的传递方式:
当输入的参数小于等于 5 个时, Linux 用寄存器传递参数。当参数个数大于 5 个时,把参数按照顺序 放入连续的内存区域,并将该区域的首地址放到 ebx 寄存器。这里我们只演示参数小于等于 5 个的情况。 eax寄存器用来存储子功能号(寄存器 eip、 ebp、 esp是不能使用的)。 5个参数存放在以下寄存器中,
传送参数的顺序如下。
(1) ebx存储第 1个参数。
(2) ecx存储第 2个参数。
(3) edx存储第 3个参数。
(4) esi存储第 4个参数。
(5) edi存储第 5个参数。

程序如下:

section .data

str_syscall: db "syscall says: hello world!",0xa
str_syscall_len equ $-str_syscall

section .text
global _start
_start:

	mov eax,4
	mov ebx,1
	mov ecx,str_syscall
	mov edx,str_syscall_len
	
	int 0x80

	mov eax,1
	int 0x80

在这里插入图片描述

是不是发现不用库函数,直接进行系统调用很简单呢~嘻嘻,我们今天就到此为止了

猜你喜欢

转载自blog.csdn.net/qq_37414405/article/details/84942067
今日推荐