News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

printing binary numbers in masm + debuggers?

Started by gelatine1, April 23, 2014, 05:24:52 AM

Previous topic - Next topic

gelatine1

Hello, I have written a program and once again it crashes.. I should use a debugger or something like that but I don't know where to get one and how to actually use one. Could anyone help me out ?
My code is below:


.386
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib

.data
integer db 01010101b
.code
printNum:
pop eax
mov edx,[eax]
xor eax,eax ;reset eax to 0
mov al,10000000b ;bitmask to check for binary digits

loopPrint:
test dl,al ;if the current digit is set to 0 the print0 else print1
pushf
jz print0
popf
jnz print1
shr al,01h
jnz loopPrint
ret

print0:
mov ecx,30h
push ecx
call StdOut
ret

print1:
mov ecx,31h
push ecx
call StdOut
ret

start:

lea eax,integer
push eax
call printNum

push 0
call ExitProcess

end start


dedndave

many of us use Olly Debugger
http://www.ollydbg.de/version2.html

but, i can see one problem....

you PUSH EAX, then call a function
when you POP EAX, you are popping the RETurn address

CALL works like this

    call    SomeProc
xyzzy:

    push    xyzzy
    jmp     SomeProc


there are a few ways to get the passed argument
one way might be
    mov     eax,[esp+4]

when you RET, you have to remove the argument from the stack
    ret     4

MichaelW

Hopefully this illustrates what is on the stack in the called procedure, but to understand it you need to know some things about the stack and stack usage. This simplified description covers only the most basic details for procedures in 32-bit programs. The stack is an area of memory that is used for temporary storage of data. The CPU uses the stack to store the return address for a procedure call, placed on the stack by the CALL instruction and retrieved from the stack by the RET instruction. Programs use the stack to store register, memory, or immediate values, local variables, and procedure parameters. The stack is functionally a last in, first out (LIFO) data structure. The PUSH instruction subtracts 4 from the stack pointer (ESP) and then copies the contents of its operand (a 32-bit register or memory operand, or an immediate operand) to the stack at the address specified by ESP. The POP instruction copies the 32-bit value from the stack address specified by ESP to its operand (a 32-bit register or memory operand) and then adds 4 to ESP. The key points are:

As values are pushed, the stack "grows" down in memory.

ESP always points to the "top" of the stack, which contains the most recently pushed value and the next in line to be popped.


include \masm32\include\masm32rt.inc
.data
.code

    ; This externdef statement tells ML what the returnAddress label is
    ; so we can reference it in the printf statement (on line 22) above
    ; the point at which it is defined (on line 25):

    externdef returnAddress:near

  xxx:

    mov eax, [esp+4]
    printf("[esp+4]:       %Xh\n", eax)
    mov eax, [esp]
    printf("[esp]:         %Xh\n\n", eax)

    ret 4

start:

    printf("returnAddress: %Xh\n\n", returnAddress)
    push 1
    call xxx
  returnAddress:

    inkey
    exit
end start


returnAddress: 401040h

[esp+4]:       1h
[esp]:         401040h

Well Microsoft, here's another nice mess you've gotten us into.

gelatine1

I believe that I have solved the problem you told me about but it still doesn't work. If I comment out the two lines jz print0 and jnz print1 it compiles and runs without crashing but if they are not commented out then the program simply crashes again. Why is this ? Do I have to push and pop things too whenever I use jz or jnz ?
My slightly edited code:


.386
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib

.data
integer db 01010101b
.code
printNum:
pop edx
pop eax
push edx

mov edx,[eax]
xor eax,eax
mov al,10000000b

loopPrint:
test dl,al
pushf
;jz print0
popf
;jnz print1
shr al,01h
jnz loopPrint
ret

print0:
mov ecx,30h
push ecx
call StdOut
ret

print1:
mov ecx,31h
push ecx
call StdOut
ret

start:

lea eax,integer
push eax
call printNum

push 0
call ExitProcess

end start


jj2007

   mov ecx,30h
   push ecx
   call StdOut


Instead of torturing your poor computer with arbitrary instructions, you should perhaps read the manual. \Masm32\Help is a good starting point.

gelatine1


jj2007

Quote from: gelatine1 on April 25, 2014, 03:11:06 PM
Could you tell me what exactly goes wrong?

Yes: You assume that the computer reads your thoughts and acts accordingly. WRONG. To force a computer to do what you want, you have to LEARN its language - see Help and tutorials, recommended reading. READ at least Randall Hyde's book, then come back and ask precise questions (I know reading is a nuisance for those who have difficulties reading, but there is no alternative. You HAVE to read before writing code).

K_F

gelatine1:
I'm afraid JJ is right..  :dazzled:

We (or most) all have gone this route and the only way to get it right is to study the manual.
This is the thing with Assembler, it has to be 100% correct, to work the way you want it too - there are no shortcuts
;)
'Sire, Sire!... the peasants are Revolting !!!'
'Yes, they are.. aren't they....'

MichaelW

Quote from: gelatine1 on April 25, 2014, 03:11:06 PM
Could you tell me what exactly goes wrong?

Your code contains multiple errors, and to recognize and correct these errors you need to know what your code is doing, and how it is supposed to work.

The StdOut procedure expects a pointer to a null-terminated string, and you are passing the 32-bit values 30h and 31h. This will not work for reasons that should be obvious, so to isolate the next problem I just commented out the calls to StdOut.

From the MASM reference for RET/RETN/RETF:
Quote
Returns from a procedure by transferring control to an address popped from the top of the stack.

One of the key points in my description of the stack above was:

QuoteESP always points to the "top" of the stack, which contains the most recently pushed value and the next in line to be popped.

On entry to your procedure the return address is at the top of the stack. The POP, POP, PUSH sequence gets the procedure argument into EAX and restores the return address to the top of the stack. Further down the PUSHF stores a copy of the flags at the top of the stack. With the jz print0 on line 27 commented out, the POPF on line 28 restores the return address to the top of the stack, and when the loop completes the RET on line 32 returns from the procedure call without problems. With the jz print0 on line 27 not commented the jump is taken and the POPF never executes, so when the RET on line 38 executes it tries to use the copy of the flags as a return address, which again, will not work for reasons that should be obvious.

I think you should start out with simpler code that uses a normal procedure where you access the parameters by name and don't have to deal with the complexities of the stack.
Well Microsoft, here's another nice mess you've gotten us into.