Question

Je suis en train d'apprendre MSNA Assemblée, mais il me semble être aux prises avec ce qui semble simplement dans des langages de haut niveau.

Tous les manuels que je me sers de discuter en utilisant des chaînes - en fait, qui semble être l'une de leurs activités préférées. Impression Bonjour tout le monde, en changeant des majuscules aux minuscules, etc.

Cependant, je suis en train de comprendre comment incrémenter et imprimer des chiffres hexadécimaux dans l'assemblage MSNA et ne savent pas comment procéder. Par exemple, si je veux imprimer # 1 - n dans Hex, comment pourrais-je le faire sans l'utilisation des bibliothèques C (toutes les références que j'ai pu trouver l'emploi)

?

Mon idée principale serait d'avoir une variable dans la section .data que je continuerais à incrémenter. Mais comment puis-je extraire la valeur hexadécimale de cet endroit? Il me semble nécessaire de le convertir en une chaîne première ...?

Tout code de conseils ou de l'échantillon serait apprécié.

Était-ce utile?

La solution

Écrire une routine simple qui prend une valeur nybble (0..15) en entrée et délivre en sortie un caractère hexadécimal ( '0' .. '9', 'A' .. 'F').

Suivant écrire une routine qui prend une valeur d'octet en entrée, puis appelle le sous-programme ci-dessus deux fois à la sortie 2 caractères hexadécimaux, à savoir une pour chaque nybble.

Enfin, pour un entier octet N vous avez besoin d'une routine qui appelle cette deuxième fois de routine N, une fois pour chaque octet.

Vous trouverez peut-être utile d'exprimer en pseudo-code ou un HLL tel que C d'abord, puis réfléchir sur la façon de traduire en asm, par exemple.

void print_nybble(uint8_t n)
{
    if (n < 10) // handle '0' .. '9'
        putchar(n + '0');
    else // handle 'A'..'F'
        putchar(n - 10 + 'A');
}

void print_byte(uint8_t n)
{
    print_nybble(n >> 4); // print hi nybble
    print_nybble(n & 15); // print lo nybble
}

print_int16(uint16_t n)
{
    print_byte(n >> 8); // print hi byte
    print_byte(n & 255); // print lo byte
}

Autres conseils

Est-ce un devoir?

bits est les bits. Bit, octet, mot, double mot, ce sont des termes de matériel, les jeux d'instructions quelque chose / assembleur va référence. hex, décimal, octal, non signé, signé, chaîne, caractère, etc. sont des manifestations de langages de programmation. De même .text, .bss, .data, etc sont également des manifestations d'outils logiciels, l'ensemble des soins instruction ne marche pas environ une adresse étant .data et étant .text, il est de la même instruction de toute façon. Il y a des raisons pour lesquelles toutes ces choses de langage de programmation existent, de très bonnes raisons parfois, mais ne se confondre en essayant de résoudre ce problème.

Pour convertir les bits à ascii lisible par l'homme, vous devez d'abord connaître votre table ascii, et les opérateurs au niveau du bit, et, ou, décalage logique, décalage arithmétique, etc. charge plus et stocker et d'autres choses.

Pensez mathmatically ce qu'il faut pour obtenir un nombre de dans un registre / mémoire dans hex ascii. Dites 0x1234 qui est 0b0001001000110100. Pour un être humain pour le lire, oui, vous devez l'obtenir en une chaîne faute d'un meilleur terme, mais vous ne devez nécessairement stocker quatre caractères plus une valeur nulle dans les emplacements de mémoire adjacents afin de faire quelque chose avec elle. Cela dépend de votre fonction de sortie. Caractère normalement des entités de sortie en fonction bouillent à une seule output_char () de quelque sorte appelé à plusieurs reprises.

Vous pouvez convertir en une chaîne, mais qui est plus de travail, pour chaque caractère ascii vous appelez calculer une sorte de fonction de sortie à base de caractères unique à droite, puis. putchar () est un exemple d'un caractère d'octet de sortie fonction du type.

Donc, pour binaire que vous voulez examiner un peu à la fois et de créer un 0x30 ou 0x31. Pour octal, 3 bits à la fois et créer 0x30 à 0x37. Hex est basé sur 4 bits à la fois.

Hex a le problème qui ne se trouvent pas les 16 caractères que nous voulons utiliser adjacents les uns aux autres dans la table ascii. Donc, vous utilisez 0x30 à 0x39 pour 0 à 9 mais 0x41 à 0x46 ou 0x61 à 0x66 A à F en fonction de vos préférences ou exigences. Ainsi, pour chaque nybble vous pourriez ET avec 0xF, comparer avec 9 et ADD 0x30 ou 0x37 (10 + 0x37 = 0x41, 11 + 0x37 = 0x42, etc).

Conversion de bits dans un registre à une représentation ASCII de binaire. Si le bit en mémoire a été un 1 montre un 1 (0x31 ascii) du bit est un 0 montrent un 0 (0x30 en ascii).

void showbin ( unsigned char x )
{
    unsigned char ra;

    for(ra=0x80;ra;ra>>=1)
    {
        if(ra&x) output_char(0x31); else output_char(0x30);
    }
}

Il peut sembler logique d'utiliser unsigned char ci-dessus, mais unsigned int, en fonction du processeur cible, pourrait produire un code beaucoup mieux (nettoyeur / plus rapide). mais cela est un autre sujet

Le ci-dessus pourrait ressembler pourrait ressembler à ceci en assembleur (intentionnellement pas en utilisant x86)

 ...
 mov r4,r0
 mov r5,#0x80
top:
 tst r4,r5
 moveq r0,#0x30
 movne r0,#0x31
 bl output_char
 mov r5,r5, lsr #1
 cmp r5,#0
 bne top
 ...

Déroulé est plus facile à écrire et va être un peu plus vite, le compromis entre la mémoire est plus utilisé

 ...
 tst    r4, #0x80
 moveq  r0, #0x30
 movne  r0, #0x31
 bl output_char
 tst    r4, #0x40
 moveq  r0, #0x30
 movne  r0, #0x31
 bl output_char
 tst    r4, #0x20
 moveq  r0, #0x30
 movne  r0, #0x31
 bl output_char
 ...

Dites que vous avez eu 9 numéros de bits et je voulais convertir en octal. Prenez trois bits à la fois (rappelez-vous les humains lus de gauche à droite pour commencer avec les bits supérieurs) et ajouter 0x30 pour obtenir 0x30 à 0x37.

...
mov r4,r0
mov r0,r4,lsr #6
and r0,r0,#0x7
add r0,r0,#0x30
bl output_char
mov r0,r4,lsr #3
and r0,r0,#0x7
add r0,r0,#0x30
bl output_char
and r0,r4,#0x7
add r0,r0,#0x30
bl output_char
...

Un seul octet (8 bits) dans l'hexagone pourrait ressembler à:

...
mov r4,r0
mov r0,r4,lsr #4
and r0,r0,#0xF
cmp r0,#9
addhi r0,r0,#0x37
addls r0,r0,#0x30
bl output_character
and r0,r4,#0xF
cmp r0,#9
addhi r0,r0,#0x37
addls r0,r0,#0x30
bl output_character
...

Faire une boucle de 1 à N mémoriser cette valeur dans la mémoire et la lecture de la mémoire (.data), la production de hex:

...
mov r4,#1
str r4,my_variable
...
top:
ldr r4,my_variable
mov r0,r4,lsr #4
and r0,r0,#0xF
cmp r0,#9
addhi r0,r0,#0x37
addls r0,r0,#0x30
bl output_character
and r0,r4,#0xF
cmp r0,#9
addhi r0,r0,#0x37
addls r0,r0,#0x30
bl output_character
...
ldr r4,my_variable
add r4,r4,#1
str r4,my_variable
cmp r4,#7 ;say N is 7
bne top
...
my_variable .word 0

Enregistrement de RAM est un peu un gaspillage si vous avez des registres assez. Bien qu'avec x86, vous pouvez utiliser directement sur la mémoire et à ne pas passer par des registres.

x86 ne est pas la même chose que ci-dessus (ARM) assembleur il est laissé en exercice du lecteur de travailler l'équivalent. Le point est, il est le déplacement, Anding, et en ajoutant que la matière, la décomposer en étapes élémentaires et les instructions tombent naturellement à partir de là.

rapide et sale macro GAS

.altmacro

/*
Convert a byte to hex ASCII value.
c: r/m8 byte to be converted
Output: two ASCII characters, is stored in `al:bl`
*/
.macro HEX c
    mov \c, %al
    mov \c, %bl
    shr $4, %al
    HEX_NIBBLE al
    and $0x0F, %bl
    HEX_NIBBLE bl
.endm

/*
Convert the low nibble of a r8 reg to ASCII of 8-bit in-place.
reg: r8 to be converted
Output: stored in reg itself.
*/
.macro HEX_NIBBLE reg
    LOCAL letter, end
    cmp $10, %\reg
    jae letter
    /* 0x30 == '0' */
    add $0x30, %\reg
    jmp end
letter:
    /* 0x57 == 'A' - 10 */
    add $0x57, %\reg
end:
.endm

Utilisation:

mov $1A, %al
HEX <%al>

<> sont utilisés en raison de .altmacro: gaz macro altmacro avec un signe pour cent dans un paramètre par défaut échoue avec "opérateur% a besoin d'expression absolue"

Résultat:

  • %al contient 0x31, qui est '1' en ASCII
  • %bl contient 0x41, qui est 'A' en ASCII

Maintenant, vous pouvez faire ce que vous voulez avec %al et %bl, par exemple:.

  • boucle sur plusieurs octets et les copier dans la mémoire (assurez-vous d'allouer deux fois plus de mémoire comme il y a des octets)
  • les imprimer avec le système ou les appels BIOS

Intel Syntaxe. Ceci est de mon bootloader mais vous devriez être en mesure d'obtenir l'idée.

print_value_of_CX:

    print_value_of_C_high:

        print_value_of_C_high_high_part:
            MOV AH, CH
            SHR AH, 0x4
            CALL byte_hex_printer

        print_value_of_C_high_low_part:
            MOV AH, CH
            SHL AH, 0x4
            SHR AH, 0x4
            CALL byte_hex_printer

    print_value_of_C_low:

        print_value_of_C_low_high_part:
            MOV AH, CL
            SHR AH, 0x4
            CALL byte_hex_printer

        print_value_of_C_low_low_part:
            MOV AH, CL
            SHL AH, 0x4
            SHR AH, 0x4
            CALL byte_hex_printer

byte_hex_printer:
    CMP AH, 0x00
    JE move_char_for_zero_into_AL_to_print
    CMP AH, 0x01
    JE move_char_for_one_into_AL_to_print
    CMP AH, 0x02
    JE move_char_for_two_into_AL_to_print
    CMP AH, 0x03
    JE move_char_for_three_into_AL_to_print
    CMP AH, 0x04
    JE move_char_for_four_into_AL_to_print
    CMP AH, 0x05
    JE move_char_for_five_into_AL_to_print
    CMP AH, 0x06
    JE move_char_for_six_into_AL_to_print
    CMP AH, 0x07
    JE move_char_for_seven_into_AL_to_print
    CMP AH, 0x08
    JE move_char_for_eight_into_AL_to_print
    CMP AH, 0x09
    JE move_char_for_nine_into_AL_to_print
    CMP AH, 0x0A
    JE move_char_for_A_into_AL_to_print
    CMP AH, 0x0B
    JE move_char_for_B_into_AL_to_print
    CMP AH, 0x0C
    JE move_char_for_C_into_AL_to_print
    CMP AH, 0x0D
    JE move_char_for_D_into_AL_to_print
    CMP AH, 0x0E
    JE move_char_for_E_into_AL_to_print
    CMP AH, 0x0F
    JE move_char_for_F_into_AL_to_print

        move_char_for_zero_into_AL_to_print:
        MOV AL, 0x30
        CALL print_teletype_stringB
        RET
        move_char_for_one_into_AL_to_print:
        MOV AL, 0x31
        CALL print_teletype_stringB
        RET
        move_char_for_two_into_AL_to_print:
        MOV AL, 0x32
        CALL print_teletype_stringB
        RET
        move_char_for_three_into_AL_to_print:
        MOV AL, 0x33
        CALL print_teletype_stringB
        RET
        move_char_for_four_into_AL_to_print:
        MOV AL, 0x34
        CALL print_teletype_stringB
        RET
        move_char_for_five_into_AL_to_print:
        MOV AL, 0x35
        CALL print_teletype_stringB
        RET
        move_char_for_six_into_AL_to_print:
        MOV AL, 0x36
        CALL print_teletype_stringB
        RET
        move_char_for_seven_into_AL_to_print:
        MOV AL, 0x37
        CALL print_teletype_stringB
        RET
        move_char_for_eight_into_AL_to_print:
        MOV AL, 0x38
        CALL print_teletype_stringB
        RET
        move_char_for_nine_into_AL_to_print:
        MOV AL, 0x39
        CALL print_teletype_stringB
        RET
        move_char_for_A_into_AL_to_print:
        MOV AL, 0x41
        CALL print_teletype_stringB
        RET
        move_char_for_B_into_AL_to_print:
        MOV AL, 0x42
        CALL print_teletype_stringB
        RET
        move_char_for_C_into_AL_to_print:
        MOV AL, 0x43
        CALL print_teletype_stringB
        RET
        move_char_for_D_into_AL_to_print:
        MOV AL, 0x44
        CALL print_teletype_stringB
        RET
        move_char_for_E_into_AL_to_print:
        MOV AL, 0x45
        CALL print_teletype_stringB
        RET
        move_char_for_F_into_AL_to_print:
        MOV AL, 0x46
        CALL print_teletype_stringB
        RET
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top