1. 程式人生 > >呼叫"系統呼叫函式write"的兩種實現

呼叫"系統呼叫函式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

在這裡插入圖片描述

是不是發現不用庫函式,直接進行系統呼叫很簡單呢~嘻嘻,我們今天就到此為止了