2011-12-08 75 views
2

該程序如何不打印到屏幕上,我在INT 80命令中丟失了什麼?NASM一次打印一個字符

section .bss 

    section .data 
     hello: db "Hello World",0xa  ;10 is EOL 

    section .text 
     global _start 

    _start: 

     mov ecx, 0;      ; int i = 0; 
    loop: 
     mov dl, byte [hello + ecx]  ; while(data[i] != EOF) { 
     cmp dl, 0xa      ; 
     je exit       ; 
     mov ebx, ecx      ; store conetents of i (ecx) 

     ; Print single character 
     mov eax, 4      ; set sys_write syscall 
     mov ecx, byte [hello + ebx]  ; ... 
     mov edx, 1      ; move one byte at a time 
     int 0x80       ; 

     inc ebx       ; i++ 
     mov ecx, ebx      ; move ebx back to ecx 
     jmp loop       ; 

    exit: 
     mov eax, 0x01     ; 0x01 = syscall for exit 
     int 0x80       ; 

加成

我的Makefile:

sandbox: sandbox.o 
    ld -o sandbox sandbox.o 

sandbox.o: sandbox.asm 
    nasm -f elf -g -F stabs sandbox.asm -l sandbox.lst 

修改代碼:

section .bss 

section .data 
    hello: db "Hello World",0xa  ;10 is EOL 

section .text 
    global _start 

_start: 

    mov ecx, 0;      ; int i = 0; 
while: 
    mov dl, byte [hello + ecx]  ; while(data[i] != EOF) { 
    cmp dl, 0xa      ; 
    je exit       ; 
    mov ebx, ecx      ; store conetents of i (ecx) 

    ; Print single character 
    mov eax, 4      ; set sys_write syscall 
    mov cl, byte [hello + ebx]  ; ... 
    mov edx, 1      ; move one byte at a time 
    int 0x80       ; 

    inc ebx       ; i++ 
    mov ecx, ebx      ; move ebx back to ecx 
    jmp while      ; 

exit:  
    mov eax, 0x01     ; 0x01 = syscall for exit 
    int 0x80       ; 
+0

請閱讀我對編輯中提到的額外字符的評論。 – AusCBloke

回答

5

一個它不打印的原因是因爲ebx應該保存值1指定stdin,另一種是因爲sys_write需要一個指針(你的字符串的地址)作爲參數,而不是實際的字符值。

不管怎麼說,讓我告訴你構建你的程序的一個簡單的方法:

section .data 

    SYS_EXIT equ 1 
    SYS_WRITE equ 4 
    STDOUT equ 1 
    TRAP  equ 0x80 
    NUL  equ 0 

    hello: db "Hello World",0xA,NUL ; 0xA is linefeed, terminate with NUL 

section .text 
    global _start 

_start: 
    nop      ; for good old gdb 
    mov ecx, hello   ; ecx is the char* to be passed to sys_write 

read: 
    cmp byte[ecx], NUL  ; NUL indicates the end of the string 
    je exit     ; if reached the NUL terminator, exit 

    ; setup the registers for a sys_write call 
    mov eax, SYS_WRITE  ; syscall number for sys_write 
    mov ebx, STDOUT   ; print to stdout 
    mov edx, 1    ; write 1 char at a time 
    int TRAP;    ; execute the syscall 

    inc ecx     ; increment the pointer to the next char 
    jmp read    ; loop back to read 

exit:  
mov eax, SYS_EXIT  ; load the syscall number for sys_exit 
mov ebx, 0    ; return a code of 0 
int TRAP    ; execute the syscall 

它可以是簡單的NUL終止您的字符串和我一樣,或者你也可以做$-hello得到它是在編譯的長度時間。因爲sys_write不保存所有的寄存器,所以我在循環中每次迭代時都將寄存器設置爲sys_write(與您一樣)。

+0

@MthethewHoggan:打印的附加字符是故意的。在字符串的末尾打印一個新行是有意義的,值爲0(NUL)表示字​​符串的結尾。如果您不想要額外的值,請從'hello'結尾刪除'0xA',但不要使用值'0xA'作爲字符串終止值。 – AusCBloke

+1

爲每個角色製作系統調用不是浪費嗎?難道不想確定循環中的長度,然後一次將緩衝區傳遞給sys_write? – Thilo

0

我不知道你是如何得到你的代碼來組裝的,但是它並沒有在這裏聚集在一起,這有兩個很好的理由。

您不能使用loop作爲標籤名稱,因爲該名稱是爲loop指令保留的。

您的行20的指令mov ecx, byte [hello + ebx]未組裝,因爲源操作數和目標操作數的大小不匹配(字節與雙字)。可能的變化:

MOV CL,字節[你好+ EBX]
MOV ECX,DWORD [你好+ EBX]
MOVZX ECX,字節[你好+ EBX]

當時上述不實際你有什麼代碼?

+0

我在FC 15上,我粘貼了上面的make文件,我做了更改,但仍未收到在終端打印的任何內容。 –

+1

我假設「sys_write()」需要數據的地址,而不是實際的數據(例如嘗試「lea ecx,[hello + ebx]」)。 – Brendan