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?
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
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
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
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/