News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Problem with LOCAL variables

Started by Gwyn, February 20, 2013, 08:23:57 AM

Previous topic - Next topic

Gwyn

Before i ask my question i think i should let you know that i am beginner in masm and in programming altogether.
My problem is - as the title say, with local variables, they get constantly overwritten between messages in all of my small programs.
For example if i declare two local variables
LOCAL localx:DWORD
LOCAL localy:DWORD
then use them to store client area size during WM_SIZE message, the value in locals will change (will be overwritten) before it reaches WM_PAINT message, resulting code will paint itself outside client area, obviously.
Usually i would think that the problem is with me, but the same program runs as expected if i declare those variables as global.
Just changing code into this
.DATA
localx DWORD 0
localy DWORD 0
will make everything work fine. I made sure that the values originally stored are fine, and that later they get overwritten by loading programs into OllyDbg.
As i said that happens with all of my programs, and i couldn't find any solution to it, except declaring global variables.
The question is of course why is this happening.

I would attach an example but the only one i currently have is using high resolution .BMP image in resource, and is 20MB large.

RuiLoureiro

Hi Gwyn
               it never happens with me. It is strange to me.
               I think the problem may be in the register EBP
used to access those variables. Is it preserved ?
               Strange is also what you said: that happens with all of my programs!

               Another question: how do you store client area size during WM_SIZE message ? could you show what are you doing ?
               Well i never used local variables in window procedures

Vortex

Hi Gwyn,

Your results are normal. Nothing unexpected. Local variables are always local to their host procedure and the scope is not global. Uninitialized local variables will contain garbage values from the stack. You need to store your critical variables in the .data or .data? section.

A quick example : you can check Iczelion's Simple Bitmap tutorial :

.data?
hBitmap dd ?
.
.
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
   LOCAL ps:PAINTSTRUCT
   LOCAL hdc:HDC
   LOCAL hMemDC:HDC
   LOCAL rect:RECT
   .if uMsg==WM_CREATE
      invoke LoadBitmap,hInstance,IDB_MAIN
      mov hBitmap,eax


hBitmap is stored in the uninitialized section .data?  No guaranty for the local variables in the procedure to survive across consecutive calls.

http://win32assembly.programminghorizon.com/tut25.html

Gwyn

Quote from: Vortex on February 20, 2013, 08:58:53 AM
Hi Gwyn,
No guaranty for the local variables in the procedure to survive across consecutive calls.
I don't understand completly, so you are saying that it's normal that values stored during WM_SIZE message in local variables, won't be the same in WM_PAINT message. I thought that the scope in which the value of local variables will be preserved is the whole procedure (for example WndProc), and now you are saying that this just applies to calls between messages.
Could you confirm that?
Because i did not know that, the thing that confused me was the Petzold's book examples were he does exactly that, so i thought that i was doing something wrong when it didn't work for me.

@ RuiLoureiro

Here is the code in attachment , it's simple mapping mode example where i change mapping mode to MM_ISOTROPIC and display bitmap(2048×3072) from resource in the center of the client area.

MichaelW

I don't know what Petzold book you are referring to, but in C for a local variable to be preserved between calls you have to declare it with the storage class specifier static, which causes the compiler to store it in the uninitialized (BSS) data section, but continue to limit the scope of the variable to within the procedure.

#include <windows.h>
#include <conio.h>
#include <stdio.h>
int test1( void )
{
    int i;
    int r = i;
    i = 123;
    return r;
}
int test2( void )
{
    static int i;
    int r = i;
    i = 123;
    return r;
}
int main( void )
{
    printf("%d\n", test1());
    printf("%d\n", test1());
    printf("%d\n", test2());
    printf("%d\n", test2());
    getch();
}


200084144
4198483
0
123


_r$ = -8 ; size = 4
_i$ = -4 ; size = 4
_test1 PROC NEAR
; File c:\program files\microsoft visual c++ toolkit 2003\my\static\test.c
; Line 5
push ebp
mov ebp, esp
sub esp, 8
; Line 7
mov eax, DWORD PTR _i$[ebp]
mov DWORD PTR _r$[ebp], eax
; Line 8
mov DWORD PTR _i$[ebp], 123 ; 0000007bH
; Line 9
mov eax, DWORD PTR _r$[ebp]
; Line 10
mov esp, ebp
pop ebp
ret 0
_test1 ENDP
. . .
_BSS SEGMENT
?i@?1??test2@@9@9 DD 01H DUP (?) ; `test2'::`2'::i
; Function compile flags: /Odt
_BSS ENDS
_TEXT SEGMENT
_r$ = -4 ; size = 4
_test2 PROC NEAR
; Line 12
push ebp
mov ebp, esp
push ecx
; Line 14
mov eax, DWORD PTR ?i@?1??test2@@9@9
mov DWORD PTR _r$[ebp], eax
; Line 15
mov DWORD PTR ?i@?1??test2@@9@9, 123 ; 0000007bH
; Line 16
mov eax, DWORD PTR _r$[ebp]
; Line 17
mov esp, ebp
pop ebp
ret 0
_test2 ENDP


With MASM you have to put it in the data section, and accept a global scope.
Well Microsoft, here's another nice mess you've gotten us into.

dedndave

local variable contents are volatile
they only remain valid for the instance of a single call to the routine

when the WM_SIZE message is received, that is one instance
when the WM_PAINT message is received, that is another instance
each message is a seperate instance
this can be overcome by using global variables (in the .DATA? or .DATA section)

in this particular case, you may not need to store the information
when you call the BeginPaint function, it fills a PAINTSTRUCT structure
part of that structure is a RECT rectangle structure that describes what part of the client area needs to be drawn

Gwyn

Quote from: MichaelW on February 20, 2013, 11:39:10 AM
I don't know what Petzold book you are referring to, but in C for a local variable to be preserved between calls you have to declare it with the storage class specifier static, which causes the compiler to store it in the uninitialized (BSS) data section, but continue to limit the scope of the variable to within the procedure.
I got it now, yes he did use static for those declarations, but because i don't know C i didn't know there is any difference between the two of them, i just thought they are regular local variables, and that is why i naively used regular local variables in masm and tried to do the same.
Thanks everybody for their posts, i can say i understand now how to properly use local variables.

RuiLoureiro

Gwyn,

    «Thanks everybody for their posts,
    i can say i understand now how to properly use local variables»

    . So i think your problem is solved.

      Meanwhile i want to say this:

        1. I use local variables very very rarely;
           This is why i have no problems with them!           
        2. I never use it in window procedures.
           And if we want to use it there
           we can use inside one message and
           not from one to another;
           There is no problem with LOCAL ps:PAINTSTRUCT
            because it is memory to be used by
            BeginPaint/EndPaint only when uMsg==WM_PAINT.           
        3. Local variables should be initialized.
           They are not 0 ! They are something !
        4. Why to declare it static if i can define
           it in the data section ?

    . Your problem is with LOCAL pos:POINT.
      When the system calls WndProc with uMsg==WM_SIZE
      you save pos.y and pos.x. But when the system
      comes again with uMsg==WM_PAINT, pos.y and pos.x
      is any value nothing to do with the previous

dedndave

QuoteI use local variables very very rarely;
This is why i have no problems with them!
a lot of C programmers tell us to always use LOCALS, never use GLOBALS - lol
they are both tools - use the right tool for the job

QuoteI never use it in window procedures.
i try to avoid using LOCAL's in WndProc, as well
the way i do it is....
    .if uMsg==WM_PAINT
        INVOKE  PaintProc,hWnd
        xor     eax,eax

then, i put the LOCAL's in the PaintProc

QuoteWhy to declare it static if i can define it in the data section ?
i thought that's what a "static" variable (C term) is in assembler

qWord

Quote from: RuiLoureiro on February 21, 2013, 05:02:27 AM1. I use local variables very very rarely;
that is very very unwise! Beside the straightforward scope, it can also be assumed that locals are always cached.
All over, is very simple: if you need to save global states, use global variables* - otherwise use locals.

Quote from: RuiLoureiro on February 21, 2013, 05:02:27 AM4. Why to declare it static if i can define
           it in the data section ?
static == variable in data section with local scope.(?)


* assuming a single threaded environment.
MREAL macros - when you need floating point arithmetic while assembling!

RuiLoureiro

Dave,
    «a lot of C programmers tell us to always use LOCALS, never use GLOBALS»

    .   generally i dont need it, no LOCALS, no GLOBALS

qWord,
    « that is very very unwise!
    Beside the straightforward scope, it can also be assumed that locals are always cached.»

    .   to get the function that a local variable do inside a proc
        i try to use other tricks. Meanwhile it is not easy to write local
        variables when we want to use esp to access the stack (not ebp).

dedndave

Rui, this may be related to that other program being 230 kb   :biggrin:
but, i suspect you just have some data declared in the .DATA section that could be in .DATA?

RuiLoureiro

Dave, Yes i have a lot of data in .data section.
And yes some of them could be in .data?. One day i
will do that work !  ;)

Vortex

QuoteMeanwhile it is not easy to write local variables when we want to use esp to access the stack (not ebp).

With a little care, it's possible.

RuiLoureiro

Quote from: Vortex on February 21, 2013, 06:25:54 AM
QuoteMeanwhile it is not easy to write local variables when we want to use esp to access the stack (not ebp).

With a little care, it's possible.
Yes i know and i do