2013-09-11 66 views
2

我必須在程序集中定義一個函數,它允許我遍歷一串聲明的字節並使用BIOS中斷打印它們。我在16位真實模式。這是一本關於從教科書中編寫一個小引導程序的練習,但它似乎只是一個草稿,並且缺少一些東西。 我一直在考慮下面的代碼:使用沒有預定義的函數在程序集中打印字符串

org 0x7c00 

mov bx, HELLO_MSG 
call print_string 

mov bx, GOODBYE_MSG 
call print_string 

jmp $    ;hang so we can see the message 

%include "print_string.asm" 

HELLO_MSG: 
    db 'Hello, World!', 0 

GOODBYE_MSG: 
    db 'Goodbye!', 0 

times 510 - ($ - $$) db 0 
dw 0xaa55 

我print_string.asm看起來是這樣的:

print_string: 
    pusha 
    mov ah, 0x0e 

    loop: 
     mov al, bl 
     cmp al, 0 
     je return 
     int 0x10 
     inc bx 
     jmp loop 

    return: 
     popa 
     ret 

我有我在做什麼了,但書中沒有解釋如何遍歷一些東西。我知道如何在C中做到這一點,但這是我第一次使用程序集來調試C代碼以外的東西。當我通過模擬器啓動時會發生什麼,它會打印出幾行亂碼,最後掛在那裏讓我看到我的失敗。哈哈哈。

回答

2

好吧,它看起來像在調用函數之前將字符串的地址加載到BX寄存器中。

實際函數看起來像它試圖循環遍歷字符串,使用BX作爲指針並遞增它(inc bx),直到它在字符串末尾碰到ASCII NUL(cmp al,0; je return )...

...但有些事情是錯的。 「mov al,bl」指令看起來不正確,因爲它會將地址的低8位移到al中,以便與ASCII NUL進行比較,這沒有多大意義。我認爲它應該更像「mov al,[bx]」;即將BX地址引用的字節移動到AL寄存器 - 儘管我已經使用了彙編很長一段時間,所以我可能沒有正確的語法。

由於該錯誤,10h中斷也會根據字符串的地址而不是字符串的內容打印隨機字符。這將解釋你看到的亂碼。

+0

感謝您的幫助。對於不同的尋址模式是如何工作的,我仍然困惑不解。 'op寄存器'似乎直接使用該值,'op [register]'表示「使用該寄存器中的數字作爲地址去」,但我並不完全清楚它。 – Hugo

+0

@Steven,巧合的是,我也使用與OP所使用的相同的書。我也被困在同一件事上,並且之前嘗試過這樣的語法: - 'mov al,[bx]'。但NASM在該行上發出編譯錯誤(無效的有效地址)。 –

1

我認爲問題是你不能指望int保存你的任何寄存器,所以你需要保護它們。另外,史蒂文指出加載你的字符串地址:

; Print the string whose address is in `bx`, segment `ds` 
; String is zero terminated 
; 
print_string: 
    pusha 

loop: 
    mov al, [bx] ; load what `bx` points to 
    cmp al, 0 
    je return 
    push bx   ; save bx 
    mov ah, 0x0e ; load this every time through the loop 
         ; you don't know if `int` preserves it 
    int 0x10 
    pop bx   ; restore bx 
    inc bx 
    jmp loop 

return: 
    popa 
    ret 
+0

我使用的中斷顯然保留了寄存器,因爲Steven的建議奏效。 int 0x10僅查看ax寄存器。但是,謝謝。 – Hugo

+0

@Hugo,好的。我仍然認爲這是一種好的做法,除非文件明確說明了有關注冊保存的問題,否則將保存您關心的任何註冊表。在處理一個不同的int調用時,我已經回覆了別人的ASM,並且在這種情況下注冊保存的確是問題。你在'print_string'例程中努力使用'pusha'和'popa'這一事實也可能爲你節省了這一點。 – lurker

相關問題