I have many questions concerning LOCAL, and how to use LOCAL variables...so bare with me.

Is LOCAL something hutch has come up with in his package?

I have seen alot of code that uses this syntax, and I have also seen .data, .data? segments within proc's

I was just wondering the benefits of using one over the other?

I've tried searching for LOCAL, but you can imagine what all popped up :) I looked through a bunch of the pages but I still haven't found anything. I'm also looking through AOA by Hydes

Thanks for any help,
gorshing
Posted on 2002-06-21 10:01:43 by gorshing
LOCAL variables are allocated at runtime. They are not on any segments. They are usually used within a procedure. When a procedure is called, the stack is used to allocate memory for the local variables. The benefit is the same concept as other HLL, local variables are confined to the procedure, you cannot use them globally. I'm sure you understand the bane of using global variables(data, data? ... ) don't you?

And no, this is not something hutch-- has come up in his package :)
Posted on 2002-06-21 10:15:29 by stryker
i understand how local variables are allocated/deallocated and everything but I'm wanting a string prompt to be local

I'm wanting to ask the user something, display a title in a message box, whatever, but I don't want the string to be global, how do I do this. Please feel free to put me in my place, I've tried the search but nothing and I'm looking through Icz tut's and still haven't seen anything like this

Did that make any sense?
gorshing
Posted on 2002-06-21 14:56:43 by gorshing
Warning :: there are some "ads"(xcall) here!!! :)

[size=9].686

.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDE \masm32\INCLUDE\windows.inc
INCLUDE \masm32\INCLUDE\kernel32.inc
INCLUDE \masm32\INCLUDE\user32.inc
INCLUDELIB \masm32\lib\user32.lib
INCLUDELIB \masm32\lib\kernel32.lib

@align MACRO val:REQ, sz:REQ
EXITM %(((val+sz-1)/sz)*sz)
ENDM

@str MACRO _str:VARARG
LOCAL @@1
IF @InStr(1, <_str>, <!"> )
.DATA
@@1 DB _str, 0
.CODE
EXITM <OFFSET @@1>
ELSE
EXITM <_str>
ENDIF
ENDM

xcall MACRO function:REQ, parameters:VARARG
LOCAL psize, paddr, plen
IFNB <parameters>
psize = 0
FOR param, <parameters>
psize = psize + 4
ENDM
psize = @align((psize+4), 4)
psize = psize - 4
sub esp, psize
psize = 0
FOR param, <parameters>
IF @SizeStr(<param> ) GT 4
paddr SUBSTR <param>, 1, 5
IFIDNI paddr, <ADDR >
paddr SUBSTR <param>, 6, @SizeStr(<param>) - 5
lea eax, paddr
mov DWORD PTR [esp+psize*4], eax
ELSE
mov DWORD PTR [esp+psize*4], @str(<param>)
ENDIF
ELSE
mov DWORD PTR [esp+psize*4], @str(<param> )
ENDIF
psize = psize + 1
ENDM
ENDIF
call function
ENDM

.CODE

[color=#3366FF]myfunc PROC

push ebp
mov ebp, esp

sub esp, 20 ;Allocate 20 bytes for our variable

mov DWORD PTR [ebp-20], "lleH"
mov DWORD PTR [ebp-16], "rC o"
mov DWORD PTR [ebp-12], " leu"
mov DWORD PTR [ebp-8], "lroW"
mov BYTE PTR [ebp-4], "d"
mov BYTE PTR [ebp-3], 0
lea eax, [ebp-20] ;Load the address of the variable
xcall MessageBox, 0, eax, "Title", MB_OK

mov esp, ebp
pop ebp
retn

myfunc ENDP[/color]

START:
xcall myfunc
xcall ExitProcess,NULL
END START[/size]


    [*]I seem to forget on how to declare a local array... LOCAL msgtext : BYTE [20] ???[*]The "title" string is on your .data section while your message box text is local. ;)
Posted on 2002-06-21 15:17:33 by stryker
I have a macro to do this:
    mov     DWORD PTR [ebp-20], "lleH"

mov DWORD PTR [ebp-16], "rC o"
mov DWORD PTR [ebp-12], " leu"
mov DWORD PTR [ebp-8], "lroW"
mov BYTE PTR [ebp-4], "d"
mov BYTE PTR [ebp-3], 0
...I'll post it when I get home. :grin: :grin:
Posted on 2002-06-21 15:24:20 by bitRAKE
I had all of my variables in the LOCAL big time... this was my BIGGEST concern all last year. Than i went global because someone said it don't matter, it will all will end up inside the .data - .data? section and also said that GLOBAL if faster...

Now a year latter i see the word "BANE"

Now i am really confuse... stryker could you please explain this a bit more........Is it safer or what?????

Thank you
Posted on 2002-06-21 19:58:58 by cmax
Global variables can be changed anytime during the execution of the code, thus are more prone to be overwritten with other values, the probabilities that this might happen increases everytime the complexity of a program arises.

Local variables cannot be changed outside a procedure. When the procedure is finished the local variables are deallocated or removed from the stack. You can easily pinpoint when an error occurs during a particular routine.

It's actually based on your preference, if you think you can make every variable global and be very vigilant on how you use those variables then make all variables global. Sometimes in a huge project, it'll be hard to pinpoint errors, since there would be a lot of variables involved, in my experience, I keep all variables that are only used by a particular procedure as local.

On this example:

There's no point in making the rect structure declaration global. If you make it global, programmers who wants to use your routine will have to setup a global rect structure declaration on their code. And this is extra work, make it hard on yourself but don't make it hard for others as much as possible.

So the answer to your question is :: It's a matter of preference. But the preferred way is to confine variables as locals in any way you can.
Posted on 2002-06-21 20:27:57 by stryker
Thanks stryker
Posted on 2002-06-21 20:48:24 by cmax
gorshing,

There are only 2 places where you can normally store string data, in the data section(not segment) using the (name DB "string",0) syntax or you can directly embed the string in the code section,


jmp @F
name DB "string",0
@@:

When you use a LOCAL variable you simply allocate uninitialised data on the stack and while its easy enough to allocate string space in a procedure,


LOCAL String_Space[128]:BYTE

There is no immediate way to fill that string space with data unless you copy it from either the data section or embed it in the code section.

Data in the code section is normally READ ONLY so its use depends on what you want to do with it.

The convenient way to handle data in a proc is to use the following syntax,


.data
name DB "string",0
.code

as MASM resolves the data into the .DATA section at assembly time.

Regards,

hutch@movsd.com
Posted on 2002-06-21 21:36:56 by hutch--
FillString MACRO Arr, Txt

LOCAL i,j
i = 0
j = 0
FORC var, <&Txt>
j = ('&var' SHL ((i AND 3)*8)) + j
IF (i AND 3) EQ 3
mov DWORD PTR Arr[(i AND -4)], j
j=0
ENDIF
i = i + 1
ENDM

IF (i AND 3) EQ 0
mov BYTE PTR Arr[i], 0
ELSEIF (i AND 3) EQ 1
mov WORD PTR Arr[i-1], j
ELSEIF (i AND 3) EQ 2
mov WORD PTR Arr[i-2], j
mov BYTE PTR Arr[i], 0
ELSEIF (i AND 3) EQ 3
mov DWORD PTR Arr[(i-3)], j
ENDIF
ENDM
You can easily create LOCAL strings:
GetPics PROC thePath:DWORD

LOCAL PathPart[MAXPATH]:BYTE

FillString PathPart, "\images\"

FillString PathPart[eax], "\images\"
Posted on 2002-06-21 21:40:58 by bitRAKE
Hrm, why do the "put-string-in-stackspace" way? It will generate
more code and execute slower. The only 'benefit' I can see is that
it will add some code obfuscation (and the string wont show up in
normal string reference analysers), but it wont fool 'determined people' :).
Yes, using LOCAL variables is good most of the time, but there are
limitations...

It can often be useful to have strings that are local in scope, though...
but you don't need to put them on the stack to achieve this :).

It's usually not too hard to determine whether to use local or global
variables. If you have stuff that is only needed inside a proc, make
it local. If you need a large amount of temporary workspace in a proc,
it can sometimes be advantegous to make that buffer global, unless of
course you need to be threadsafe.
Posted on 2002-06-22 05:13:04 by f0dder
f0dder, it will execute slower? Why don't you test that and get back to me with your finding? :) :) Thanks for saying at least one positive thing about it (threadsafe). :alright: I mainly did it because I could. :tongue:
Posted on 2002-06-22 08:03:06 by bitRAKE
well, assembling strings on the stack like that ought to be slower
than a "mov esi, offset myDataString" :). But of course it depends
on what you do. And it definitely is *interesting*, if you want to
write eg a code mutator you'll have to either assemble data this
way, or have a more complex mutation engine.

I just don't see a use for it in general programs, that's all.
Posted on 2002-06-22 09:59:47 by f0dder
f0dder, just use lstrcat if it makes you feel better, but the processor can do quite a few immediate moves in the time it takes to just call and return from that function - not to mention the cache miss on the constant data and data cache polution for intialization code. This is just a simple example - I trust you can extrapolate to more complex coding situations. :)
Posted on 2002-06-22 10:21:21 by bitRAKE
Well sure, for appending to strings this *is* useful - I was talking
about constructing string constants on the stack (ie, "local") instead
of just having them in the .data section. String appending is obviously
quite a different matter :).
Posted on 2002-06-22 10:45:24 by f0dder
Gosh, I thought the primary use of local was for accessing
"variables" by name that were passed on the stack by
invoke (the calling code)? Am I wrong? Variables in code and data
I understand. Double work if variable is of static value - or contains default values to make it a local - I think.
Posted on 2002-06-22 16:16:59 by Roy Cline
Gosh, I thought the primary use of local was for accessing
"variables" by name that were passed on the stack by
invoke (the calling code)?
You mean like this:
myfunc PROC param1:DWORD, param2:DWORD

mov eax, param1
ret
myfunc ENDP

...

invoke myfunc, 1, 2
Actually param1/param2 isn't a local variable but a value that points to the parameters on the stack. In this case:
1. Non-Frame Based:


param1 == DWORD PTR [esp+4]
param2 == DWORD PTR [esp+8]

2. Frame Based:

param1 == DWORD PTR [ebp+8]
param2 == DWORD PTR [ebp+12]
:)
Posted on 2002-06-22 18:48:33 by stryker

Gosh, I thought the primary use of local was for accessing
"variables" by name that were passed on the stack by
invoke (the calling code)? Am I wrong? Variables in code and data
I understand. Double work if variable is of static value - or contains default values to make it a local - I think.


this is how i access variables passed by invoke:



invoke EagerBeaver,-1
...

EagerBeaver proc IsEagerBeaver:DWORD
mov eax,IsEagerBeaver
shl IsEagerBeaver,3
ret
EagerBeaver endp
Posted on 2002-06-22 18:49:59 by jademtech
ok, so I can do something like

main proc
.data
szText db "This is a test", 0
.code
invoke MessageBox, NULL, offset szText, offset szText, MB_OK
ret
main endp

but is szText global? I can't access it from another proc but ... well ... I guess my question would be why would I want/need to use the LOCAL name:BYTE instead of using the sections like hutch said -> using the name db "Foobar", 0 in the data section?

Is this because each proc has it's own sections? And that using LOCAL pushes(ofcourse) that on the stack?

If this question has been answer before ( some tut or anything ) let me know and I'll go read. I've been looking but can't find anything anywhere.

Thanks for any help,
gorshing

PS ( or whatever we call it these days ) I understand the use of the stack/global variables from a C/C++ point of view, but I'm trying to understand excatly what's going on. Thanks again
Posted on 2002-06-26 12:27:40 by gorshing
but is szText global? I can't access it from another proc
Yes, szText is global, and you can access it in any procedure.
I guess my question would be why would I want/need to use the LOCAL name:BYTE instead of using the sections like hutch said -> using the name db "Foobar", 0 in the data section?
because you asked something like it :). Quoting from your previous thread
I'm wanting to ask the user something, display a title in a message box, whatever, but I don't want the string to be global, how do I do this. Please feel free to put me in my place, I've tried the search but nothing and I'm looking through Icz tut's and still haven't seen anything like this
Is this because each proc has it's own sections?
Nope, procedures does not have its own sections
And that using LOCAL pushes(ofcourse) that on the stack?
You mean the data is pushed? Yes and No.

The answer is no when doing it like this ::

sub esp, 20 ;will just allocate 20 bytes and this data is garbage.
mov DWORD PTR , "lleh" ;is putting the string "lleh" on top of the stack. This will mimic push 6C6C6548h

this will just allocate the size needed nothing more, putting the data on the stack is another aspect.

Yes if done like this:

push 6C6C6548h ;"allocate" and place the string "lleh" on the top of the stack.

Now you might question me like this :: Why would I choose the above style of doing a sub-mov when I can push?

The answer is to remove dependencies on esp which happens during a push. But it's a matter of choice. If you want to strictly follow optimization tricks, use sub esp-mov combo, else use the push. Personally, I myself never had notice the speed gain.

:)
Posted on 2002-06-26 12:39:32 by stryker