0

So I started learning assembly 4 days ago (I started with 8086 assembly and moved to masm32 since I want to run my programs on windows) and I am currently trying to set up some handy procedures and macro's so I can make coding bigger programs easier. I started working on a procedure to print integers to the console (252 would be displayed as '252' instead of the ascii character for 2, 5 & 2 again), but for some reason it isn't working as I intended, I'm not getting any errors and the program doesn't even halt. Could someone help me figure out why?

Output (the program only prints the 'é' character and then does nothing until I stop it):

é

main procedure:

main proc
    
    ; Getting the console input & output handles and storing them in consoleInHandle & consoleOutHandle
    invoke GetStdHandle, STD_INPUT_HANDLE
    mov consoleInHandle, eax
    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov consoleOutHandle, eax

    mPrintUInt32 251

invoke ExitProcess, 0
main endp

mPrintUInt32 macro:

mPrintUInt32 macro integer ; Prints the integer in decimal to the console

    pusha

    mov edx, 0
    mov eax, integer
    mov max, 1000000000
    call pPrintUInt32

    popa

endm

pPrintUInt32 procedure:

pPrintUInt32 proc ; Prints a 32-bit unsigned integer to the console

    ; Divide EDX:EAX by r/m32 and store the result in EAX and the remainder in EDX
    ; Result: EAX, remainder: EDX

    cmp max, 1 ; If max is equal to 1 we know that we have cycled through all digits and can now stop
    je stop

    div max ; Divide the input by max

    cmp eax, 0 ; If the input is smaller than max (if the result is 0, the whole number is in the remainder)
    je next_digit ; Go to the next digit

    add eax, '0' ; Turn the result into an ascii character by adding the '0' character
    mPrintChar al ; Print the current digit

next_digit:
    push edx ; Push the remainder

    mov ebx, 10 ; Store 10 in ebx so we can divide max
    div max ; Divide max by 10
    mov max, eax ; Store the result of the division back into max

    pop edx ; Pop the remainder so we can use it as input
    call pPrintUInt32 ; Call pPrintUInt32 with the remainder as input

stop:
    ret
pPrintUInt32 endp

mPrintChar macro (seems to be working fine, I've tested it outside of the pPrintUInt32 procedure and it behaves as it should):

mPrintChar macro character ; Prints the given character to the console

    push bx

    mov bl, character
    call pPrintChar

    pop bx

endm

pPrintChar procedure (also works fine):

pPrintChar proc ; Prints the character stored in bl

    mov char, bl ; Store the character in memory
    invoke WriteConsole, consoleOutHandle, offset char, sizeof char, offset bytesWritten, 0 ; Print the character to the console

ret
pPrintChar endp

Any help is appreciated!

Matthias
  • 1
  • 1
  • After the first `div`, EDX=remainder, not the high half of the quotient. (Which would have to be zero if you didn't overflow and trigger a #DE exception: [Why should EDX be 0 before using the DIV instruction?](https://stackoverflow.com/q/38416593)). Your code never sets EDX=0 inside any div loop so this can't work. Your comment even says *Prints a 32-bit unsigned integer*, so don't try to mess around with taking a 64-bit EDX:EAX integer; that's harder to deal with and would take multiple div instructions for each `digit = n % 10` / `n /= 10;` step. – Peter Cordes Aug 20 '21 at 18:19
  • See also [How do I print an integer in Assembly Level Programming without printf from the c library?](https://stackoverflow.com/a/46301894) for working code. Single-step through yours with a debugger to see what happens. You didn't describe what *does* happen when you run this, so it's not a [mcve]. – Peter Cordes Aug 20 '21 at 18:20
  • Oh I think your edit did add the specific output you're getting. Yeah, anyway, single-step with a debugger to see how you end up with that ASCII code in a byte in memory to be printed. This design looks like a mess, but I think you're trying to find the max power of 10 so you can get the leading digit, but I'm not sure you're ever actually looping to do that. (In any case, that either takes an array of powers of 10 or takes twice as many div instructions as needed vs. just getting digits in least-significant-first order and storing them backwards.) – Peter Cordes Aug 20 '21 at 19:02
  • Thanks for pointing me in the right direction! I didn't know there were debuggers for MASM assembly, turns out printing to the console changes the eax register which messed up my procedure, also I should've compared max to 0, not 1, since it wont print the last character if I compare it with 1. – Matthias Aug 20 '21 at 19:47

0 Answers0