0

im writing a simple code that receives a pointer to null-terminated string that contains only digits and converts it to hex. like "479" -> 1DF but im getting segmentation fault in pop eax! any help please? note: assembly x86

Error on gdb: cannot access memory ar 0xfff...


lop:
    push  dword[edi]
    inc byte [co]
    mov edi, an
    jmp loop

fin:
    push dword[edi]
    inc byte [co]
    jmp finish

loop:
    mov edx, [co]
    cmp edx, 0
    je done
    dec edx
    pop eax
    mov [edi], eax
    inc edi
    jmp loop 


Full code:

section .data
    co: dd 0
    hex: dd "123456789ABCDEF"   

section .rodata                     ; we define (global) read-only variables in .rodata section
    format_string: db "%s", 10, 0   ; format string

section .bss                        ; we define (global) uninitialized variables in .bss section
    an: resb 12                     ; enough to store integer in [-2,147,483,648 (-2^31) : 2,147,483,647 (2^31-1)]

section .text
    global convertor
    extern printf

convertor:
    push ebp
    mov ebp, esp    
    pushad          

    mov ecx, dword [ebp+8]      ; get function argument (pointer to string)
    mov edx, ecx                    ; our string

    mov ebx, 16
    xor eax, eax                    ; zero a "result so far"
top:
    movzx ecx, byte [edx]           ; get a character
    inc edx                         ; ready for next one
    cmp ecx, '0'                    ; valid?
    jb finish
    sub ecx, '0'                    ; "convert" character to number
    imul eax, 10                    ; multiply "result so far" by ten
    add eax, ecx                    ; add in current digit
    jmp top                         ; until done


finish:
    mov edi, hex
    xor edx, edx
    cmp eax, ebx
    jl hello
    div ebx
innerLoop:
    cmp edx, 1
    je fin
    inc edi
    dec edx
    jmp innerLoop

hello:
    cmp eax, 1
    je lop
    inc edi
    dec edx
    jmp hello

lop:
    push  dword[edi]
    inc byte [co]
    mov edi, an
    jmp loop

fin:
    push dword[edi]
    inc byte [co]
    jmp finish

loop:
    mov edx, [co]
    cmp edx, 0
    je done
    dec edx
    pop eax
    mov [edi], eax
    inc edi
    jmp loop 

done:               
    push an                     ; call printf with 2 arguments -
    push format_string          ; pointer to str and pointer to format string
    call printf
    add esp, 8                      ; clean up stack after call

    popad           
    mov esp, ebp    
    pop ebp
    ret
Jester
  • 56,577
  • 4
  • 81
  • 125
  • 1
    There are multiple problems with your code and it's not clear what you are doing either. Comment your code, especially if you want others to help. One obvious problem is that you load 4 bytes instead of 1. Another is that you only push 1 value at `lop` and then you go into `loop` which tries to pop multiple things in a loop. If `co` is a pointer then `inc byte [co]` should be a `dword`. In `loop` you do `dec edx` but then don't use `edx` at all. – Jester Apr 24 '20 at 21:53
  • i cant add the code here ... it says 550 chars left – Tariq Ganem Apr 24 '20 at 22:46
  • i posted my code as an answer can you see it please? – Tariq Ganem Apr 24 '20 at 22:47
  • Use the [edit link under the question](https://stackoverflow.com/posts/61417970/edit) to add new information. – Jester Apr 24 '20 at 22:50
  • and now it says : all your comments seem to be Code, re-write them ... – Tariq Ganem Apr 24 '20 at 23:07
  • The code is still unclear, what is your algorithm? It's easy to convert to hex just by masking off 4 bits at a time for a hex digit. – Jester Apr 24 '20 at 23:13
  • Thank you for your support! my algorithm: 1. convert the given string to int: "1234" -> 1234 (atoi) 2. convert to hex : push the remainder of the division of 1234 by 16 to the stack 3. pop items from the stack so we insert the digits in reverse to an (output to print) – Tariq Ganem Apr 24 '20 at 23:18
  • If you have a better solution i will be happy ;) – Tariq Ganem Apr 24 '20 at 23:26
  • 1
    [How to convert a binary integer number to a hex string?](https://stackoverflow.com/q/53823756) has working code for int->hex. Don't use `div` to divide by 16, that's horrible. Also, it looks like `pop` segfaults because your loop runs forever if `[co] != 0`, because your loop doesn't change it. So eventually ESP points to an unmapped page and you segfault. Use the debugger to single-step your code and see what happens *before* the segfault and why. Also, doing 4-byte stores and incrementing `edi` by 1 byte is probably not what you wanted. – Peter Cordes Apr 25 '20 at 00:13
  • is there any simple way to convert int to hex and store the hex digits into buffer? assembly x86 – Tariq Ganem Apr 25 '20 at 00:47
  • Yes, the first code block in my answer [How to convert a binary integer number to a hex string?](https://stackoverflow.com/q/53823756) shows a nice simple loop that does exactly that, using rotate + AND to isolate 4-bit chunks, and a lookup table to convert to hex. I've linked it several times; is something about the early parts of that answer not clear? – Peter Cordes Apr 25 '20 at 05:14
  • there is no problem in code you give, but its mandatory to use div and mul in this homework .. any ideas how to solve this? – Tariq Ganem Apr 25 '20 at 11:05
  • @PeterCordes, i tried your solution and it worked for me! just one thing, 479 -> 1DF but your code padding it with 0, so 479 -> 000001DF, which i dont want ... – Tariq Ganem Apr 25 '20 at 11:31
  • `itohex_conditional` later in my answer has a version that starts from the lowest nibble first, and writes backwards from the end of a buffer. The comment on the bottom of the loop points out how to tweak it to stop when the rest of the bits are `0`, i.e. all the non-zero bits have been shifted out and only leading zeros are left. There are of course other ways to implement conversion without leading zeros, e.g. you could `bsr` to find the highest non-zero bit and use that to shl by a multiple of 4 bits, leaving the desired bits at the top of the register. – Peter Cordes Apr 25 '20 at 12:13
  • Having to use `mul`: that's normal for converting from decimal to a number in a register (binary). Having to use `div`: that's horrible, but of course you *can* divide by 16 just like you'd divide by 10 to convert to decimal, getting the remainder as the least-significant digit first. – Peter Cordes Apr 25 '20 at 12:14

0 Answers0