以更高效的方式在纯汇编中输出整数 [英] More efficient way to output an integer in pure assembly

查看:266
本文介绍了以更高效的方式在纯汇编中输出整数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用纯汇编输出一个整数。我在64位linux机器上使用nasm。目前我正在寻找一种方式来输出整数来调试编译器,但我想使用相同的代码写一个操作系统,这也是为什么不简单地使用 printf )。经过大量的搜索和挫折,我想出了这段代码。

  SECTION .data 
var:db ,0

SECTION .text
global main
global _printc
global _printi

main:
mov rax,90
push rax
call _printi

xor rbx,rbx
mov rax,1
int 0x80

_printi:
pushf
push rax
push rbx
push rcx
push rdx

mov rax,[rsp + 48]
mov rcx,4
.start:
dec rcx
xor rdx,rdx
mov rbx,10
div rbx
add rdx,48
mov [var + rcx],dl
cmp rax,0
jne .start

mov rax,[var]
push rax
call _printc
pop rax

pop rdx
pop rcx
pop rbx
pop rax
popf
ret

_printc:
push rax
push rbx
push rcx
push rdx

mov rax,[rsp + 40]
mov [var]
mov rax,4
mov rbx,1
mov rcx,var
mov rdx,4
int 0x80

pop rdx
pop rcx
pop rbx
pop rax
ret

注意,当移植到操作系统开发时,我将用BIOS调用替换0x80调用。



我的问题是如何优化,甚至美化这个代码。我的第一个想法是替换推送所有的寄存器,但没有任何64位 pusha 指令...

  _printi:


pushf
push rax
push rbx
push rcx
push rdx

mov rax,[rsp + 48]
mov rcx,4
mov rbx,10; - 在循环外移动
.start:
dec rcx
xor rdx,rdx
div rbx
add rdx,48
mov [var + rcx ],dl
cmp rax,0
jne .start

; mov rax,[var] - 未使用
; push rax - 未使用
call _printc
; pop rax - 未使用

pop rdx
pop rcx
pop rbx
pop rax
popf
ret

我还注意到了算法中的一些限制。如果数字大于9999,代码将继续将数字放在分配的空间之外,覆盖一些其他数据。该例程不能完全重复使用,即如果您打印123,则9将显示为129。


I'm looking to output an integer using pure assembly. I'm using nasm on a 64-bit linux machine. At the moment I'm looking for a way to output integers to debug a compiler, but I want to use the same code for writing an OS, which is also the reason I don't simply use printf(). After much searching and frustration I have come up with this code

    SECTION .data
var:    db  "      ",10,0

    SECTION .text
global main
global _printc
global _printi

main:
    mov rax, 90
    push    rax
    call    _printi

    xor rbx, rbx
    mov rax, 1
    int 0x80

_printi:
    pushf
    push    rax
    push    rbx
    push    rcx
    push    rdx

    mov rax, [rsp+48]
    mov rcx, 4
.start:
    dec rcx
    xor rdx, rdx
    mov rbx, 10
    div rbx
    add rdx, 48
    mov [var+rcx], dl
    cmp rax, 0
    jne .start

    mov rax, [var]
    push    rax
    call    _printc
    pop rax

    pop rdx
    pop rcx
    pop rbx
    pop rax
    popf
    ret

_printc:
    push    rax
    push    rbx
    push    rcx
    push    rdx

    mov rax, [rsp+40]
    mov [var], rax
    mov rax, 4
    mov rbx, 1
    mov rcx, var
    mov rdx, 4
    int 0x80

    pop rdx
    pop rcx
    pop rbx
    pop rax
    ret

Note that I'll be replacing 0x80 calls with BIOS calls when porting to OS development.

My question is how to optimize, or even prettify, this code further. My first thought would be to replace pushing all the registers individually, but there isn't any 64-bit pusha instruction...

解决方案

Here are some possible changes to the routine:

_printi:
    pushf
    push    rax
    push    rbx
    push    rcx
    push    rdx

    mov rax, [rsp+48]
    mov rcx, 4
    mov rbx, 10 ; --moved outside the loop
.start:
    dec rcx
    xor rdx, rdx
    div rbx
    add rdx, 48
    mov [var+rcx], dl
    cmp rax, 0
    jne .start

    ; mov rax, [var] -- not used
    ; push    rax -- not used
    call    _printc
    ; pop rax -- not used

    pop rdx
    pop rcx
    pop rbx
    pop rax
    popf
    ret

I also noted some limitations in the algorithm. If the number is larger than 9999, the code will continue to put digits outside of the allocated space, overwriting some other data. The routine is not fully reusable, i.e. if you print 123, then 9 it will come out as 129.

这篇关于以更高效的方式在纯汇编中输出整数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆