News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

INVOKE and ADDR directives

Started by guro, April 06, 2011, 11:14:46 AM

Previous topic - Next topic

guro

Hi,
I have read somewhere that OFFSET is used to access the memory of global variables, while ADDR is used to access the memory of either global or local variables. So why in INVOKE statements we use ADDR to access the memory of an argument when a pointer is required (and the data is global)? Also, since the ADDR is capable to access both global and local why don't we use only ADDR directive?

dedndave

OFFSET uses the MOV instruction
ADDR uses the LEA instruction (Load Effective Address)
probably one clock cycle difference   :P
        mov     edx,offset SomeLabel
;or
        lea     edx,[ebp+4]  ;stack address of a local

however, the LEA is a little more versatile in what it can do

notice that, in an INVOKE directive, we intend to PUSH the operand...
        push    offset SomeLabel
;or
        lea     eax,[ebp+4]  ;stack address of a local
        push    eax

so code size is also a factor

it is good to know which kind of variable you are working with   :bg

hutch--

Hi guro,

The operator OFFSET literally means what it says, its a location in the executable file from its start address. Almost exclusively this means the address of data stored in either the initialised or uninitialised data sections of the file. Data stored this way has GLOBAL scope.

The MASM notation ADDR is an abstraction of an address which can be either an OFFSET or a dynamically created memory location on the stack, normally called a LOCAL variable.

When the variable is a LOCAL created on the stack, the underlying code uses LEA to get the effective address of that variable.


LOCAL myvar  :DWORD
.....
lea eax, myvar  ; load the address of myvar into the EAX register
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

guro

Please verify if the following is correct: When we use the INVOKE directive, it is actually expanded to a series of PUSH instructions followed by a CALL instruction to the selected API routine. If this is correct, then if the API routine has an argument that is a pointer for example to a string, which is declared to .data section, then it would be logical to access the memory address of the string by using OFFSET directive, like in PUSH OFFSET var , right? But we write INVOKE API_Name, ADDR var ! why? (i know you maybe have already explained it but i it's not clear to me yet!) .

Also, can you tell me what is the equivalent of an OFFSET and ADDR directives? I mean when the assembler matches the OFFSET var or ADDR var what code it generates? Does it depends from the context ?

@hutch

In the code you wrote don't we have to add the ADDR directive like in: lea eax, ADDR myvar ?

@ dedndave

OFFSET can be used in PUSH instructions also, not only in MOV. So what do you mean when you say that ADDR uses the LEA instruction, that is actually expanded to a LEA instruction internally in the assembler?

qWord

the ADDR-operator allows to addres local variables,which are relative to ebp.
QuoteLOCAL myvar:DWORD
...
invoke function,ADDR myvar
->
Quotelea eax,myvar ; whereas myvar is something like [ebp-12]
push eax
call function
FPU in a trice: SmplMath
It's that simple!

jj2007

Quote from: guro on April 06, 2011, 01:13:29 PMit would be logical to access the memory address of the string by using OFFSET directive, like in PUSH OFFSET var , right? But we write INVOKE API_Name, ADDR var !

The invoke macro doesn't care if you type addr or offset, except it chokes if you try to use offset on a local var.
It is a matter of taste. Personally, I use offset for global vars and addr for local vars, it reminds me of the variable's scope.

If you want to pass eax, you may get this message:
error A2133:register value overwritten by INVOKE

Quoteinclude \masm32\include\masm32rt.inc

MyTest   PROTO: DWORD, :DWORD

.code
AppName   db "Masm32 is great!", 0
Hello   db "A message:", 0

start:
   invoke MyTest, offset AppName, addr Hello
   exit

MyTest proc arg1:DWORD, arg2:DWORD
LOCAL buffer[1000]:BYTE
 invoke lstrcpy, addr buffer, arg2
 mov eax, arg1
 MsgBox 0, eax, addr buffer, MB_OK
 ret
MyTest endp

Try replacing eax with edx, and it works. The reason is that the invoke macro wants to use lea eax, buffer but then detects that you want to push eax afterwards.

redskull

OFFSET can only be used with static labels known as assemble-time, i.e. .data section labels, not LOCALS.  ADDR is smart enough to be used on either, but only as part of an INVOKE statment.  To my knowledge, there is no MASM-language construct to get the address of a LOCAL outside of an INVOKE, and you must manually use the LEA instruction to calculate it (which is what ADDR does 'behind the scenes' during invoke).

-r
Strange women, lying in ponds, distributing swords, is no basis for a system of government

guro

Hey, thanks all for the replies  :U

Now i understand that: The OFFSET directive is used to access global variables, while the ADDR is used to access both local and/or global variables. The INVOKE directive works fine either by using OFFSET (for global) or ADDR directives (global/local), but we prefer to distinct their usage to support readability. Finally, the ADDR is actually translated by the assembler to the pair of instructions: LEA eax, var; PUSH eax in order to determine the address of the local variable var, otherwise is translated like the OFFSET directive (that is the address is known at the compile time and is patched to the code).

One last question that came from the example of jj2007 : Does the assembler always use the EAX to push a local variable (when INVOKE is used) or we can set the register we want?

donkey

Quote from: redskull on April 06, 2011, 01:51:48 PM
ADDR is smart enough to be used on either, but only as part of an INVOKE statment.

Well, I wouldn't call ADDR smart, LEA is definitely not the way it should be done since it destroys a register with no good reason occasionally resulting in the error "Register value overwritten by INVOKE". We had this discussion in the compiler section quite a long time ago. A better way to accomplish the same thing is to use offsets from the contents of EBP or ESP. For example we know at assembly time that the first DWORD local (without the USES directive) is offset -4 bytes from the value in EBP, the second is -8 bytes, etc... So a more transparent way is to use the following:

; First DWORD local
push ebp
add DWORD PTR [esp],-4
call function


The LEA approach is only used in MASM (and perhaps JWASM) as far as I know.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

guro,

I did not answer the question for practice, I bothered to explain the SEMANTICS of the reserve work OFFSET for a reason.

> The OFFSET directive is used to access global variables

MASM has data section entries which are global in scope, OFFSET does not address GLOBAL variables, it literally gives you an OFFSET from a known location, the executable file's start address. OFFSET means "HOW FAR" a data section extry is from the executable start address.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

guro

ok i understand now that is wrong to say that: "OFFSETdirective is used to access global variables". what actually happens is to use distances from base address (the executable load address) and find out the correct address of the global variable by adding its 'offset' to the base address. Is that what you mean?

Does the INVOKE uses always the EAX register in case one of its arguments is local and has to resolve its address?


donkey

Quote from: hutch-- on April 06, 2011, 02:22:26 PM
MASM has data section entries which are global in scope, OFFSET does not address GLOBAL variables, it literally gives you an OFFSET from a known location, the executable file's start address. OFFSET means "HOW FAR" a data section extry is from the executable start address.

Offset gives a segment relative offset, it has nothing to do with the start address of the executable. In the FLAT programming model it is the offset from 0. For example

push offset Here
Here:
pop eax

Assembles to:

01351021   . 68 26103501    PUSH TestOffs.01351026
01351026   . 58             POP EAX


Here: is certainly not 0x01351026 bytes from the start address of the executable.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

guro

It's +0 from the EIP's value ?

@donkey

You say that in FLAT programming model it is the offset from 0 and not relative to a segment value?

clive

To use the EIP relative encoding<G>

00000000  E8 00000000 Start:  call    Here
00000005  58 Here:   pop     eax
It could be a random act of randomness. Those happen a lot as well.

donkey

Quote from: guro on April 06, 2011, 02:45:52 PM
It's +0 from the EIP's value ?

@donkey

You say that in FLAT programming model it is the offset from 0 and not relative to a segment value?

Yes and no, the OFFSET is still relative but since the segment register is set to zero it is equivalent to linear addressing. For example DS:040000 is the same as CS:040000 since both CS and DS contain 0. In the Windows FLAT model, only the FS segment register contains a value other than zero, which is why a segment override is needed for that particular one.

Values relative from EIP are used in CALL and short/near jumps.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable