我已经编写了一个汇编代码来打印1到9的数字,但是代码只打印1,并且没有打印出1以外的其他元素,只接收到一个输出。这意味着循环也没有运行。我无法弄清楚我的代码有什么问题。
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov cx,0
incre:
inc cx
add cx,30h
mov [outbuff],cx
cmp cx,39h
jg done
cmp cx,39h
jl print
print:
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,lena
syscall
jmp incre
done:
mov rax,60 ;sys_exit
mov rdi,0
syscall
我的操作系统是64位Linux。此代码使用nasm使用以下命令构建:nasm -f elf64 -g -o num.o num.asm和ld -o num num.asm
答案 0 :(得分:0)
经过一些实验后重写了答案。
您的代码中存在两个错误,以及一些效率低下的问题。
首先,在数字上加上0x30(将数字从1转为ASCII 1)。但是,您在循环内执行此增量操作。因此,您的第一次迭代cx
为0x31,第二次为0x62(“b”),第三次为0x93(无效的UTf-8序列)等。
只需将cx
初始化为0x30并从循环中删除添加。
但还有另一个问题。系统调用期间RCX被破坏了。用cx
替换r12
会使程序生效。
除此之外,您将缓冲区的长度传递给write
,但它只有一个字符。到目前为止的计划:
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov r12,30h
incre:
inc r12
mov [outbuff],r12
cmp r12,39h
jg done
cmp r12,39h
jl print
print:
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,1
syscall
jmp incre
done:
mov rax,60 ;sys_exit
mov rdi,0
syscall
即使是现在,代码效率也非常低。在相同条件下有两个比较,其中一个分支到下一个指令。
此外,如果将中断条件移动到代码末尾,则代码会更快更小。此外,cx
是16位寄存器。 r12
是64位寄存器。我们实际上只需要8位。使用比所需更大的寄存器意味着我们所有的immediates都会浪费内存和缓存空间。我们因此切换到r12
的8位变体。完成这些更改后,我们得到:
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov r12b,30h
incre:
inc r12b
mov [outbuff],r12b
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,1
syscall
cmp r12b,39h
jl incre
mov rax,60 ;sys_exit
mov rdi,0
syscall
你还可以做更多的事情。例如,您调用write
系统调用9次,而不是填充缓冲区然后调用一次(尽管您已经分配了1024字节缓冲区)。用零(xor r12, r12
)初始化r12然后加上0x30可能会更快。 (与8位版本的寄存器无关。)