在 nasm 中打印数字
printing numbers in nasm
我写了一个汇编代码来打印从 1 到 9 的数字,但是代码只打印 1,除了 1 之外没有其他元素被打印,只有一个输出是 received.It 意味着循环也不是运行。我无法弄清楚我的代码有什么问题。
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
我的 OS 是 64 位 linux。此代码是使用 nasm 和以下命令构建的:nasm -f elf64 -g -o num.o num.asm 和 ld -o num num.asm
经过一些实验重写了答案。
您的代码中有两个错误,并且效率低下。
首先,将 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 位。使用比需要更大的寄存器意味着我们所有的立即数都浪费在内存和缓存中 space。因此,我们切换到 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 位版本无关)。
我写了一个汇编代码来打印从 1 到 9 的数字,但是代码只打印 1,除了 1 之外没有其他元素被打印,只有一个输出是 received.It 意味着循环也不是运行。我无法弄清楚我的代码有什么问题。
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
我的 OS 是 64 位 linux。此代码是使用 nasm 和以下命令构建的:nasm -f elf64 -g -o num.o num.asm 和 ld -o num num.asm
经过一些实验重写了答案。
您的代码中有两个错误,并且效率低下。
首先,将 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 位。使用比需要更大的寄存器意味着我们所有的立即数都浪费在内存和缓存中 space。因此,我们切换到 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 位版本无关)。