使用x86 32位Linux sys_write(NASM)打印整数

提问

我是这个论坛的新手.
我对高级语言有一点经验(真的很少).差不多一个月前,我认为在Linux上选择nasm(IA-32)之后,看看汇编是如何工作的,这是一个好主意我开始从一个教程中学习.

现在,在结束之后,我尝试编写一个简单的程序,让计算机打印100个数字的列表(1 2 4 8 16 …),但我甚至无法做到正确.
我得到这个输出:

1PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP(continues)...

该计划是这样的:

section .text
    global main
main:
    mov word [num], '1'
    mov ecx, 100
doubl:
    push ecx ; to push the loop counter

    mov eax, 4
    mov ebx, 1
    mov ecx, num
    mov edx, 1
    int 0x80

    sub ecx, 30h
    add ecx, ecx   ; shl ecx, 1
    add ecx, 30h
    mov [num], ecx   ; deleting this line I get  11111111111111111...

    pop ecx  ; to pop the loop counter
    loop doubl
exit:
    mov eax, 1
    int 0x80    
section .bss
num resw 2

看起来错误是在数字加倍的部分或将数据存储在变量’num’中的部分,但我不明白它为什么会发生以及如何解决它.

那么有人可以解释我何时准确使用方括号?有规则还是什么?本教程将其称为“有效地址”,当我想要移动(或做某事)变量的内容而不是将其放到变量的地址时,看起来我必须使用括号.然而我对它很困惑.我看到它用于:

mov ebx, count
inc word [ebx]
mov esi, value
dec byte [esi]

但是,显而易见的是,人们想要增加寄存器的内容(因为它没有地址(或者它有吗?)?

最佳答案

您的数字将迅速增长,而不仅仅是一位数.您应该做的是使用num而不是字符的整数,然后将该整数转换为可以使用sys_write打印的字符串.

这是进行转换的一种方法:重复除以10,首先得到最低位数作为余数:

; Input:
; eax = integer value to convert
; esi = pointer to buffer to store the string in (must have room for at least 10 bytes)
; Output:
; eax = pointer to the first character of the generated string
; ecx = length of the generated string
int_to_string:
  add esi,9
  mov byte [esi],0    ; String terminator

  mov ebx,10
.next_digit:
  xor edx,edx         ; Clear edx prior to dividing edx:eax by ebx
  div ebx             ; eax /= 10
  add dl,'0'          ; Convert the remainder to ASCII 
  dec esi             ; store characters in reverse order
  mov [esi],dl
  test eax,eax            
  jnz .next_digit     ; Repeat until eax==0

  ; return a pointer to the first digit (not necessarily the start of the provided buffer)
  mov eax,esi
  ret

您可以这样使用:

    mov    dword [num],1
    ...
    mov    eax,[num]       ; function args using our own private calling convention
    mov    esi,buffer
    call   int_to_string
; eax now holds the address that you pass to sys_write
    ...

section .bss
    num    resd 1
    buffer resb 10

您的倍数可以简化为shl dword [num],1.或者更好的是,它在某个时刻加倍,而它仍然在添加eax,eax的寄存器中.