Impression hexadécimaux Digits avec l'Assemblée
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é.
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