flat assembler
Message board for the users of flat assembler.

Index > Windows > Confused about register preserving

Author
Thread Post new topic Reply to topic
newbie



Joined: 09 Jul 2004
Posts: 3
newbie 09 Jul 2004, 21:20
I've been trying to learn windows assembly programming and have been using the Iczelion tutorials that Privalov converted to fasm 1.52 format.

So far so good, but I'm a bit confused about register preservation. From what I've read you have to preserve ebx, esi, and edi in callbacks such as the main window proc.

In the converted fasm tutorials (at http://board.flatassembler.net/topic.php?t=1482), those registers are used in the main window proc without restoring them at the end. I guess I've obviously got it wrong that they are meant to be saved. Could someone please explain which registers have to be saved and when?

Thanks.
Post 09 Jul 2004, 21:20
View user's profile Send private message Reply with quote
pelaillo
Missing in inaction


Joined: 19 Jun 2003
Posts: 878
Location: Colombia
pelaillo 09 Jul 2004, 21:41
You're right. In returning from win32 callbacks you must preserve any modified register with the exception of eax, ecx and edx.

If not preserved, you could face some weird problems, death blue screen included. Sometimes it does not cause any problems, but this is a matter of luck.
Please post the implied tutorial in order to fix it.
Post 09 Jul 2004, 21:41
View user's profile Send private message Yahoo Messenger Reply with quote
scientica
Retired moderator


Joined: 16 Jun 2003
Posts: 689
Location: Linköping, Sweden
scientica 09 Jul 2004, 21:46
well, as a general rule you should preserve all registers you use (imo), think the secario:

uses some registers
calls a fnction or api
ok what's the state of the regitsers now?

with the api you're told that some registers are always preserved by the API (forgot which ones now), this means that all other registers should be considered tampered with by the funciton/api.
There is only two registers you never need/must to preserve, eax and esp. eax is return value and esp is the stack pointer - "break" esp and you'll most likey(read: always) crash your program, and eax is genereally god to set to 0 - to indicate the function did fine.
Post 09 Jul 2004, 21:46
View user's profile Send private message Visit poster's website Reply with quote
newbie



Joined: 09 Jul 2004
Posts: 3
newbie 09 Jul 2004, 22:19
pelaillo wrote:
Please post the implied tutorial in order to fix it.


Well it's most of them in tutfasm.zip from the thread I linked to. The direct URL is http://board.flatassembler.net/download.php?id=756

Anyway here's an example from tut04.asm

Code:
  proc WndProc, hWnd,uMsg,wParam,lParam
    hdc dd ?
    ps PAINTSTRUCT
    rect RECT
     enter
     .if [uMsg],e,WM_DESTROY
       invoke  PostQuitMessage, NULL
     .elseif [uMsg],e,WM_PAINT
     lea     esi,[ps]
    invoke  BeginPaint, [hWnd],esi
      mov     [hdc],eax
   lea     ebx,[rect]
  invoke  GetClientRect, [hWnd],ebx
   invoke  DrawText, [hdc],OurText,-1,ebx,DT_SINGLELINE or DT_CENTER or DT_VCENTER
     invoke  EndPaint, [hWnd],esi
     .else
  invoke  DefWindowProc, [hWnd],[uMsg],[wParam],[lParam]
      return
     .endif
       xor    eax,eax
      return
  endp
    


As you can see, ebx and esi are used in that callback proc without being restored. I'm not sure if it's okay or not. This asm stuff is complicated! Rolling Eyes
Post 09 Jul 2004, 22:19
View user's profile Send private message Reply with quote
pelaillo
Missing in inaction


Joined: 19 Jun 2003
Posts: 878
Location: Colombia
pelaillo 09 Jul 2004, 23:47
You see it well, tutorials go fixed. I am going to take care of them.
If you permit me a counsel: abandon "ifs", "elses" and other HLL constructs to take most control of your code and because is easier to maintain. For example:
Code:
  proc WndProc, hWnd,uMsg,wParam,lParam    hdc dd ?    ps PAINTSTRUCT    rect RECT      enter push ebx esi  mov eax,[uMsg] ; note 1       cmp eax,WM_PAINT ; note 2     je wm_paint   cmp eax,WM_DESTROY    je .wm_destroy        invoke  DefWindowProc, [hWnd],[uMsg],[wParam],[lParam]        jmp .finish  .wm_destroy:       invoke  PostQuitMessage, NULL jmp .finish  .wm_paint: lea     esi,[ps]      invoke  BeginPaint, [hWnd],esi        mov     [hdc],eax     lea     ebx,[rect]    invoke  GetClientRect, [hWnd],ebx     invoke  DrawText, [hdc],OurText,-1,ebx,DT_SINGLELINE or DT_CENTER or DT_VCENTER       invoke  EndPaint, [hWnd],esi  .finish:  xor eax,eax   pop esi ebx   return   ;note 3  endp    


Doesn't it look nicer?
The notes:
note 1: WinProc normally have many compares against uMsg, and comparing against eax let you save some bytes because opcode is shorter.
note 2: Your program will have many WM_PAINT messages before a WM_DESTROY so it is beter dispatch it first.
note 3: Althrough it is not wrong to have more than one ret for a procedure, it is safer to have only one, mainly because stack balancing when some pop's missing.
Post 09 Jul 2004, 23:47
View user's profile Send private message Yahoo Messenger Reply with quote
newbie



Joined: 09 Jul 2004
Posts: 3
newbie 10 Jul 2004, 09:46
Thanks for the help and for showing how registers are meant to be preserved in a callback. The cmp/je method does look nicer too. The Iczelion win32asm tutorials seem to use a lot of highlevel if/else stuff.

I have one more question regarding register preservation. Is it okay to use ebx esi and edi without preserving them if you're *not* in a callback?

For example in WinMain:
Code:
 lea ebx,[msg]
    @@:
        invoke  GetMessage, ebx,NULL,0,0
    or      eax,eax
     jz      @f
  invoke  TranslateMessage, ebx
       invoke  DispatchMessage, ebx
        jmp     @b
    @@:
    


I think that's okay because we're not in a callback, but I just wanted to check that the api's themselves don't change ebx esi or edi either. Is that correct?
Post 10 Jul 2004, 09:46
View user's profile Send private message Reply with quote
pelaillo
Missing in inaction


Joined: 19 Jun 2003
Posts: 878
Location: Colombia
pelaillo 10 Jul 2004, 15:03
Yes. If you are not in a callback, you are worried by your own code. Windows API functions *must* preserve themselves the ebx, esi and edi, is part of the game. For example, when painting to a DC it is common practice to use ebx to store the handle to the DC through all the gdi functions.

However, it is a good idea to preserve those registers in your own procedures if you are going to use a mix of API and them or to work in a team. Everyone is expecting those registers to be preserved.

But as general rule, try to avoid relying on API functions, otherwise their bugs will became yours Wink
Post 10 Jul 2004, 15:03
View user's profile Send private message Yahoo Messenger Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.