NASM一次打印一个字符

Mat*_*gan 2 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                         ;
Run Code Online (Sandbox Code Playgroud)

加成

我的Makefile:

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

sandbox.o: sandbox.asm
    nasm -f elf -g -F stabs sandbox.asm -l sandbox.lst
Run Code Online (Sandbox Code Playgroud)

修改代码:

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                         ;   
Run Code Online (Sandbox Code Playgroud)

Aus*_*oke 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
Run Code Online (Sandbox Code Playgroud)

NUL可以像我一样更简单地终止你的字符串,或者你也可以$-hello在编译时获得它的长度.我还在sys_write循环中的每次迭代中设置寄存器(就像你一样),因为sys_write不保留所有寄存器.

  • 为每个角色进行系统调用是否浪费资源?难道不是要确定循环中的长度,然后一次性将缓冲区传递给sys_write吗? (2认同)