The MASM Forum

General => The Campus => Topic started by: Nyatta on January 23, 2016, 08:38:32 AM

Title: push 0
Post by: Nyatta on January 23, 2016, 08:38:32 AM
I feel very silly asking this, but what purpose does "push 0" serve?; I can't get over feeling that I am pushing 4 bytes of garbage onto the stack, which certainly is incorrect. Studying the code below, originally posted by jj2007, everything works swimmingly despite me perceiving it as there being 4 byte gap between the data it is popping off the stack... not to say my perception is altering the outcome, as this isn't some sort of quantum computing. :P

Quote from: jj2007 on April 12, 2014, 10:08:17 AMinclude \masm32\include\masm32rt.inc

.code
start:
  ; open a file - the handle returned in eax gets pushed on the stack:
  push fopen("\Masm32\examples\exampl05\hlldemo\fileio\fileio.exe")
  push 0      ; create an empty 4-byte buffer on the stack
  mov ecx, esp      ; and store its address to ecx
  push eax            ; create another 4-byte buffer on the stack
  mov edx, esp      ; and store its address to edx
  invoke ReadFile, eax, ecx, 1, edx, 0      ; invoke ReadFile, handle, pBuffer, #bytes, pBytesRead, 0
  .if !eax
      print LastError$(), 13, 10      ; good to know if an error occurred
  .endif
  pop ecx                  ; get value from the second stack buffer
  print str$(ecx), " bytes read", 13, 10
  pop ebx                  ; get value from the first stack buffer
  call CloseHandle      ; the handle is still on the stack, so this is invoke CloseHandle, eax
  print str$(ebx), " is the first byte"
  exit

end start

I'd rather not run under any false assumptions so in the context of that code what is push 0 accomplishing and is it generally used to serve the same purpose in most code?
Title: Re: push 0
Post by: jj2007 on January 23, 2016, 08:45:58 AM
Sometimes a function expects a pointer to a variable. The push 0 creates a variable:

AAAAA   stack before
0000AA  stack after push 0

The function uses these 4 bytes to store a result, e.g. 1234:

1234AA

Now you use e.g.
pop ecx
... and ecx contains 1234.

Btw the example you posted above has even two stack variables.
Title: Re: push 0
Post by: Nyatta on January 23, 2016, 09:05:35 AM
To be sure I'm clear on this...
push fopen(offset fileLocation) ; Nothing pushed into the stack yet...
push 0 ; Faux-pointer defined, now it's in the stack!
Title: Re: push 0
Post by: dedndave on January 23, 2016, 10:41:45 AM
first, "fopen" returns a file handle in EAX - it is puhed on the stack (for later use)

next, these instructions kind of work together
a temporary (local) variable is created and initialized to 0
the pointer to that variable is in ECX
this variable is used by the ReadFile function to write the number of bytes read
  push 0      ; create an empty 4-byte buffer on the stack
  mov ecx, esp      ; and store its address to ecx


after the read, that variable is removed from the stack
if the read is successful, it is no longer 0 - it holds the number of bytes actually read
  pop ecx
Title: Re: push 0
Post by: Nyatta on January 24, 2016, 07:09:48 AM
Quote from: jj2007 on January 23, 2016, 08:45:58 AMBtw the example you posted above has even two stack variables.
Quote from: dedndave on January 23, 2016, 10:41:45 AM
first, "fopen" returns a file handle in EAX - it is puhed on the stack (for later use)
I'm still very confused on what I'm looking at. The second buffer pushes EAX onto the stack where ReadFile then modifies it? I was under the impression the second parameter of ReadFile would point me to the data I loaded from the file into memory?
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx)

Maybe I'm misunderstanding this due to how all of the bytes are being handled and when they are being altered. EAX and EDX (ESP and EBP also) only change between every function, unless otherwise specified in the parameters, correct?
Perhaps I should temporarily fall back on something simpler to practice proper register usage.

Edit:
I did accomplish this through studying other codes, I was aiming to tweak it to load a file in place of nData.
.686
.model flat, stdcall
option casemap :none

include \masm32\include\masm32rt.inc

.data
lb db 13, 10, 0
nData dw 01408h, 08C08h, 0DF08h, 0F408h, 00D09h, 0FE08h, 0E108h, 0BA08h,\
08A08h, 05A08h, 02708h, 0E207h, 0BF07h, 09407h, 08807h, 0B607h,\
0DF07h, 02E08h, 06E08h, 0C808h, 02A09h, 0AF09h, 0470Ah, 0EC0Ah,\
07E0Bh, 0FF0Bh, 0510Ch, 05E0Ch, 0400Ch, 0FA0Bh, 0710Bh, 0D50Ah

.code
start:
inkey "Data: 32 double-words.", 13, 10, "Press any key to print hexadecimal values ...", 13, 10
mov ecx, 16
mov esi, offset nData

printNumb:
push esi
push ecx
mov eax, [esi]
and eax, 0000FFFFh
mov ebx, [esi]
shr ebx, 16
ror ax, 8
ror bx, 8
print uhex$(eax), 13, 10

print uhex$(ebx), 13, 10

pop ecx
pop esi
add esi, 4
loop printNumb

print offset lb
inkey "End of numberical values.",10,13,"Press any key to close ...", 13, 10
invoke ExitProcess,0

end start


Editing in loading from a file results in this mess...
.686
.model flat, stdcall
option casemap :none

include \masm32\include\masm32rt.inc

.code
start:

inkey "Press any key to begin ...", 13, 10, 10

push fopen("My_File.raw")
push 0
mov ecx, esp
push eax
mov edx, esp
invoke ReadFile, eax, ecx, 64, edx, 0

.if !eax
print LastError$(), 13, 10
.endif
pop ecx
push ecx
print str$(ecx), " bytes read", 13, 10

pop ecx
pop ebx
shr ecx, 2

pLoop:
push ecx
push ebx

and ebx, 0000FFFFh
print str$(ebx), 13, 10

pop ebx
push ebx
shr ebx, 16
print str$(ebx), 13, 10

pop ebx
pop ecx
add ebx, 4
loop pLoop

call CloseHandle

inkey "Press any key to exit ...", 13, 10

exit

end start

The code outputs The correct first 2 initial values, however adding 4 to ebx adds an additional 4 to the first WORD which each rep, and as the second WORD is outside of bh and bl it remains equal with each rep. I'm attempting to treat ebx as a pointer to the address, but it's treating it as a value. I've been trying to correct this for awhile now... :icon_confused:
Title: Re: push 0
Post by: jj2007 on January 24, 2016, 08:04:44 AM
You should discover the joys of OllyDbg (http://www.ollydbg.de/version2.html). In your code, insert an int 3 (http://int%203) e.g. before the ReadFile call, then open the exe in Olly and hit F9. You will be just in front of the ReadFile. Hit F8 slowly and watch what happens, especially in the stack window in the lower right corner.
Title: Re: push 0
Post by: dedndave on January 24, 2016, 08:11:10 AM
"fopen" is a macro - part of the masm32 package

you can view it in the file \masm32\macros\macros.asm

  ; -------------------------------------------------------------------------
  ; open an existing file with read / write access and return the file handle
  ; -------------------------------------------------------------------------
    fopen MACRO filename
      invoke CreateFileA,reparg(filename),GENERIC_READ or GENERIC_WRITE,
                        NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
      EXITM <eax>       ;; return file handle
    ENDM


it opens the file, and returns the handle in EAX
Title: Re: push 0
Post by: Nyatta on January 24, 2016, 09:58:35 AM
Quote from: dedndave on January 24, 2016, 08:11:10 AM"fopen" is a macro - part of the masm32 package
Thank you, I've noticed this said many times, sorry you have to repeat it yet again, it is however very helpful.
    fopen MACRO filename
      invoke CreateFileA,reparg(filename),GENERIC_READ or GENERIC_WRITE,
                        NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
      EXITM <eax>       ;; return file handle
    ENDM

The macro runs something I was attempting to do earlier with no success: running the CreateFile function directly with the same parameters (not CreateFileA).

Quote from: jj2007 on January 24, 2016, 08:04:44 AMYou should discover the joys of OllyDbg (http://www.ollydbg.de/version2.html). In your code, insert an int 3 (http://int%203) e.g. before the ReadFile call, then open the exe in Olly and hit F9. You will be just in front of the ReadFile. Hit F8 slowly and watch what happens, especially in the stack window in the lower right corner.
That's amazing to watch, it'll be very helpful when I understand what I'm looking at a bit better.
My interpretation of what I am seeing is that I am changing the value of EBX which is acting to store the first 4 bytes of data opposed to storing the address and incrementing it as I had intended, not new news, but now I know what it looks like. From within the first loop:
ADD EBX, 4 ;Imm=4, EBX=088C0814
EBX is equal to 2188 and 2068, explaining why 2068 repeatedly increments by my addition value and not 2188.

This should work fine once I find some information on accessing data from addresses on registers as well as storing those addresses to the registers, I'll be back with a follow up post by tonight, hopefully sooner with proper code. :biggrin:

Edit:
Quote from: jj2007 on January 24, 2016, 08:04:44 AMHit F8 slowly and watch what happens, especially in the stack window in the lower right corner.
I feel so dense right now; I was expecting the data to be returned with an address, not pushed into the stack. Thank you so much.
Title: Re: push 0
Post by: Nyatta on January 24, 2016, 11:25:52 AM
Done much sooner than expected, this runs without missing a beat, hooray! :biggrin:
.686
.model flat, stdcall
option casemap :none

include \masm32\include\masm32rt.inc

.data
lb db 13, 10, 0
nFile db "My_File.raw", 0

.code
start:

inkey "Press any key to begin ...", 13, 10, 10

push fopen(offset nFile)
push 0
mov ecx, esp
push eax
mov edx, esp
invoke ReadFile, eax, ecx, 64, edx, 0

.if !eax
print LastError$(), 13, 10
.endif

push 0
call CloseHandle

pop ecx
push ecx
print str$(ecx), " bytes read.", 13, 10

pop ecx
push ecx
shr ecx, 1
print str$(ecx), " words to print.", 13, 10, 10

pop ecx
shr ecx, 2

pLoop:
pop ebx
push ecx
push ebx

and ebx, 0000FFFFh
print str$(ebx), 13, 10

pop ebx
shr ebx, 16
print str$(ebx), 13, 10
pop ecx
loop pLoop

print offset lb
inkey "Press any key to exit ...", 13, 10

exit

end start

Is the push 0 before the CloseHandle an appropriate practice?
Title: Re: push 0
Post by: dedndave on January 24, 2016, 12:13:32 PM
no - you want to pass the file handle to the CloseHandle function
Title: Re: push 0
Post by: Nyatta on January 25, 2016, 02:30:08 AM
Quote from: dedndave on January 24, 2016, 12:13:32 PMno - you want to pass the file handle to the CloseHandle function
Okay, I understand now, I misinterpreted what I was doing. I was oblivious to the fact invoke pushes each following value to the stack, as call directly calls the function without pushing values onto the stack. Additionally, I better understand what I'm looking at when I search for a function or macro, and I think I have bettered my understanding of proper more-so fluid register use. Take a look:
.686
.model flat, stdcall
option casemap :none

include \masm32\include\masm32rt.inc

.data
lb db 13, 10, 0
nFile db "My_File.raw", 0

.code
start:
inkey "Press any key to begin ...", 13, 10, 10

invoke CreateFileA,reparg(offset nFile),GENERIC_READ or GENERIC_WRITE,
NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL

push esp
push eax
invoke GetFileSize, eax, 0

pop esi
pop ecx
mov edx, ecx
add ecx, 4
invoke ReadFile, esi, ecx, eax, edx, 0

.if !eax
print LastError$(), 13, 10
.endif

invoke CloseHandle, esi

pop ebx
print str$(ebx), " bytes read.", 13, 10

shr ebx, 1
print str$(ebx), " words to print.", 13, 10, 10

mov ecx, ebx
shr ecx, 1
pLoop:
pop ebx
push ecx
mov esi, ebx

and ebx, 0000FFFFh
print uhex$(ebx), 13, 10

shr esi, 16
print uhex$(esi), 13, 10

pop ecx
loop pLoop
print offset lb
inkey "Press any key to exit ...", 13, 10

exit
end start

I was nearly about to make a reply asking for advice on it not printing the first 4 bytes of data, then I realized I had my ReadFile function set pointing both outputs to the same exact location, whoops! I hope and want to believe everything is in perfect working order now.
Title: Re: push 0
Post by: dedndave on January 25, 2016, 04:22:29 AM
when you write
    INVOKE  SomeFunction, Arg1, Arg2, Arg3, Arg4

the assembler actually generates this code
    push    Arg4
    push    Arg3
    push    Arg2
    push    Arg1
    call    SomeFunction


each argument can be a memory location (global variable), local variable, register, or constant (which may be an address)

in the case of CloseHandle, there is only one argument, the handle to be closed

for StdCall functions (most window API functions), the arguments are removed from the stack when the function returns
Title: Re: push 0
Post by: Nyatta on January 27, 2016, 12:15:23 PM
Alright, I feel I got a grasp on all this information; I utilized PUSH 0 and CloseHandle in the code within this post.

I worked on this a bit as a way of practice and it's pretty purposeless at the moment... I plan to write it to save to a file next, having it convert the entire file into a list of signed integers represented with ASCII split into labeled columns that narrate the audio channels.
;For use with Signed 16 or 24-BIT PCM .RAW audio files.
;Define BIT length of .RAW file with data variable "fType".

.686
.MODEL flat, stdcall
OPTION casemap :none

INCLUDE masm32rt.inc

.DATA
fName DB "Audio_Seg.raw", 0
fType DD 16

exitMsg DB 13, 10, "Press any key to exit ...", 13, 10, 0

.DATA?
fBuffer DB 1024 DUP(?)

.CODE
start:
INVOKE CreateFileA,reparg( OFFSET fName ),GENERIC_READ OR GENERIC_WRITE,
NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
PUSH EAX ;Store the handle to the stack.
PUSH 0 ;Create a buffer in the stack to retrieve count of BYTEs read.
MOV ECX, ESP ;Move the buffer / stack pointer to ECX.
MOV ESI, offset fBuffer ;Set data buffer pointer to ESI.
INVOKE ReadFile, EAX, ESI, 1024, ECX, 0

.IF !EAX ;Check for error,
POP EBX ;if true move BYTEs read out of the way
POP EBX ;retrieve handle,
INVOKE CloseHandle, EBX ;close handle,
inkey LastError$(), 13, 10 ;display the error
exit ;and close the program.
.ENDIF
POP EBX ;Move BYTEs read from stack to EBX.
print str$( EBX ), " BYTEs read.", 13, 10

POP ECX ;Move the handle from the stack to ECX
INVOKE CloseHandle, ECX ;and close the program's access to the file.

MOV EAX, fType ;Move the BIT size to EAX,
CMP EAX, 24 ;if it's 24-BIT
JE print24 ;jump to print24, else continue.
SHR EBX, 1 ;Divide BYTEs read by 2 to represent WORDs read.
print str$( EBX ), " WORDs to print.", 13, 10, 10

SHR EBX, 1 ;Divide WORDs read by 2 to represent DWORDs read.
inkey "Press any key to begin ...", 13, 10

MOV ECX, EBX ;Copy DWORDs to read to count register.
printData16:
PUSH ECX ;Push count to the stack.
MOV EAX, [ ESI ] ;Copy the DWORD at address within ESI to EAX.
MOV EBX, [ ESI ] ;Copy the DWORD at address within ESI to EBX.
AND EAX, 0000FFFFh ;Remove unneeded data from first WORD.
SHR EBX, 16 ;Rotate second WORD right into AX with zeros carried left.
MOVSX EAX, AX
MOVSX EBX, BX
print str$( EAX ), 13, 10 ;Print value 1.

print str$( EBX ), 13, 10 ;Print value 2.

POP ECX ;Retrieve the count from the stack.
ADD ESI, 4 ;Increment ESI to next DWORD.
LOOP printData16

inkey OFFSET exitMsg

exit
print24:
MOV EAX, EBX ;Move BYTEs read to EAX.
MOV EBX, 3 ;Move divisor, 3, to EBX.
DIV EBX ;Divide BYTEs read by 3 to represent TRIBYTEs read.
MOV EBX, EAX ;Move TRIBYTEs to read to EBX.
print str$( EBX ), " TRIBYTEs to print.", 13, 10, 10

inkey "Press any key to begin ...", 13, 10

MOV ECX, EBX ;Copy TRIWORDs to read to count register.
printData24:
PUSH ECX ;Push count to the stack.
MOV EAX, [ ESI ] ;Copy the DWORD at address within ESI to EAX
AND EAX, 00FFFFFFh ;Remove garbage data from current TRIBYTE.
.IF EAX > 8388607 ;If value is larger than number
ADD EAX, 0FF000000h ;convert to signed DWORD to print correctly.
.ENDIF
print str$( EAX ), 13, 10 ;and then print the resulting value.

POP ECX ;Retrieve the count from the stack.
ADD ESI, 3 ;Increment ESI to next TRIBYTE.
LOOP printData24

inkey OFFSET exitMsg

exit

END start

If you mind taking the time to skim this, is there anything obvious that I am doing incorrectly or inefficiently?

PSA: Anything above 16-BIT audio is overkill.
Title: Re: push 0
Post by: Grincheux on January 27, 2016, 03:44:21 PM
You should test the number of bytes read


cmp DWord Ptr [ecx],0
jne EOF

cmp DWord Ptr [ecx],1024
jne Error


The code is not very clear, comment it and rewrite it.
Mine is not always very easy to understand but here you make worst than I.
Title: Re: push 0
Post by: dedndave on January 27, 2016, 05:31:13 PM
this is not very sound practice
write the code so that it will work, pass or fail - and exit at the same point
notice that EBX, ESI, EDI, and EBP are preserved across API calls
you can use those resisters to hold values without PUSH/POP
.IF !EAX ;Check for error,
POP EBX ;if true move BYTEs read out of the way
POP EBX ;retrieve handle,
INVOKE CloseHandle, EBX ;close handle,
inkey LastError$(), 13, 10 ;display the error
exit ;and close the program.
.ENDIF
Title: Re: push 0
Post by: Nyatta on January 28, 2016, 01:27:12 AM
Quote from: Grincheux on January 27, 2016, 03:44:21 PMYou should test the number of bytes read


cmp DWord Ptr [ecx],0
jne EOF

cmp DWord Ptr [ecx],1024
jne Error


The code is not very clear, comment it and rewrite it.
Mine is not always very easy to understand but here you make worst than I.
It is intended to load any file size, but print a max of 1 KB of data, I don't understand the need to test the filesize for any means other than informing the user the file read was empty, as that would crash the program.
I added comments more as step-by-step means to keep track of what data's where, as this was started on my 3rd day using MASM or any assembler. :icon_confused:
POP EBX ;Move BYTEs read from stack to EBX.
print str$( EBX ), " BYTEs read.", 13, 10

CMP EBX, 0 ;If zero BYTEs are read
JE closeProg ;jump to closing sequence.


Quote from: dedndave on January 27, 2016, 05:31:13 PMthis is not very sound practice
write the code so that it will work, pass or fail - and exit at the same point
notice that EBX, ESI, EDI, and EBP are preserved across API calls
you can use those resisters to hold values without PUSH/POP
.IF !EAX ;Check for error,
POP EBX ;if true move BYTEs read out of the way
POP EBX ;retrieve handle,
INVOKE CloseHandle, EBX ;close handle,
inkey LastError$(), 13, 10 ;display the error
exit ;and close the program.
.ENDIF

What portion of this as practice isn't sound? Printing more data than the console holds within it's history?
My logic for split exit points was to avoid the additional JUMP where I felt it was unneeded (saving 3 clocks); I was under the impression that having a single exit point boiled down to personal preference, though it can result in lost readability. I'm trying my best to lean towards speed over readability where rational, in part to hardwire speed-based systems into my learning, but also to expand my comprehension. (I'd use a loop instead of repeating the same macro an irrational number of times.) I'm not trying to make it seem like anyone here is the bad-guy, I'm just explaining what I, most likely incorrectly, see here.
Thank you for pointing out the preservation of those registers, I will edit my code to incorporate those.
Title: Re: push 0
Post by: dedndave on January 28, 2016, 01:47:29 AM
conditional pushing and popping is asking for trouble (although, i have done it myself - lol)

and - having a common exit point makes more sense
try writing the code so there is only one close handle call
then, branch as required - perhaps to the exit point
Title: Re: push 0
Post by: dedndave on January 28, 2016, 01:50:22 AM
also - handles and counts, etc - don't need to always be kept in registers with push/pop
it sometimes makes for cleaner code to store the value in a memory variable
that way, push and pop mismatches are less likely to cause problems later on
Title: Re: push 0
Post by: dedndave on January 28, 2016, 01:53:37 AM
you may see some of us do the push/pop thing a lot
we are very comfortable with use of the stack  :biggrin:

it's not necessarily the best code, though
Title: Re: push 0
Post by: Nyatta on January 28, 2016, 02:23:38 AM
Quote from: dedndave on January 28, 2016, 01:47:29 AMconditional pushing and popping is asking for trouble (although, i have done it myself - lol)
The pop occurs and the program exits, but I understand you mean that in the broad scope of programming. Those pops were removed when I changed the "PUSH EAX" before "PUSH 0" to "MOV EDI, EAX", it cut down on few lines all around. :t
.IF !EAX ;Check for error,
INVOKE CloseHandle, EDI ;close handle,
inkey LastError$(), 13, 10 ;display the error
exit ;and close the program.
.ENDIF


Quote from: dedndave on January 28, 2016, 01:47:29 AMand - having a common exit point makes more sense
try writing the code so there is only one close handle call
then, branch as required - perhaps to the exit point
My code makes it impossible for CloseHandle to be called twice, and as I said, I feel I am increasing the clock count by 3 by branching when a condition that triggers closing procedures are met. It just sounds more like a decision between file-size and clocks... and I was practicing optimisation tactics here.
I'm uncertain on why I'm being told to branch beyond that, that's what I'm asking for information on.

Quote from: dedndave on January 28, 2016, 01:50:22 AMalso - handles and counts, etc - don't need to always be kept in registers with push/pop
it sometimes makes for cleaner code to store the value in a memory variable
I used a PUSH 0 and directed lpNumberOfBytesRead from the ReadFile function to this address because it requests a pointer to a variable, and not a register. If it were faster for the computer to read from the memory I would do that, until then I aim to stay away until I hit a dead-end and need to store some data.
Title: Re: push 0
Post by: Grincheux on January 28, 2016, 04:32:10 AM
After exit you don't POP EDI!
Title: Re: push 0
Post by: Nyatta on January 28, 2016, 07:11:05 AM
Quote from: Grincheux on January 28, 2016, 04:32:10 AM
After exit you don't POP EDI!
Doesn't the exit macro trigger clean-up of the process space before turning it over to the OS?
    exit MACRO optional_return_value
      IFNDEF optional_return_value
        invoke ExitProcess, 0
      ELSE
        invoke ExitProcess,optional_return_value
      ENDIF
    ENDM

The MSDN page on ExitProcess (http://"https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx") states:
"6. All of the object handles opened by the process are closed."
Does the stack have a handle that once cleared leaves the remanence within the RAM until it's either over-written or degrades?
Title: Re: push 0
Post by: qWord on January 28, 2016, 07:48:40 AM
Quote from: Nyatta on January 28, 2016, 07:11:05 AM
Quote from: Grincheux on January 28, 2016, 04:32:10 AM
After exit you don't POP EDI!
Doesn't the exit macro trigger clean-up of the process space before turning it over to the OS?
Yes. Also, ExitProcess does never return, thus following code would be dead code.

BTW, you could make your live much easier -- without any performance lost -- by using local variables rather than this error-prone,  unmaintainable and unreadably push/pop technique.



Title: Re: push 0
Post by: Nyatta on January 28, 2016, 08:15:03 AM
Quote from: qWord on January 28, 2016, 07:48:40 AMYes. Also, ExitProcess does never return, thus following code would be dead code.
Exactly my intended outcome if the condition is met, but from the looks of what I'm being told I used a fairly unconventional method.

Quote from: qWord on January 28, 2016, 07:48:40 AMBTW, you could make your live much easier -- without any performance lost -- by using local variables rather than this error-prone,  unmaintainable and unreadably push/pop technique.
No performance loss in mind I will certainly take a look as it sounds it will make the whole process far easier. Ollydbg is simplifying all of this by far have I make a mistake in the stack, it's getting far easier to track registers and the stack.
Isn't my buffer variable, "fBuffer", a local variable as it's data is written to as the program runs?
Title: Re: push 0
Post by: qWord on January 28, 2016, 09:04:46 AM
Local variables are local to a function or procedure and are setup on the stack when entering a function and destroyed when returning from it. MASM does that for you automatically when using PROCs with the keyword LOCAL (use OllyDbg to see how it is done exactly):
include \masm32\include\masm32rt.inc

.code
main proc
LOCAL hFile:HANDLE, buffer[123]:CHAR, numberOfBytesRead:DWORD

  mov hFile, fopen("...")
  ; ...
  invoke ReadFile, hFile, ADDR buffer, SIZEOF buffer, ADDR numberOfBytesRead, 0
  ; ...
 
  invoke CloseHandle, hFile
 
  exit
 
main endp
end main

Remarks that the total size of local variables in a PROC should not exceed 4096 Bytes (= size of 1 page), because there is a guard-page (access to that page cause an exception) below the stack that must be touched to increase the stack size (the system does that in the corresponding exception handler). There is also the possibility to allocate more than 4KB, but this requires to "probe the stack" ...  but that is another story.
Title: Re: push 0
Post by: jj2007 on January 28, 2016, 09:39:50 AM
Quote from: qWord on January 28, 2016, 09:04:46 AMthe total size of local variables in a PROC should not exceed 4096 Bytes (= size of 1 page), because there is a guard-page (access to that page cause an exception) below the stack that must be touched to increase the stack size (the system does that in the corresponding exception handler).

You can see the effect in the debugger when playing with the size of a local buffer:
include \masm32\include\masm32rt.inc

.code
MyTest proc arg
LOCAL LocBuffer[3*4096+3960]:BYTE ; try +3970
  lea eax, LocBuffer
  int 3 ; for Olly
  dec dword ptr [eax]    ; this modifies the start of the buffer
  ret
MyTest endp

start: invoke MyTest, 123
print "ok"
exit
end start
Title: Re: push 0
Post by: dedndave on January 29, 2016, 05:27:35 AM
if i  were to write such a program, it might look something like this...

        INCLUDE     \masm32\include\masm32rt.inc
        .686

;#################################################################################

FileSize  PROTO :LPSTR
OpnFile   PROTO :DWORD,:LPSTR

;#################################################################################

RawFileType     EQU 16
FileBufferSize  EQU 1024

;*********************************************************************************

OPF_FILECREATE  EQU GENERIC_WRITE or CREATE_ALWAYS                  ;(40000002h)
OPF_FILEWRITE   EQU GENERIC_WRITE or OPEN_EXISTING                  ;(40000003h)
OPF_FILEREAD    EQU GENERIC_READ or OPEN_EXISTING                   ;(80000003h)
OPF_FILERANDOM  EQU GENERIC_READ or GENERIC_WRITE or OPEN_EXISTING  ;(C0000003h)

;#################################################################################

        .DATA
        ALIGN   4

szFileName      db "Audio_Seg.raw",0

szFileErrMsg    db "Error Reading Input File"
szExitMsg       db 13,10,"Press any key to exit ...",13,10,0

;*********************************************************************************

        .DATA?
        ALIGN   4

hFileHandle     HANDLE ?
dwBytesRead     dd ?

FileBuffer      db FileBufferSize dup(?)

;#################################################################################

        .CODE

;*********************************************************************************

main    PROC

    INVOKE  FileSize,offset szFileName
    .if ecx==INVALID_FILE_ATTRIBUTES
        mov     edx,offset szFileErrMsg
    .else
        mov     ebx,FileBufferSize
        .if !(edx) && (eax<ebx)
            xchg    eax,ebx             ;EBX = lesser of file size or buffer size
        .endif
        INVOKE  OpnFile,OPF_FILEREAD,offset szFileName
        .if eax==INVALID_HANDLE_VALUE
            mov     edx,offset szFileErrMsg
        .else
            mov     hFileHandle,eax
            INVOKE  ReadFile,eax,offset FileBuffer,ebx,offset dwBytesRead,NULL
            push    eax
            INVOKE  CloseHandle,hFileHandle
            pop     eax
            .if eax

                ;add your code here
                ;to process data from the buffer

                mov     edx,offset szExitMsg
            .else
                mov     edx,offset szFileErrMsg
            .endif
        .endif
    .endif
    inkey   edx
    exit

main    ENDP

;*********************************************************************************

FileSize PROC lpszFileName:LPSTR

;File Size Function

;Call With: lpszFileName = address of zero-terminated filename string
;
;  Returns: EDX:EAX = file size
;           ECX     = file attributes, INVALID_FILE_ATTRIBUTES if file not found (-1)
;
;Also Uses: all other registers are preserved

;-----------------------------------------

    LOCAL   _w32fds :WIN32_FILE_ATTRIBUTE_DATA

;WIN32_FILE_ATTRIBUTE_DATA STRUCT
;  dwFileAttributes DWORD ?
;  ftCreationTime   FILETIME <>
;  ftLastAccessTime FILETIME <>
;  ftLastWriteTime  FILETIME <>
;  nFileSizeHigh    DWORD ?
;  nFileSizeLow     DWORD ?

;-----------------------------------------

    xor     ecx,ecx
    mov     _w32fds.dwFileAttributes,INVALID_FILE_ATTRIBUTES
    mov     _w32fds.nFileSizeHigh,ecx
    mov     _w32fds.nFileSizeLow,ecx
    INVOKE  GetFileAttributesEx,lpszFileName,ecx,addr _w32fds
    mov     edx,_w32fds.nFileSizeHigh
    mov     eax,_w32fds.nFileSizeLow
    mov     ecx,_w32fds.dwFileAttributes
    ret

FileSize ENDP

;*********************************************************************************

        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

OpnFile PROC    dwOpenFlags:DWORD,lpszFileName:LPSTR

;File Open Function

;Call With: lpszFileName = address of zero-terminated filename string
;           dwOpenFlags  = combined creation and access flags:
;                          bits 0 and 1   = dwCreationDisposition flag(s)
;                              typically, CREATE_ALWAYS to create a new file,
;                              or OPEN_EXISTING to open an existing file
;                          bits 30 and 31 = dwDesiredAccess flag(s)
;                              typically, GENERIC_WRITE to write to a file,
;                              or GENERIC_READ to read a file,
;                              or both flags for read/write ("random") access
;
;  Returns: EAX = file handle, INVALID_HANDLE_VALUE if unable to open file (-1)
;
;Also Uses: ECX and EDX are destroyed, all other registers are preserved

;-----------------------------------------

    mov     eax,[esp+4]
    xor     ecx,ecx
    movzx   edx,al
    and     eax,0C0000000h
    and     dl,3
    INVOKE  CreateFile,[esp+32],eax,FILE_SHARE_READ,ecx,edx,FILE_ATTRIBUTE_NORMAL,ecx
    ret     8

OpnFile ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

;#################################################################################

        END     main
Title: Re: push 0
Post by: Grincheux on January 29, 2016, 06:02:00 AM
Easy to read.
Just verify the number of bytes read.
Title: Re: push 0
Post by: dedndave on January 29, 2016, 06:23:22 AM
easy enough
just change this line

            INVOKE  CloseHandle,hFileHandle
            pop     eax
            .if eax


to this

            INVOKE  CloseHandle,hFileHandle
            pop     eax
            .if (eax) && (ebx==dwBytesRead)
Title: Re: push 0
Post by: Grincheux on January 29, 2016, 08:01:38 AM
That was a joke



test eax,eax
jz Eof

sub eax,FileBufferSize
jnz Error_1


and
mov     edx,_w32fds.nFileSizeHigh

It is ignored and the buffer will not be big enougth : 4 294 967 296 bytes if edx = 1 and eax = 0h
Title: Re: push 0
Post by: dedndave on January 30, 2016, 07:23:51 AM
if you read the code a little, you'll see that i get the file size
then, i determine the lesser of the file size or buffer size, and that read count value is in EBX
so, it's no problem to add the check   :P