How can I create private data in a procedure?

DoNothing proc
PrivateString db "This is a private string",0


DoNothing endp

I want PrivateString to be a private string, visible only from inside DoNothing procedure
Posted on 2003-05-19 11:50:04 by greenant
I don't think that is possible. You can however use LOCAL statement to allocate uninitialized data on the stack.

DoNothing proc
LOCAL PrivateString[512]:BYTE ;512 bytes buffer

DoNothing endp
Posted on 2003-05-19 11:58:17 by Delight
You can't have initialized data in a LOCAL variable. You would have to have the data in a global variable or string table and copy it to the local variable each time the procedure is called.
Posted on 2003-05-19 12:00:33 by donkey
I have to create an ErrorHandlig routine based on GetLastError and FormatMessage so I need some initialized string to formate the message. I will use this procedure in my programs just copy & paste.
But no problem. I will use a global string
Posted on 2003-05-19 13:00:04 by greenant

ErrorMessage macro
IFNDEF ErrorMessage_lpmsg
ErrorMessage_lpmsg dd ?
call GetLastError
ADDR ErrorMessage_lpmsg,0,NULL
invoke MessageBox, 0, ErrorMessage_lpmsg, 0, MB_OK
invoke LocalFree, ErrorMessage_lpmsg

Posted on 2003-05-19 21:12:29 by roticv
You could try inserting the "private" data as follows:
DoNothing proc 

jmp @F
PrivateString db "This is a private string",0
DoNothing endp

Posted on 2003-05-19 21:41:27 by Raymond

If you want to modify your private data in the code section,don't forget to mark it as "writable" before
linking your object file.
Posted on 2003-05-20 01:46:03 by Vortex
Thanks to all.
I have modifyed the procedure and now I need only an uninitialized variable
Posted on 2003-05-20 07:01:32 by greenant
In cases where you need to return a string, and since you generally don't know how big it really is, its normal procedure to create the memory for the string with your favorite memory management API, HeapAlloc or such.

The proc creates the memory, stores the string there, and passes back a reference (pointer) to it. It's then the responsibility of the proc's calling code to clean up the memory after it is used.
Posted on 2003-05-20 07:09:21 by Ernie

ReportError proc hWnd:HWND
LOCAL buffer[50] : BYTE

invoke GetLastError
mov ecx, eax
invoke FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM, 0, ecx, 0, addr buffer, sizeof buffer, 0
invoke MessageBox, hWnd, addr buffer, addr AppName, MB_OK+MB_ICONERROR

ReportError endp
Posted on 2003-05-20 09:24:35 by greenant
There is no need to transfer the value of EAX to ECX and use the latter as a parameter for the FormatMessage function. In your posted code, you could eliminate that "mov" instruction and use EAX directly as the parameter.

Posted on 2003-05-20 09:33:19 by Raymond
Yes, you have to substitute the eax for another register, eax is used by invoke in the case you supplied. ecx is as good a choice as any.
Posted on 2003-05-20 09:52:06 by donkey

Could you please clarify for me which part of the invoke trashes the EAX register, the addr buffer or the sizeof buffer? Using which assembler/compiler? Would it apply using MASM32?

Posted on 2003-05-20 10:21:37 by Raymond
If you run the invoke you will find that you get "register value overwritten by invoke" if you attempt to use eax in the FormatMessage command.

invoke FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM, 0, ecx, 0, addr buffer, sizeof buffer, 0

EDIT: corrected a typo.
Posted on 2003-05-20 10:28:03 by donkey
Hi Raymond,

I just re-read that and I come off as a little combattive, I didn't mean to sound like that at all. Sorry.
Posted on 2003-05-20 10:58:30 by donkey
A call to

invoke FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM, 0, ecx, 0, addr buffer, sizeof buffer, 0

is compiled in

push 0 ;0
push 32 ;sizeof buffer
[color=red]lea eax,[ebp-32][/color] ;eax == addr buffer
push eax
push 0 ;0
push ecx ;ecx
push 0 ;0
call FormatMessage
Posted on 2003-05-20 12:28:44 by greenant
That is because buffer is a local variable, stored on the stack. ebp just helps to acces it.
Posted on 2003-05-21 00:57:50 by roticv
So, the addr buffer is the part responsible for trashing the EAX register in the quoted code. I guess that I could have done the same as greenant instead of asking the question!:rolleyes:

Now I know that it has nothing to do with the procedure "invoked" but only with the type of parameter passed on the stack. If the address of a LOCAL variable on the stack needs to be passed, the EAX register is used by MASM to retrieve that address because it is not known at assembly time.

If the address of a GLOBAL variable needs to be passed, its address IS know at assembly time and the EAX register would NOT be trashed in that case. An addr variable would then get coded as
        push offset variable
This is the only explicit example given for the usage of ADDR in MASM32. Unfortunately, there's no mention of using EAX to retrieve addresses of variables on the stack, even though the use of a register seems to be a necessity.

Posted on 2003-05-22 10:03:43 by Raymond
yep, at less one register for each local var, the eax is used by masm by default, you can do this by yourself and pass directly the register to invoke.

amm. i dont understand, you want a example???

.model flat, stdcall
option casemap:none

includelib kernel32.lib

hola proto :DWORD,:DWORD
pez proTO ar1:DWORD, ar2:DWORD

invoke hola, 12,22
invoke ExitProcess,0

hola proc uses edi ebx Arg1:DWORD, Arg2:DWORD
push [Arg1] ;you are pushing the value
push Arg1 ;you are pushing the value
invoke pez, addr Arg1, addr Arg1 ;are making use of how masm interpret addr
;is the same than
lea eax, Arg1 ;get the effective direction (at run-time) of Arg1
invoke pez, eax, eax ;pushing the direction
hola endp

pez proc ar1:DWORD, ar2:DWORD


pez endp
end start
Posted on 2003-05-22 12:49:20 by rea
I think Raymond was talking about local variables
Posted on 2003-05-22 14:55:27 by greenant