What is the difference between these two? I assume ReadFile is a call to the Win 32 API function with the same name? Is fread the equivalent of a macro that calls ReadFile in the end? I can't find the include-files where fread is defined. Where should I search for it?
Also, here is my code, it works but you guys can probably see bad standards in it. Feel free to let me know about it.
include \masm32\include\masm32rt.inc ; All includes needed for comon MASM32-programming
.code
start:
call main
inkey ; Wait for input to close console
exit
main proc
local hFile :HANDLE
local count :DWORD
local buffer :PTR BYTE
mov hFile, fopen("008.dat")
mov count, fread(hFile, addr buffer, 1001)
fclose hFile
ret
main endp
end start
\masm32\macros\macros.asm:
; ------------------------------------------------
; read data from an open file into a memory buffer
; ------------------------------------------------
fread MACRO hFile,buffer,bcnt
LOCAL var
.data?
var dd ?
.code
invoke ReadFile,hFile,buffer,bcnt,ADDR var,NULL
mov eax, var
EXITM <eax> ;; return bytes read
ENDM
It is actually not the most efficient code, as it needs a global variable. Here is an alternative:
push eax ; create a slot for bytes read
mov eax, esp
invoke ReadFile, hFile, lpBuffer, bytes, eax, 0
pop eax ; bytes read
Masm use macro.
When you don't know if it is a macro or a function proceed as follow.
Put .NOLIST a the start of your source
Before the instruction you want to know:
.LISTALL
Just after the instruction you want to know:
.NOLIST
Made a listing.
and in the listing ,if it is a macro ,you see his code expanded as this
Quote
.NOLIST
.LISTALL
SET_CRT_DEBUG_FIELD _CRTDBG_LEAK_CHECK_DF
000002ED 6A FF * push -000000001h
000002EF E8 00000000 E * call _CrtSetDbgFlag
000002F4 83 C4 04 * add esp, 000000004h
1 invoke _CrtSetDbgFlag,_CRTDBG_REPORT_FLAG
1 ;Returns the previous state of _crtDbgFlag
000002F7 83 C8 20 1 or eax,_CRTDBG_LEAK_CHECK_DF
000002FA 50 * push eax
000002FB E8 00000000 E * call _CrtSetDbgFlag
00000300 83 C4 04 * add esp, 000000004h
1 invoke _CrtSetDbgFlag,eax
.NOLIST
push eax ; create a slot for bytes read
mov eax, esp
invoke ReadFile, hFile, lpBuffer, bytes, eax, 0
pop eax ; bytes read
Jochen, better if you return the count in ECX
EAX holds the status :U
another way to go...
push eax ; create a slot for bytes read
mov eax, esp
invoke ReadFile, hFile, lpBuffer, bytes, eax, 0
pop ecx ; bytes read
cmp ecx,bytes
now, the macro returns with ZF set if bytes requested = bytes read
and, EAX has the return status
Now, pretend I prefer to call ReadFile directly, like this:
mov hFile, fopen("fread-readfile.dat")
push 0
push 81
push ptr$(lpBuffer)
push hFile
Wouldn't it be faster? This compiles, but gives some kind of error in runtime, the error looks to be memory-related?
the small differences in speed are minimal compared to the time consumed by the ReadFile call
macros are handy - they can save you some typing
however, when you are learning how things work, they hide a lot of stuff
Dave: Yeah, that is one of the reasons I refuse to use macros. Got it to work by the way, had forgot one parameter when calling. But bellow code both compiles and runs without error.
mov hFile, fopen("fread-readfile.dat")
push 0
push bytesRead
push ptr$(lpBuffer)
push 81
push hFile
call ReadFile
i noticed that, in your original post, you allocated 1 byte for the buffer :P
INCLUDE \masm32\include\masm32rt.inc
;----------------------------------------------------------
BYTES_TO_READ EQU 1001
BUFFER_SIZE EQU 1024
;----------------------------------------------------------
.DATA
szFileName db '008.dat',0
szErrOpen db 'Error Opening File',13,10,0
szErrRead db 'Error Reading File',13,10,0
szSuccess db 'Read File Successful',13,10,0
;----------------------------------------------------------
.CODE
main PROC
LOCAL hFile:HANDLE
LOCAL Count:DWORD
LOCAL Buffer[BUFFER_SIZE]:BYTE
INVOKE CreateFile,offset szFileName,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
mov edx,offset szErrOpen
or eax,eax
jz Report2
mov hFile,eax
INVOKE ReadFile,eax,addr Buffer,BYTES_TO_READ,addr Count,NULL
mov edx,offset szErrRead
or eax,eax
jz Report1
mov edx,offset szSuccess
Report1:
push edx
INVOKE CloseHandle,hFile
pop edx
Report2:
print edx
ret
main ENDP
;----------------------------------------------------------
Start: call main
inkey
exit
;----------------------------------------------------------
END Start
Quote from: dedndave on October 31, 2011, 07:22:07 PM
Jochen, better if you return the count in ECX
EAX holds the status :U
Yes, but the status is pretty useless:
QuotelpNumberOfBytesRead
Points to the number of bytes read. ReadFile sets this value to zero before doing any work or error checking
Comparing NumberOfBytesRead to zero or to the requested count is therefore a safer way to check for errors.
Quote from: Ani_Skywalker on October 31, 2011, 07:58:04 PM
push 0
push bytesRead <<<<<<<<< sure?
push ptr$(lpBuffer) <<<<<<<<< attention dangerous macro!
push 81
push hFile
call ReadFile
Quote from: jj2007 on October 31, 2011, 08:23:18 PM
push 0
push bytesRead <<<<<<<<< sure?
push ptr$(lpBuffer) <<<<<<<<< attention dangerous macro!
push 81
push hFile
call ReadFile
Well, not sure, but I use an uninitialized variable, should be almost as good as setting it to zero, or? The docs suggest zero though: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
Ah, why is it a dangerous macro and how can I turn that line to pure assembly?
Quote from: Ani_Skywalker on October 31, 2011, 10:25:12 PM
Quote from: jj2007 on October 31, 2011, 08:23:18 PM
push 0
push bytesRead <<<<<<<<< sure?
push ptr$(lpBuffer) <<<<<<<<< attention dangerous macro!
push 81
push hFile
call ReadFile
Well, not sure, but I use an uninitialized variable, should be almost as good as setting it to zero, or? The docs suggest zero though: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
Check the order of your paras. The doc uses the invoke order, you are pushing, so you must invert everything.
Quote
Ah, why is it a dangerous macro and how can I turn that line to pure assembly?
Just pulling your leg... but you better check what the macro does.
Look at the file macros.asm in your masm32\macros directory to see the code of all the macros and how they are done :)
local buffer[1024]:BYTE
local bytesRead:DWORD
...
push 0
lea eax,bytesRead
push eax
push SIZEOF buffer
lea eax,buffer
push eax
push hFile
call ...
Quote from: jj2007 on October 31, 2011, 10:35:09 PM
Check the order of your paras. The doc uses the invoke order, you are pushing, so you must invert everything.
But isn't that exactly what I am doing? I push the first parameter last, the second to first second to last, and so on? Then when the cpu reads it from the stack it should come in reverse order, meaning the first one comes first etc. Or have I got it wrong?
QuoteBOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
so it would be:
push lpOverlapped
push lpNumberOfBytesRead
push nNumberOfBytesToRead
push lpBuffer
push hFile
call ReadFile
Of course you have to push the address of buffers were needed
Quote from: Gunner on October 31, 2011, 10:50:20 PM
so it would be:
push lpOverlapped
push lpNumberOfBytesRead
push nNumberOfBytesToRead
push lpBuffer
push hFile
call ReadFile
Which is what I am doing, right?
Quote from: qWord on October 31, 2011, 10:39:52 PM
local buffer[1024]:BYTE
local bytesRead:DWORD
...
push 0
lea eax,bytesRead
push eax
push SIZEOF buffer
lea eax,buffer
push eax
push hFile
call ...
qWord: As always, interesting posts. I have 2 questions about it:
1. Why do we need to load effective address before push, isn't enough that the value is poped upon call?
2. I understand it as (right or wrong) that we can use mov instead of lea? Which one is preferable? Which one uses least clock cycles?
I never seem to find where to look for clock cycles in Intel Software Developers Manual. Looking at page 649 in the pdf, I find lea explained, but nothing about clock cycles..
Your beginning right? Stop trying to save clock cycles...
You use lea because the buffer is local, and ReadFile needs an address. Now if the buffer was global you CAN'T just push the variable (you would be pushing the value) you would have to push offset variable
Quote from: Gunner on October 31, 2011, 11:58:54 PM
Your beginning right? Stop trying to save clock cycles...
Yes but I disagree with you here. If you learn something wrong to start with, it's just even harder to get it right the second time. Relearning is much harder then learning. I'll rather have a very slow start and take my time then start coding windows frames using invokes and the Win 32 api. That kind of programming is what I have C and Java for :)
Thanks for the answer though, appreciated!
Quote from: Ani_Skywalker on October 31, 2011, 10:56:47 PM
Quote from: Gunner on October 31, 2011, 10:50:20 PM
so it would be:
push lpOverlapped
push lpNumberOfBytesRead
push nNumberOfBytesToRead
push lpBuffer
push hFile
call ReadFile
Which is what I am doing, right?
No. What you are doing is as follows:
Quote from: Ani_Skywalker on October 31, 2011, 07:58:04 PM
Dave: Yeah, that is one of the reasons I refuse to use macros. Got it to work by the way, had forgot one parameter when calling. But bellow code both compiles and runs without error.
mov hFile, fopen("fread-readfile.dat")
push 0 ; lpOverlapped
push bytesRead ;lpNumberOfBytesRead, i.e.LONG POINTER TO ...
push ptr$(lpBuffer) ; should be nNumberOfBytesToRead, i.e. the numberof bytes
push 81 ; should be lpBuffer, i.e LONG POINTER TO ...
push hFile ; that one is correct.
call ReadFile
Amazing and nice looking site please love it and make more effective.. keep it up baby..
URL removed.
We do not allow this forum to be used for advertising.
Quote from: Ani_Skywalker on October 31, 2011, 11:50:24 PM1. Why do we need to load effective address before push, isn't enough that the value is poped upon call?
2. I understand it as (right or wrong) that we can use mov instead of lea?
1. if the address is unknown at compile time (local -> ebp-relative -> esp-relative), you must calculate it at runtime - LEA can do this.
2. only if not referencing a local variable
(Also, to make it clear: LEA is an arithmetic instruction, which never access any memory)
Quote from: Ani_Skywalker on November 01, 2011, 12:02:16 AM
I'll rather have a very slow start and take my time then start coding windows frames using invokes and the Win 32 api. That kind of programming is what I have C and Java for :)
Like you, I'm something of a n00b to Windows assembly-language programming (though I've been writing DOS-based '86 assembly for a long time). I think you may have a somewhat distorted picture of what INVOKE does.
When I started Win32 asm just a couple months ago, I had never used INVOKE, just plain CALLs. I would recommend to you that you use it. Why?
First of all, it incurs absolutely no more overhead than what you're doing when you push parameters "by hand". That's basically all it does, apart from some extra code that may occasionally be generated to move static addresses into a register (EAX) and then pushing the register. So all in all, it's pretty benign. It's not doing a lot of stuff "behind the curtain." In any case, I would also recommend that you code the two methods (pushing by hand vs. INVOKE) and look at the generated code in the listing file to see exactly what's being generated.
The reason I like to use INVOKE is that it makes it a hell of a lot easier to keep all those pesky parameters straight, especially for functions like CreateWindowEx() that take a lot of them. I HATE trying to chase down crap like [ESP + xxx]; honestly, it makes my head hurt, and I don't code well with headaches. Spend less time trying to be a macho "down-to-the-bare-metal" assembly programmer, and you'll have more energy to devote to debugging the damn program and dreaming up new stuff. It's hard enough to keep track of stuff as it is; why make it harder?
You'll still get very slick, streamlined, slim and fast code out of it, even if you let the assembler help you now and then. Myself, I draw the line at macros (I only use ones I invent myself) and the .if-.else-.endif constructs. Hell, if I wanted to code like that, why not just use C++?
I see that the no use of invoke generate only questions and problems.Thinks are simple using:
Quote
INVOKE ReadFile, hFile,addr Buff, NumberOfBytesToRead,\
addr NumberOfBytesRead ,0
and what happen with the no use of invoke if you made a mistake ?
Invoke verify (at compile time) if the size of the parameter is correct and if the number of parameters is correct.
Use the push method at your own risks.
there are times when using PUSH/CALL is advantageous
in certain cases, i may want to push values while they are in register for a call later
or - there may be times when i want to perform calculations or call other functions between parameter pushes
one example is if some of the parameters are in a table, and i want to use LODSD to get them
these are somewhat advanced tecniques, as they require extreme vigilance over the stack and, perhaps, registers
otherwise, use INVOKE :U
not only does INVOKE check the parm count for you, but it is easier to read and maintain
Ob1 Cannoli: "Become one with The Stack, my young padawan learner"
(http://www.masm32.com/board/index.php?action=dlattach;topic=17652.0;id=9901)
Quote from: NoCforMe on November 01, 2011, 03:12:19 AM
It's hard enough to keep track of stuff as it is; why make it harder?
Let's take this discussion once and for all :)
Answer to your question is: Because I like the learn->understand->do chain better then the learn->do chain.
Look at my original post in this thread, I used fread to read a file instead of the native ReadFile. After that it took almost 2.5 pages on this forum to sort out all questions about push/call operations. If I was about to code something useful in assembly, you probably would be right. At the moment, I'm just solving Project Euler problems to l-e-a-r-n.
Also, it has never been about being a "macho" guy. I ask noobish questions on open forums and show my lack off knowledge, hoping more experienced people have the time and willing to share their knowledge with me so I can learn and improve - that's the exact opposite of being "macho".
That said, I appreciate that shared your experience of the MASM-macros from an assembly programmers point of view.
well - a lot of it has to do with personal choice
my choice - if it isn't speed critical, make it small
but then, programming is not my business
i am not worried about someone else maintaining my code
many of the professional programmers look at it this way:
if it isn't speed critical, make it as clear and readable as practical (maintainable)
there are other choices, as well
macros - how often - when
basically, i use macros for something quick - or to debug code
otherwise, i prefer to write my own stuff :P
i also do not like indented lines or if/else/elseif/endif structures
it is all a matter of personal choice
each of us will defend our choices to the death :lol
Quote from: Ani_Skywalker on November 01, 2011, 11:56:37 AM
Quote from: NoCforMe on November 01, 2011, 03:12:19 AM
It's hard enough to keep track of stuff as it is; why make it harder?
Let's take this discussion once and for all :)
Answer to your question is: Because I like the learn->understand->do chain better then the learn->do chain.
Look at my original post in this thread, I used fread to read a file instead of the native ReadFile. After that it took almost 2.5 pages on this forum to sort out all questions about push/call operations. If I was about to code something useful in assembly, you probably would be right. At the moment, I'm just solving Project Euler problems to l-e-a-r-n.
Also, it has never been about being a "macho" guy. I ask noobish questions on open forums and show my lack off knowledge, hoping more experienced people have the time and willing to share their knowledge with me so I can learn and improve - that's the exact opposite of being "macho".
That said, I appreciate that shared your experience of the MASM-macros from an assembly programmers point of view.
Whoa just a second there, pardner. I meant no disrespect to you. Your point about learning is well taken. It's good go know what's actually going on in your code, which is why I suggested looking at the assembler listing if you do use INVOKE.
And I certainly wasn't accusing you of macho programming. There are those who practice it, and I just wanted to warn you of that tendency, is all.
Good luck with your programming learning. Once you get over the hump you should be able to have fun with it.
Oh, I didn't take it as an insult. The reason why I gave such a long answer is that several people suggested similar approaches to me here, so I just wanted to sort out why I am asking all this dumb questions right now (besides the obvious fact that I am a noob) :)
And like I wrote, I appreciated your post. Thanks once again!