News:

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

Main Menu

Rhs and flags not working properly?

Started by gelatine1, April 26, 2014, 05:42:31 AM

Previous topic - Next topic

gelatine1

Hi I have written an easy piece of code that should output 0 some times. Well lets just take a look to the code below:

.data
integer db 00110000b

.code

start:
mov eax,01000010b
rpt:
lea ecx,integer
push ecx
call StdOut
shr eax,1
jnc rpt

push 0
call ExitProcess

end start


This code outputs a 0 one time so this means that the carry flag is set after the shr instruction right ? I have read that the rhs only sets the carry flag if the last bit was 1 which is not the case. Now if I alter the code to jc rpt I get a full load of zeros coming which means that the carry flag is always set clearly after the shr instruction. Is this normal ?
If i change it to jz rpt I get again infinitely many 0s which would mean that eax is always zero ?
Can someone please tell me what is going wrong here?

dedndave

first of all, most masm32 and windows API functions follow the "windows ABI"
the ABI (application binary interface) is a set of rules that governs how parameters are passed and how functions are called

the ABI says that EBX, EBP, ESI, and EDI are preserved across function calls
EAX, ECX, and EDX are expendable (may be trashed)
many functions return a result or status in the EAX register
the value you have stored in EAX is almost certain to be lost across the call

secondly, we often use INVOKE when passing arguments
it's a masm-internal macro that passes arguments, according to how a function is prototyped
masm will also check INVOKE'ed calls by verifying that the proper number and size of arguments are passed
and, if a function is prototyped using a calling convention that requires it, INVOKE will also generate code to balance the stack after the call

while the PUSH/CALL method will work, INVOKE is usually a better way to go
it makes the code easier to read and understand
    INVOKE  StdOut,offset szString
the assembler actually generates this code...
    push    offset szString
    call    StdOut


finally, StdOut requires a pointer to a null-terminated string
the binary values you are playing with need to be converted to ASCII strings, prior to display

gelatine1

Thank you very much! I had totally forgotten that the registers get altered during those calls.
And by the way StdOut can print a single ascii character which is not null terminated. Following code works exactly as expected:


start:
mov eax,01000010b
rpt:
lea ecx,integer
push eax
push ecx
call StdOut
pop eax
shr eax,1
jnz rpt

push 0
call ExitProcess

end start

MichaelW

Quote from: gelatine1 on April 26, 2014, 06:53:54 PM
And by the way StdOut can print a single ascii character which is not null terminated. Following code works exactly as expected...

The code will not assemble because multiple components are missing, including the definition of integer.

As Dave stated, StdOut requires a pointer to a null terminated string. The null is used to mark the end of the string, and without it StdOut, like other similar functions, will continue displaying characters until it encounters a null byte somewhere or triggers an exception. It is possible to construct a string in memory, either in the data section or on the stack, and that is effectively what your code, and the example below, is doing.

include \masm32\include\masm32rt.inc
.data
    str1 dd 434241h     ; stored in memory as 41h,42h,43h,00h note null terminator
    str2 dd 44434241h   ; stored in memory as 41h,42h,43h,44h note no null terminator
    crlf dd 0a0dh       ; stored in memory as 0dh,0ah,00h,00h
.code
start:
    invoke StdOut, ADDR str1
    invoke StdOut, ADDR crlf
    invoke StdOut, ADDR str2
    push 0a0dh
    push 44434241h
    mov eax, esp
    invoke StdOut, eax
    inkey
    exit
end start


ABC
ABCD
ABCD



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

Vortex

Hi gelatine1,

The example below is a modified version of your code :

include     \masm32\include\masm32rt.inc

.data

integer     dd 10000000b
crlf        db 13,10,0

.data?

buffer      db 4 dup(?)

.code

start:

    mov     ecx,8

rpt:

    push    ecx                         ; eax,ecx and ecx are not stored always accross
                                        ; function calls
    invoke  dwtoa,integer,ADDR buffer   ; convert DWORD to ASCII
                                        ; dwtoa is a member of masm32.lib
    invoke  StdOut,ADDR buffer
    invoke  StdOut,ADDR crlf            ; CR+LF for the next line
    shr     integer,1                   ; divide the variable by 2
    pop     ecx
    dec     ecx
    jnz     rpt   

    invoke  ExitProcess,0

END start


The console output :

128
64
32
16
8
4
2
1


You should read the chapter Register Preservation Convention of the manual Introduction To Assembler :

\masm32\help\asmintro.chm

I would suggest you also to run the code under OllyDbg :

http://www.ollydbg.de/