2010-11-07 3 views
3

Je cherche à produire un nombre entier en utilisant un assemblage pur. J'utilise nasm sur une machine Linux 64 bits. En ce moment je cherche un moyen de sortir des entiers pour déboguer un compilateur, mais je veux utiliser le même code pour écrire un OS, ce qui est aussi la raison pour laquelle je n'utilise pas simplement printf(). Après beaucoup de recherche et de frustration que je suis venu avec ce codeManière plus efficace de générer un nombre entier dans un assemblage pur

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 

Notez que je remplacerai 0x80 appels avec le BIOS lors du portage au développement OS.

Ma question est de savoir comment optimiser, ou même enjoliver, ce code plus loin. Ma première pensée serait de remplacer pousser tous les registres individuellement, mais il n'y a pas d'instruction 64 bits pusha ...

+0

« * plus * optimal » ??? – tchrist

+0

Version Hex: http://stackoverflow.com/questions/3853730/printing-hexadecimal-digits-with-assembly –

Répondre

2

Voici quelques possibles changements à la 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 

J'ai également noté certaines limitations dans l'algorithme. Si le nombre est supérieur à 9999, le code continuera à placer des chiffres en dehors de l'espace alloué, remplaçant certaines autres données. La routine est pas entièrement réutilisable, à savoir si vous imprimez 123, puis 9 il sortira comme 129.

+0

@eZanmoto: En ce qui concerne la poussée et poping, considérez ce que le code fait. Vous mettez une valeur dans 'rax' qui n'est pas utilisée par' _printc' pas plus tard dans le code. La routine '_printc' conserve elle-même' rax', de sorte que vous n'avez pas besoin de pousser et de l'ouvrir même si cela était nécessaire plus tard. Si '_printc' est uniquement utilisé par' _printi', vous pouvez aligner son code, ce qui vous évite un appel et un ensemble de poussées et de pops. – Guffa

+0

Désolé pour mon ignorance, mais je ne suis toujours pas ... Je pousse les données dans la variable 'var' afin qu'elle puisse être passée en paramètre dans la routine' _printc'. Je sais que '_printc' est seulement utilisé par' _printi' pour le moment, mais j'ai l'intention de l'utiliser dans une bibliothèque de fonctions tout en construisant mon compilateur et mon système d'exploitation. Mais vous avez raison, en ce qui concerne ma question originale d'une manière plus efficace de sortir un entier, il vaut mieux utiliser simplement _printc en ligne, merci pour la réponse, et désolé pour l'ambiguïté dans la question. –

+0

@eZanmoto: Je vois ... vous obtenez la première partie de la chaîne, la passe en paramètre à '_printc', qui la replace là où elle était, en écrasant les caractères avec les mêmes caractères ... C'était juste inutile que je ne l'ai pas vu. :) – Guffa

Questions connexes