匯編語(yǔ)言簡(jiǎn)易教程(12):系統(tǒng)服務(wù)

匯編語(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)看原文吧.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容