在Linux上输出程序集中的整数

Dav*_*ard 7 x86 assembly nasm

这需要在纯汇编中完成(即没有库或调用C).

我理解问题的本质:需要将整数除以10,将一位数的余数转换为ASCII,然后输出,然后用商重复该过程.

但由于某种原因,它只是不起作用.我在x86上使用NASM.

这是我现在所拥有的(不输出任何内容,但也不会抛出任何汇编错误):

; integer to output is stored in eax
mov ecx, 10   ; for base 10

loop:
div ecx  ;EAX contains the quotient, EDX the remainder

; Do something to EDX to convert it to ASCII, not sure if this is correct
add edx, '0'

push eax    ;We'll be playing with EAX to output EDX, save EAX to the stack

mov eax, 4              ; sys_write
mov ebx, 1              ; to STDOUT
mov ecx, edx
mov edx, 1
int 0x80

pop eax  ;restore EAX

cmp eax, 0   ;If EAX is 0, our job is done
jnz loop
Run Code Online (Sandbox Code Playgroud)

有许多类似于这个的问题(即这个这个),但我在实现中迷失了.这个问题(对于DOS)也有帮助,但我仍然感到困惑.

我必须在这里遗漏一些东西.思考?

Mat*_*ery 5

还有至少两个问题.除了ecx@sarnold提到的腐败之外:

  1. div ecx将64位值edx:eax除以ecx,因此您需要确保edx在除法之前将其设置为0.

  2. write系统调用(in ecx)的第二个参数应该是指向包含要打印的字符的缓冲区的指针,而不是字符本身.

解决第二个问题的一种方法是将包含要打印的字符的寄存器推送到堆栈上,然后将堆栈指针指定especx(堆栈指针指向最近推送的项目,x86存储值little-endian,所以第一个字节是低8位).例如

push edx         ; save value on stack
mov  eax, 4      ; sys_write
mov  ebx, 1      ; to STDOUT
mov  ecx, esp    ; first byte on stack
mov  edx, 1      ; length = one byte
int  0x80
pop  edx         ; remove what we pushed (or "add esp, 4" would do just as well here;
                 ;                        we don't need the actual value again)
Run Code Online (Sandbox Code Playgroud)

这应该足以获得一些输出......

(但在那时,您可能会注意到算法的"特征",并且想要重新考虑如何存储分部产生的数字!)

  • 为数字保留一些空间(最大的无符号 32 位整数是 4294967295,因此 10 个字节就足够了),无论是在数据部分(例如使用 `resb` 指令)还是在堆栈上(只需从 `esp` 中减去,但请确保减去 4 的倍数以保持堆栈正确对齐)。然后要么将数字向前存储到缓冲区中,然后循环遍历缓冲区以反向打印每个字符;或者(更好?)将数字从缓冲区的最后一个字节开始向后存储到缓冲区中,然后您可以使用单个“write”系统调用写入所有数字。 (2认同)