匯編語(yǔ)言簡(jiǎn)易教程(12):系統(tǒng)服務(wù)
應(yīng)用程序必須使用操作系統(tǒng)執(zhí)行許多操作。 此類操作包括控制臺(tái)輸出、鍵盤輸入、文件服務(wù)(打開(kāi)、讀取、寫入、關(guān)閉等)、獲取時(shí)間或日期、請(qǐng)求內(nèi)存分配等
訪問(wèn)系統(tǒng)服務(wù)是應(yīng)用程序請(qǐng)求操作系統(tǒng)執(zhí)行某些特定操作(代表進(jìn)程)的方式。 更具體地說(shuō),系統(tǒng)調(diào)用是執(zhí)行進(jìn)程和操作系統(tǒng)之間的接口
本節(jié)介紹如何使用一些基本的系統(tǒng)服務(wù)調(diào)用。
系統(tǒng)調(diào)用
系統(tǒng)服務(wù)調(diào)用在邏輯上類似于調(diào)用函數(shù),其中函數(shù)代碼位于操作系統(tǒng)中。 該功能可能需要權(quán)限才能操作,這就是為什么必須將控制權(quán)轉(zhuǎn)移到操作系統(tǒng)的原因
調(diào)用系統(tǒng)服務(wù)時(shí),參數(shù)放置在標(biāo)準(zhǔn)參數(shù)寄存器中。系統(tǒng)服務(wù)通常不使用基于堆棧的參數(shù)。 這將系統(tǒng)服務(wù)的參數(shù)限制為六 (6) 個(gè), 一般來(lái)說(shuō)這不是一個(gè)嚴(yán)重的限制.
如果需要任何參數(shù),則系統(tǒng)服務(wù)的參數(shù)將放在 RDI、RSI、RDX、R10、R8 和 R9 寄存器中(按此順序)。 下表顯示了與標(biāo)準(zhǔn)調(diào)用約定一致的參數(shù)位置
設(shè)置調(diào)用代碼和任何參數(shù)后,將執(zhí)行 syscall 指令。 系統(tǒng)調(diào)用指令將暫停當(dāng)前進(jìn)程并將控制權(quán)轉(zhuǎn)移到操作系統(tǒng),操作系統(tǒng)將嘗試執(zhí)行 rax 寄存器中指定的服務(wù)。 當(dāng)系統(tǒng)服務(wù)返回時(shí),該過(guò)程將恢復(fù).
控制臺(tái)輸出
將字符輸出到控制臺(tái)的系統(tǒng)服務(wù)是系統(tǒng)寫入 (SYS_write)。與高級(jí)語(yǔ)言一樣,字符被寫入標(biāo)準(zhǔn)輸出(STDOUT),即控制臺(tái)。 STDOUT 是控制臺(tái)的默認(rèn)文件描述符。 filedescriptor 已打開(kāi),可用于程序(匯編語(yǔ)言和高級(jí)語(yǔ)言)
參考代碼
這部分的代碼可以參考注釋來(lái)閱讀, 基本上沒(méi)有什么難度
section .data LF equ 10 NULL equ 0 True equ 1 FALSE equ 0 EXIT_SUCCESS equ 0 STDIN equ 0 STDOUT equ 1 STDERR equ 2 SYS_read equ 0 SYS_write equ 1 SYS_open equ 2 SYS_close equ 3 SYS_fork equ 57 SYS_exit equ 60 SYS_create equ 85 SYS_time equ 201 message1 db "hello world.", LF, NULL message2 db "Enter Answer: ", NULL newLine db LF, NULL section .text global _start _start: mov rdi, message1 ; 設(shè)置string頭地址, 使用rdi存儲(chǔ) call printString ; 調(diào)用printString 函數(shù) exampleDone: mov rax, SYS_exit mov rdi, EXIT_SUCCESS syscall global printString printString: push rbx ;因?yàn)槭褂玫搅藃bx的地址, 所以需要壓棧, 為后續(xù)做準(zhǔn)備 mov rbx, rdi ;復(fù)制rdi到rbx mov rdx, 0 ;將rdx設(shè)為0 strCountLoop: cmp byte [rbx], NULL je strCountDone ; 如果字符為NULL,表示結(jié)束, 則直接跳轉(zhuǎn)到結(jié)果. inc rdx ; 增加rdx, 表示的字符串長(zhǎng)度 inc rbx ; 增加rbx, 這里表示的是string的位置 jmp strCountLoop ; 繼續(xù)統(tǒng)計(jì) strCountDone: cmp rdx, 0 ; 如果rdx == 0, 表示字符串長(zhǎng)度為0, 不需要系統(tǒng)調(diào)用 je prtDone ; 輸出結(jié)束 mov rax, SYS_write ; 調(diào)用sys_write mov rsi, rdi mov rdi, STDOUT syscall prtDone: pop rbx ret控制臺(tái)輸入
將字符輸出到控制臺(tái)的系統(tǒng)服務(wù)是系統(tǒng)寫入 (SYS_write)。與高級(jí)語(yǔ)言一樣,字符被寫入標(biāo)準(zhǔn)輸出(STDOUT),即控制臺(tái)。 STDOUT 是控制臺(tái)的默認(rèn)文件描述符。 filedescriptor 已打開(kāi),可用于程序(匯編語(yǔ)言和高級(jí)語(yǔ)言)。
示例代碼
section .data LF equ 10 NULL equ 0 True equ 1 FALSE equ 0 EXIT_SUCCESS equ 0 STDIN equ 0 STDOUT equ 1 STDERR equ 2 SYS_read equ 0 SYS_write equ 1 SYS_open equ 2 SYS_close equ 3 SYS_fork equ 57 SYS_exit equ 60 SYS_create equ 85 SYS_time equ 201 STRLEN equ 50 pmpt db "Enter Text: ", NULL newLine db LF, NULL section .bss chr resb 1 inLine resb STRLEN+2 section .text global _start _start: mov rdi, pmpt call printString ; 打印提示內(nèi)容 mov rbx, inLine ; 將buffer地址計(jì)入rbx mov r12, 0 ; 計(jì)數(shù)r12 readCharacters: mov rax, SYS_read ; 調(diào)用sys_read mov rdi, STDIN lea rsi, byte [chr]; 讀取的結(jié)果寫入chr mov rdx, 1 ; 每次只讀取一個(gè)字符 syscall mov al, byte [chr] ; 將chr復(fù)制到 A 寄存器 cmp al, LF ; 判斷是否是 \n, 如果是則直接結(jié)束. je readDone inc r12 ; 增加字符統(tǒng)計(jì)數(shù) cmp r12, STRLEN ; 如果超過(guò)最大長(zhǎng)度, 則直接結(jié)束, 反之繼續(xù) jae readCharacters mov byte [rbx], al inc rbx ; 將結(jié)果寫入 inLine, 同時(shí) ptr = ptr + 1 jmp readCharacters readDone: mov byte [rbx], NULL mov rdi, inLine call printString exampleDone: mov rax, SYS_exit mov rdi, EXIT_SUCCESS syscall global printString printString: push rbx; -----; Count characters in string. mov rbx, rdi mov rdx, 0 strCountLoop: cmp byte [rbx], NULL je strCountDone inc rdx inc rbx jmp strCountLoop strCountDone: cmp rdx, 0 je prtDone mov rax, SYS_write mov rsi, rdi mov rdi, STDOUT syscall prtDone: pop rbx ret文件打開(kāi)操作符
為了進(jìn)行文件操作,如讀取和寫入,必須首先打開(kāi)文件。有兩種文件打開(kāi)操作,打開(kāi)和打開(kāi)/創(chuàng)建。這兩種打開(kāi)操作在以下章節(jié)中有所解釋。文件打開(kāi)后,為了執(zhí)行文件讀取或?qū)懭氩僮鳎僮飨到y(tǒng)需要關(guān)于文件的詳細(xì)信息,包括完整狀態(tài)和當(dāng)前的讀/寫位置。這是必要的,以確保讀取或?qū)懭氩僮髂軌驈纳弦淮谓Y(jié)束的地方繼續(xù)。
如果文件打開(kāi)操作失敗,將返回一個(gè)錯(cuò)誤代碼。如果文件打開(kāi)操作成功,將返回一個(gè)文件描述符。這適用于高級(jí)語(yǔ)言和匯編代碼。
操作系統(tǒng)使用文件描述符來(lái)訪問(wèn)關(guān)于文件的完整信息。關(guān)于一個(gè)打開(kāi)文件的完整信息集合存儲(chǔ)在一個(gè)名為文件控制塊(FCB)的操作系統(tǒng)數(shù)據(jù)結(jié)構(gòu)中。本質(zhì)上,文件描述符被操作系統(tǒng)用來(lái)引用正確的FCB。程序員的責(zé)任是確保文件描述符被存儲(chǔ)和正確使用。
打開(kāi)文件
文件打開(kāi)操作要求文件必須存在才能被打開(kāi)。如果文件不存在,那就是一個(gè)錯(cuò)誤。文件打開(kāi)操作還需要參數(shù)標(biāo)志來(lái)指定訪問(wèn)模式。訪問(wèn)模式必須包括以下之一:
- 只讀訪問(wèn) → O_RDONLY
- 只寫訪問(wèn) → O_WRONLY
- 讀/寫訪問(wèn) → O_RDWR
必須使用這些訪問(wèn)模式之一。通過(guò)與這些模式中的一個(gè)進(jìn)行邏輯或(OR)操作,可以使用額外的訪問(wèn)模式。這可能包括如追加模式(本文未提及)。參見(jiàn)附錄C,系統(tǒng)服務(wù)以獲取關(guān)于文件訪問(wèn)模式的附加信息。
文件打開(kāi)系統(tǒng)服務(wù)的參數(shù)如下:
- 寄存器 SYS_open
- rax 調(diào)用代碼 = SYS_open (2)
- rdi 空終止文件名字符串的地址
- rsi 文件訪問(wèn)模式標(biāo)志
假設(shè)以下聲明:
- SYS_open equ 2;文件打開(kāi)
- O_RDONLY equ 000000q;只讀
- O_WRONLY equ 000001q;只寫
- O_RDWR equ 000002q;讀寫
應(yīng)當(dāng)注意,常量是以八進(jìn)制或基數(shù)8定義的(如q后綴所指定)。這與Linux文件權(quán)限有時(shí)指定的方式相匹配。
系統(tǒng)調(diào)用之后,rax寄存器將包含返回值。如果文件打開(kāi)操作失敗,rax將包含一個(gè)負(fù)值(即<0)。具體的負(fù)值提供了遇到錯(cuò)誤類型的指示。參見(jiàn)附錄C,系統(tǒng)服務(wù)以獲取關(guān)于錯(cuò)誤代碼的附加信息。典型的錯(cuò)誤可能包括無(wú)效的文件描述符、文件未找到或文件權(quán)限錯(cuò)誤。
如果文件打開(kāi)操作成功,rax包含文件描述符。文件描述符將需要用于進(jìn)一步的文件操作,并應(yīng)當(dāng)被保存。參見(jiàn)關(guān)于示例文件讀取的部分以獲取一個(gè)完整的打開(kāi)文件的例子。
文件打開(kāi)/創(chuàng)建
文件打開(kāi)/創(chuàng)建操作將創(chuàng)建一個(gè)文件。如果文件不存在,將創(chuàng)建一個(gè)新文件。如果文件已經(jīng)存在,它將被擦除并創(chuàng)建一個(gè)新文件。因此,文件以前的內(nèi)容將丟失。
必須指定一個(gè)文件訪問(wèn)模式。由于文件正在被創(chuàng)建,訪問(wèn)模式必須包括在創(chuàng)建文件時(shí)將設(shè)置的文件權(quán)限。這將包括為用戶、組或全世界指定讀、寫和/或執(zhí)行權(quán)限,這是Linux文件權(quán)限的典型做法。本例中僅涉及到的權(quán)限是對(duì)文件用戶或所有者的權(quán)限。因此,其他用戶(即使用其他帳戶的用戶)將無(wú)法訪問(wèn)我們程序創(chuàng)建的文件。參見(jiàn)附錄C,系統(tǒng)服務(wù)以獲取關(guān)于文件訪問(wèn)模式的附加信息。
文件打開(kāi)/創(chuàng)建系統(tǒng)服務(wù)的參數(shù)如下:
- 寄存器 SYS_create
- rax 調(diào)用代碼 = SYS_create (85)
- rdi 空終止文件名字符串的地址
- rsi 文件訪問(wèn)模式標(biāo)志
假設(shè)以下聲明:
- SYS_create qu 85;文件打開(kāi)
- O_CREAT equ 0x40
- O_TRUNC equ 0x200
- O_APPEND equ 0x400
- S_IRUSR equ 00400q;所有者,讀權(quán)限
- S_IWUSR equ 00200q;所有者,寫權(quán)限
- S_IXUSR equ 00100q;所有者,執(zhí)行權(quán)限
文件狀態(tài)標(biāo)志“S_IRUSR | S_IWUSR”將允許同時(shí)讀寫,這是典型的。"|" 是邏輯或(OR)操作,因此組合了選擇。
如果文件打開(kāi)/創(chuàng)建操作沒(méi)有成功,rax寄存器中將返回一個(gè)負(fù)值。如果文件打開(kāi)/創(chuàng)建操作成功,將返回一個(gè)文件描述符。文件描述符用于所有后續(xù)的文件操作。參見(jiàn)關(guān)于示例文件寫入的部分以獲取一個(gè)完整的文件打開(kāi)/創(chuàng)建的示例。
文件讀取
這個(gè)和IO Read是幾乎一致的, 不再重復(fù)了
文件寫入
示例
示例的內(nèi)容太長(zhǎng)了, 請(qǐng)看原文吧.