我正在尝试学习NASM程序集,但我似乎正在努力解决高级语言中的问题。
我正在使用的所有教科书都使用字符串进行讨论 - 事实上,这似乎是他们最喜欢的东西之一。打印你好世界,从大写变为小写等
但是,我试图了解如何增加和打印NASM程序集中的十六进制数字,并且不知道如何继续。例如,如果我想在Hex中打印#1 - n,那么如果不使用C库(我能够找到所有引用,我将如何使用),我该怎么办呢?
我的主要想法是在.data部分有一个变量,我将继续增加。但是如何从此位置提取十六进制值?我似乎需要先将它转换为字符串......?
任何建议或示例代码都将不胜感激。
答案 0 :(得分:8)
首先编写一个简单的例程,它将nybble值(0..15)作为输入并输出一个十六进制字符('0'..'9','A'..'F')。
接下来编写一个例程,它接受一个字节值作为输入,然后调用上面的例程两次输出2个十六进制字符,即每个nybble一个。
最后,对于一个N字节整数,你需要一个例程,它调用第二个例程N次,每个字节一次。
您可能会发现在伪代码或HL等首先表达它有帮助,然后考虑如何将其转换为asm,例如。
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
}
答案 1 :(得分:1)
这是家庭作业吗?
比特是比特。位,字节,字,双字,这些是硬件术语,指令集/汇编器将参考。 hex,decimal,octal,unsigned,signed,string,character等是编程语言的表现形式。同样,.text,.bss,.data等也是软件工具的表现形式,指令集并不关心一个地址是.data,一个是.text,它是同一条指令。所有这些编程语言都存在的原因有很多,有时是非常好的理由,但在尝试解决这个问题时不要混淆。
要从位转换为人类可读的ascii,首先需要知道你的ascii表,按位运算符,以及逻辑移位,算术移位等。加载和存储等等。
从数学上思考从寄存器/内存中的某个数字到ascii hex的内容。比如0x1234,即0b0001001000110100。对于一个人来阅读它,是的,你需要把它变成一个字符串,因为缺少一个更好的术语,但是你不一定需要在相邻的内存位置存储四个字符和一个null,以便用它做一些事情。这取决于您的输出功能。通常,基于字符的输出实体可以归结为多次调用的某种output_char()。
你可以转换为一个字符串,但这更有效,因为你计算的每个ascii字符都会调用某种基于单字符的输出函数。 putchar()是字节输出字符类型函数的示例。
因此对于二进制文件,您希望一次检查一个位并创建0x30或0x31。对于八进制,一次3位,并创建0x30到0x37。十六进制一次基于4位。
Hex有一个问题,就是在ascii表中找不到我们想要使用的16个字符。因此,对于A到F,您使用0x30至0x39表示0至9但0x41至0x46或0x61至0x66,具体取决于您的偏好或要求。因此,对于每个nybble,您可以使用0xF,与9和ADD 0x30或0x37(10 + 0x37 = 0x41,11 + 0x37 = 0x42等)进行比较。
从寄存器中的位转换为二进制的ascii表示。如果内存中的位为1则显示该位的1(0x31 ascii)为0,则显示0(ascii中的0x30)。
void showbin ( unsigned char x ) { unsigned char ra; for(ra=0x80;ra;ra>>=1) { if(ra&x) output_char(0x31); else output_char(0x30); } }
上面使用unsigned char似乎是合乎逻辑的,但unsigned int(取决于目标处理器)可以产生更好(更清晰/更快)的代码。但这是另一个话题
以上看起来在汇编程序中可能看起来像这样(故意不使用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 ...
展开更容易编写并且速度更快,权衡更多的内存
... 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 ...
假设您有9位数字并希望转换为八进制数。一次取三位(记住人从左到右读取所以从高位开始)并添加0x30以获得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 ...
十六进制的单个(8位)字节可能如下所示:
... 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 ...
从1到N进行循环,将该值存储在内存中并从内存中读取(.data),以十六进制输出:
... 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
如果你有足够的寄存器,保存到ram有点浪费。虽然使用x86,您可以直接在内存上操作,而不必通过寄存器。
x86与上面的(ARM)汇编程序不同,所以它留给读者练习等效。关键是,正在转移,分析和添加这个问题,将其分解为基本步骤,指令自然会从那里掉出来。
答案 2 :(得分:1)
快速而肮脏的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
用法:
mov $1A, %al
HEX <%al>
由于<>
:Gas altmacro macro with a percent sign in a default parameter fails with "% operator needs absolute expression" ,因此使用 .altmacro
结果:
%al
包含0x31,在ASCII '1'
%bl
包含0x41,在ASCII 'A'
现在,您可以使用%al
和%bl
执行任何操作,例如:
答案 3 :(得分:0)
英特尔语法。这是来自我的引导程序,但你应该能够理解。
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