greenity
greenity

Reputation: 439

convert binary to hex in assembly 80x86

I'm looking for a program that coverts a String of 1's and 0's to hexadecimal string in assembly, where the binary string comes from a code that I write in 'C'.
for example:

10111111100-> "5 F C"

The problem is that for more than 12 chars input , the output is wrong , and my mission demands at most 32 chars.

for example given 110010101111-> "CAF" it works ok! but giving 10010001101000101011001111000 should be "12345678" but i only get "123" debugging with gdb tool i see that the values are being override . how to take care of this with minimal changes in the code? Thanks

The idea is to transform the string pointed by ecx to a value in eax. now i want to take the 4 most right each time and convert them , and them put them in edx .

So far, I have:

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

Upvotes: 0

Views: 9080

Answers (3)

Alexander Zhak
Alexander Zhak

Reputation: 9282

Another variant for any-length input. The code is 16-bit and probably could be optimized a bit. Written on a knee, to show the idea

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

Upvotes: 1

Sep Roland
Sep Roland

Reputation: 39691

If it is the task to convert a string of zeroes and ones into a string of hexcharacters ("10111111100" -> "000005FC") then the first thing to do is to put the value of the source string in a register. You need to setup ECX to point to the string 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

You can simplify the code shl al,4 shr al,4 to 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 

The end part should not change EBX and jump back 8 times precisely.

end:
inc ecx
cmp ecx,LC1+8
jb Again

Upvotes: 2

User.1
User.1

Reputation: 2642

Syntax, gotcha. (Everybody on earth has done this, including me a zillion times.)

cmp al , 00001001    ;This is actually one thousand and one
jz case1001to9       ;but you treat it like it's nine

I can't tell if you're using Masm/Tasm/Nasm/ or whatever, but I believe that if you put the letter "b" at the end of your binary numbers, Masm will recognize them as such.

(ooops, edit: The letter B at the end is old school. Just checked HERE on the Microsoft website and the new improved (no it isn't, but I don't get to vote) way to do this is to insert "0y" as a prefix instead of my originally suggested "B" as a suffix.)

Put my words to the test: before you do this, look at the output from the assembler, and see if the 00001001 is actually a nine or if it is a thousand and one.

If you can't see the output in assembler, step it through debug.

Upvotes: 2

Related Questions