i am still learning MASM+OPENGL.
when should there be "addr" or "offset" in front of a parameter in an INVOKE command?
i am confused ::)
ADDR should be used whenever the address of the variable needs to be calculated
this mainly applies to local variables
OFFSET should be used whenever it is a fixed address
.DATA
szString db 'Hello World',0
.CODE
Function PROC
LOCAL dwVariable:DWORD
INVOKE SomeFunc,offset szString,addr dwVariable
ret
Function ENDP
the local variable is actually accessed by something like [EBP-4], so the ADDR operator should be used
Use offset whenever you want the address of an item that is known at compile time, for example global strings or variables.
Use ADDR whenever your want the address of an item that has variable locations that can only be known at run-time. For example the address of an local variable on the stack.
Also note that ADDR usually generates an LEA EAX,[ebp +/- xxx] instruction and this trash EAX if you use for other tasks.
The difference between the CONTENT of a variable and WHERE it is. The notation ADDR in an invoke statement is WHERE the variable is in memory. An OFFSET refers to the location (WHERE) of a known address is that is created at assembly time.
can i say that it is also related to the invoked function? as some functions request an address, some functions request the content of an address?
still need some time to digest.
currently i am working on a small scale program and i use global variables mostly. i have no problem writing my own fucntions but when i invoke existing APIs, i need to swith on and off the "addr" to get it right.
i understand perfectly :bg
i had the exact same problem when i started out
i learned to read the MSDN documents carefully and to interpret the Hungarian Notation parameter names :U
if the name refers to a pointer, it usually starts with "lp" or "p"
("p" means pointer, "lp" means long pointer - same thing in win32)
otherwise, it wants the value - not a pointer
a good example might be WriteFile
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747%28v=vs.85%29.aspx
BOOL WINAPI WriteFile(
__in HANDLE hFile,
__in LPCVOID lpBuffer,
__in DWORD nNumberOfBytesToWrite,
__out_opt LPDWORD lpNumberOfBytesWritten,
__inout_opt LPOVERLAPPED lpOverlapped
);
in particular, the lpNumberOfBytesWritten parameter
it wants the address of a dword variable that will receive the number of bytes written to the file
if it is a local variable, ADDR is appropriate
your remark about ADDR applying to INVOKE is not strictly correct
however, that is where you are most likely to see it
some notes on Hungarian Notation...
http://msdn.microsoft.com/en-us/library/aa260976%28v=vs.60%29.aspx
http://en.wikipedia.org/wiki/Hungarian_notation
It's simple really, ADDR is just an invoke helper macro,
addr xyz
If xyz Resolves To Offset use
push offset xyz
else if it is a local varible use:
lea eax, xyz
push eax
else
show error
you can use offset explicitly to indicate that xzy is not a local variable so it is clearer for anyone looking at your code.
also, a lot of times you will use eax and addr in invoke, sometimes you will get an error "value of eax overwritten" if you remember my snippet from above you will know why.
while:
invoke myfunc, addr localvar, eax
will work,
this:
invoke myfunc, eax , addr localvar
will not
In an case. preserve eax before the invoke statement unless its contents are arbitrary.
Paul
Just in case you do have something important in eax:
mov eax, 123
lea edx, rc
invoke WhatEver, eax, edx ; same as addr rc
This works because addr rc would be coded as
lea eax, rc
push eax
You can do the same explicitly wirh another register in order to spare eax from being ruthlessly destroyed.
Also a nice trick: use ADDR for calculating a function's parameter:
; create buffer for string psz
invoke invoke szLen,psz
invoke invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT, ADDR [eax+1]
; the same as: alloc(ADDR [len(psz)+1])
I agree with drizz.
Something to keep in mind when you are calling high level functions like OpenGl or similar, there is no particular reason why you need to load the arguments into registers when normal memory operands work fine. The Microsoft reference material will tell you what is a VALUE and what is an ADDRESS and if you use LOCAL variables for the arguments you completely avoid the register overwrite problems.
Naming your variable according to what information they have in them makes your code a lot clearer and more reliable and you need only pick a naming scheme to do this.
Just as a suggestion you can do stuff like this.
LOCAL pMemory :DWORD ; a POINTER to a memory address
LOCAL loopcounter :DWORD ; a variable to contain the loop count VALUE
By writing the high level code in this format you have all of your registers available when you need to write high speed mnemonic code without any of the problems.
invoke GlobalAlloc,bytecount etc etc ....
mov pMemory, eax
Once you have the return value from GlobalAlloc() written to a POINTER you don't have to track the EAX register.
Once you have the code up and running reliably you can perform any close range optimisations you think will be useful but note that almost all high level functions are far slower than pure mnemonic code so there is often little gain by doing so.
Quote from: hutch-- on September 25, 2011, 10:55:33 PM
...but note that almost all high level functions are far slower than pure mnemonic code
Hey, that's new, can you give an example?
:bg
That's easy, disassembler kernel32.dll. It gets worse with later OS code, SEH, anti-hacking protection etc ....
Quote from: hutch-- on September 26, 2011, 12:13:03 AM
That's easy, disassembler kernel32.dll. It gets worse with later OS code, SEH, anti-hacking protection etc ....
That makes it clearer, thanks. I confused "high level function" with "high level language elements" like .if/.endif, .Repeat/.Until etc, which are obviously as fast as the "pure" mnemonic code they produce. Perhaps it is better to clarify that in a Campus thread :wink