在nasm

时间:2017-10-01 10:24:04

标签: linux assembly nasm

我已经编写了一个汇编代码来打印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

1 个答案:

答案 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位版本的寄存器无关。)