在汇编 80x86 中将二进制转换为十六进制
convert binary to hex in assembly 80x86
我正在寻找一个程序,将 1 和 0 的字符串转换为汇编中的十六进制字符串,其中二进制字符串来自我在 'C'.
中编写的代码
例如:
10111111100-> "5 F C"
问题是超过 12 个字符的输入,输出是错误的,而我的任务最多需要 32 个字符。
例如给定 110010101111-> "CAF" 它工作正常!
但给出 10010001101000101011001111000 应该是“12345678”
但我只得到“123”
使用 gdb 工具进行调试,我看到值正在被覆盖。如何以最少的代码更改来解决这个问题?谢谢
思路是将ecx指向的字符串转换为eax中的值。
现在我想每次取最正确的4个并转换它们,然后将它们放入edx中。
到目前为止,我有:
section .rodata
LC0:
DB "The result is: %s", 10, 0 ; Format string
section .bss
LC1:
RESB 32
section .text
align 16
global my_func
extern printf
my_func:
push ebp
mov ebp, esp ; Entry code - set up ebp and esp
pusha ; Save registers
mov ecx, dword [ebp+8] ; Get argument (pointer to string)
mov ebx, 0 ; counter for length
mov eax, 0 ; will hold the string as a value
mov edx, 0 ; manipulation helper
mov edi, 0 ; counter for ehile_length loop
length:
inc ebx
cmp byte [ecx+ebx], 0x00
jne length
dec ebx
;;;;THIS PART IS PARSING THE STRING INTO A REGISTER;;;
bring_ecx_to_end:
inc ecx
cmp byte [ecx], 0x0
JNE bring_ecx_to_end
dec ecx
dec ecx
or edi ,ebx
add esi,1
while_length:
mov dl,byte [ecx] ; gets 1 char into edx
cmp DL, 0x31 ; the right character
JE inc1 ; if it a '1'
resume_loop:
shl esi,1 ; multiply by 2
dec ecx
sub edi,1
cmp edi,0
jne while_length
;;;;;;;;;;NOW EAX CONSISTS THE STRING ;;;;;;;;;;;;;;
mov dword edx,0 ;target register
while:
mov dword edi ,0
add edi ,15 ; masking
and edi,eax
cmp di , 10
jl less_than_10
;less_than_F
add di ,55
jmp resume
less_than_10:
add di ,48
resume:
or edx,edi
shl edx,8
shr eax,4
cmp al ,0
jne while
shr edx , 8
;;;;;;;;;DONE;;;;;;;;;;;;;
end:
mov dword [LC1],edx
push LC1 ; Call printf with 2 arguments: pointer to str
push LC0 ; and pointer to format string.
call printf
add esp, 8 ; Clean up stack after call
popa ; Restore registers
mov esp, ebp ; Function exit code
pop ebp
ret
inc1:
or eax, esi
jmp resume_loop
如果任务是将零和一的 字符串 转换为十六进制字符的 字符串 ("10111111100" -> " 000005FC") 那么首先要做的就是将源字符串的值放入一个寄存器中。
您需要将 ECX 设置为指向字符串 LC1.
mov ecx,[ebp+8] ;Pointer to an ASCIIZ string of zero and one characters.
xor ebx,ebx
First:
rcl ebx,1
mov al,[ecx]
inc ecx
shr al,1
jnz First
mov ecx,LC1 ;Buffer to recieve 8 hexcharacters.
Again:
rol ebx,4
您可以将代码 shl al,4
shr al,4
简化为 and al,15
。
end:
shr ebx, 4
inc ecx ; increment pointer
cmp byte [ecx], 0 ; check if byte pointed to is zero
jnz while_ebx_not_zero ; keep looping until it is null
end部分不要改变EBX,精确跳回8次。
end:
inc ecx
cmp ecx,LC1+8
jb Again
语法,明白了。 (地球上的每个人都这样做过,包括我无数次。)
cmp al , 00001001 ;This is actually one thousand and one
jz case1001to9 ;but you treat it like it's nine
我不知道你是在使用 Masm/Tasm/Nasm/ 还是什么,但我相信如果你把字母“b
”在二进制数的末尾,Masm 会这样识别它们。
(糟糕,编辑:最后的字母 B
是老派了。刚刚在 Microsoft 网站上检查了 HERE 和新的改进(不,不是,但我不t 得到投票)做到这一点的方法是插入“0y
”作为 前缀 而不是我最初建议的“B
”作为后缀。)
验证我的话:在执行此操作之前,查看汇编程序的输出,看看 00001001
实际上是 9 还是 1001。
如果您在汇编程序中看不到输出,请逐步调试。
任意长度输入的另一种变体。该代码是 16 位的,可能可以稍微优化一下。写在膝盖上,表达想法
mov si, input_string
mov di, output_string
mov ax, 7 ;input_string length
call bin2hex
bin2hex:
add si, ax ;si points to the end of input string
mov bx, ax
mov cx, 4 ;\
div cl ;
cmp ah, 0 ;compute how many nibbles to convert
jz short .a ;and point di to the end of the result buffer
inc di ;
mov ah, 0 ;
.a: ;
add di, ax ;/
mov [di], ah ;terminating zero
.next_nibble:
mov cl, 4 ;iterate 4 times
mov dl, 0
.next_bit:
dec si
mov al, [si]
shr al, 1 ;mov bit0 to carry flag
rcl dl, 1 ;shift with carry flag into the least-significant bit
dec bx
jz short .stop ;end of input string?
dec cx
jnz short .next_bit
.stop:
shl dl, cl ;complete last nibble to full
cmp dl, 0x0a
jl short .to_ascii
add dl, 7 ;0Ah - 0Fh = ASCII codes 41h - 46h
.to_ascii:
add dl, 0x30
dec di
mov [di], dl
test bx, bx ;end of input string reached?
jnz .next_nibble ;continue if not
ret
我正在寻找一个程序,将 1 和 0 的字符串转换为汇编中的十六进制字符串,其中二进制字符串来自我在 'C'.
中编写的代码
例如:
10111111100-> "5 F C"
问题是超过 12 个字符的输入,输出是错误的,而我的任务最多需要 32 个字符。
例如给定 110010101111-> "CAF" 它工作正常! 但给出 10010001101000101011001111000 应该是“12345678” 但我只得到“123” 使用 gdb 工具进行调试,我看到值正在被覆盖。如何以最少的代码更改来解决这个问题?谢谢
思路是将ecx指向的字符串转换为eax中的值。 现在我想每次取最正确的4个并转换它们,然后将它们放入edx中。
到目前为止,我有:
section .rodata
LC0:
DB "The result is: %s", 10, 0 ; Format string
section .bss
LC1:
RESB 32
section .text
align 16
global my_func
extern printf
my_func:
push ebp
mov ebp, esp ; Entry code - set up ebp and esp
pusha ; Save registers
mov ecx, dword [ebp+8] ; Get argument (pointer to string)
mov ebx, 0 ; counter for length
mov eax, 0 ; will hold the string as a value
mov edx, 0 ; manipulation helper
mov edi, 0 ; counter for ehile_length loop
length:
inc ebx
cmp byte [ecx+ebx], 0x00
jne length
dec ebx
;;;;THIS PART IS PARSING THE STRING INTO A REGISTER;;;
bring_ecx_to_end:
inc ecx
cmp byte [ecx], 0x0
JNE bring_ecx_to_end
dec ecx
dec ecx
or edi ,ebx
add esi,1
while_length:
mov dl,byte [ecx] ; gets 1 char into edx
cmp DL, 0x31 ; the right character
JE inc1 ; if it a '1'
resume_loop:
shl esi,1 ; multiply by 2
dec ecx
sub edi,1
cmp edi,0
jne while_length
;;;;;;;;;;NOW EAX CONSISTS THE STRING ;;;;;;;;;;;;;;
mov dword edx,0 ;target register
while:
mov dword edi ,0
add edi ,15 ; masking
and edi,eax
cmp di , 10
jl less_than_10
;less_than_F
add di ,55
jmp resume
less_than_10:
add di ,48
resume:
or edx,edi
shl edx,8
shr eax,4
cmp al ,0
jne while
shr edx , 8
;;;;;;;;;DONE;;;;;;;;;;;;;
end:
mov dword [LC1],edx
push LC1 ; Call printf with 2 arguments: pointer to str
push LC0 ; and pointer to format string.
call printf
add esp, 8 ; Clean up stack after call
popa ; Restore registers
mov esp, ebp ; Function exit code
pop ebp
ret
inc1:
or eax, esi
jmp resume_loop
如果任务是将零和一的 字符串 转换为十六进制字符的 字符串 ("10111111100" -> " 000005FC") 那么首先要做的就是将源字符串的值放入一个寄存器中。 您需要将 ECX 设置为指向字符串 LC1.
mov ecx,[ebp+8] ;Pointer to an ASCIIZ string of zero and one characters.
xor ebx,ebx
First:
rcl ebx,1
mov al,[ecx]
inc ecx
shr al,1
jnz First
mov ecx,LC1 ;Buffer to recieve 8 hexcharacters.
Again:
rol ebx,4
您可以将代码 shl al,4
shr al,4
简化为 and al,15
。
end:
shr ebx, 4
inc ecx ; increment pointer
cmp byte [ecx], 0 ; check if byte pointed to is zero
jnz while_ebx_not_zero ; keep looping until it is null
end部分不要改变EBX,精确跳回8次。
end:
inc ecx
cmp ecx,LC1+8
jb Again
语法,明白了。 (地球上的每个人都这样做过,包括我无数次。)
cmp al , 00001001 ;This is actually one thousand and one
jz case1001to9 ;but you treat it like it's nine
我不知道你是在使用 Masm/Tasm/Nasm/ 还是什么,但我相信如果你把字母“b
”在二进制数的末尾,Masm 会这样识别它们。
(糟糕,编辑:最后的字母 B
是老派了。刚刚在 Microsoft 网站上检查了 HERE 和新的改进(不,不是,但我不t 得到投票)做到这一点的方法是插入“0y
”作为 前缀 而不是我最初建议的“B
”作为后缀。)
验证我的话:在执行此操作之前,查看汇编程序的输出,看看 00001001
实际上是 9 还是 1001。
如果您在汇编程序中看不到输出,请逐步调试。
任意长度输入的另一种变体。该代码是 16 位的,可能可以稍微优化一下。写在膝盖上,表达想法
mov si, input_string
mov di, output_string
mov ax, 7 ;input_string length
call bin2hex
bin2hex:
add si, ax ;si points to the end of input string
mov bx, ax
mov cx, 4 ;\
div cl ;
cmp ah, 0 ;compute how many nibbles to convert
jz short .a ;and point di to the end of the result buffer
inc di ;
mov ah, 0 ;
.a: ;
add di, ax ;/
mov [di], ah ;terminating zero
.next_nibble:
mov cl, 4 ;iterate 4 times
mov dl, 0
.next_bit:
dec si
mov al, [si]
shr al, 1 ;mov bit0 to carry flag
rcl dl, 1 ;shift with carry flag into the least-significant bit
dec bx
jz short .stop ;end of input string?
dec cx
jnz short .next_bit
.stop:
shl dl, cl ;complete last nibble to full
cmp dl, 0x0a
jl short .to_ascii
add dl, 7 ;0Ah - 0Fh = ASCII codes 41h - 46h
.to_ascii:
add dl, 0x30
dec di
mov [di], dl
test bx, bx ;end of input string reached?
jnz .next_nibble ;continue if not
ret