NASM一次打印一个字符

时间:2011-12-08 05:17:51

标签: linux assembly nasm

为什么这个程序没有打印到屏幕上,我在INT 80命令上遗漏了什么?

  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                         ;

ADDITION

我的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                         ;   

2 个答案:

答案 0 :(得分: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不会保留所有寄存器。

答案 1 :(得分:0)

我不知道你是如何编写代码的,但是由于几个很好的理由,它并没有在这里聚集。

您不能将loop用作标签名称,因为该名称是为loop指令保留的。

你的第20行指令mov ecx, byte [hello + ebx]无法汇编,因为源和目标操作数'大小不匹配(字节与双字)。可能的变化:

mov cl,byte [hello + ebx]
mov ecx,dword [hello + ebx]
movzx ecx,byte [hello + ebx]

以上不是您的实际代码吗?