News:

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

Main Menu

Register preservation

Started by LoGiCaL__, April 20, 2018, 01:34:58 PM

Previous topic - Next topic

LoGiCaL__

    My question here is about Register preservation and the general convention for doing. I was working through some basic examples and tried to set a value to eax and then mov ecx, eax and then print eax, followed by eax and wasn't what I was expecting. Example :

    mov eax, 1000
    mov ecx, eax
    print str$(eax)    ; prints "1000" as expected
    print chr$(13, 10, 13, 10)
    print str$(ecx)    ; print 4 not 1000. Not sure if 4 was something random


    After doing some research in the help files about registers and reading through some posts. I came across register preservation. I also did some research from the following site http://www.webalice.it/jj2006/Masm32_Tips_Tricks_and_Traps.htm and of course found out what I was doing was a noob mistake.  ::) ::)  After changing the code and reading the help files about registers I was able to get the expected result in 2 separate ways.
    1)
         
                 mov eax, 1000
                 mov edi, eax                                ; protected register
                 print str$(eax)                             ; prints "1000" as expected
                 print chr$(13, 10, 13, 10)
                 print str$(edi)                              ; now prints "1000" as expected
         


    2)
         
                 mov eax, 1000                         
                 push eax
                 print str$(eax)                              ; prints "1000" as expected
                 print chr$(13, 10, 13, 10)
                 pop eax
                 print str$(eax)                              ; now also prints "1000" as expected
         


    The way I understand it is to use push and pop only after there are no more protected registers to use as pushing and popping memory values on and off the stack is slower.  Please correct me if I'm wrong.

    My question is does it matter which protected register I use? Is there a correct one and if so am I using it? Also, if not any info on how this convention is usually handled would be greatly appreciated. :biggrin:

hutch--

The register convention works by splitting what the OS (Windows) requires and what you need to do with your code. The basics are that any procedure can alter the volatile registers eax ecx and edx but must ensure that ebx esi and edi remain the same between calls. ebp and esp are a lot more complicated to use and that is more advanced but the jist of the situation is if you call any other procedure, they can modify eax ecx and edx as well. Now you can push and pop any of these 3 registers which will do the job but if you are careful, you can often keep the content you want in esi edi and ebx as long as you preserve them first.

What is happening in your example is that eax and ecx are being overwritten by the Windows API that "print" uses. Solution is to make esi edi and ebx as needed available in your proc, store the value in esi for example and display it to the screen without it being overwritten by the API. The up side of everyone having to preserve esi edi and ebx is you can use them once preserved and nothing else will overwrite it.

LoGiCaL__

Quote from: hutch-- on April 20, 2018, 02:57:05 PM
Now you can push and pop any of these 3 registers which will do the job but if you are careful, you can often keep the content you want in esi edi and ebx as long as you preserve them first.

What is happening in your example is that eax and ecx are being overwritten by the Windows API that "print" uses. Solution is to make esi edi and ebx as needed available in your proc, store the value in esi for example and display it to the screen without it being overwritten by the API. The up side of everyone having to preserve esi edi and ebx is you can use them once preserved and nothing else will overwrite it.

Let me see if I got this given the example I've been using.
So for example:

   
        mov eax, 1000
        mov esi, eax                                ; preserve eax in esi
       
        print str$(eax)                             ; windows api overwrites eax
        print chr$(13, 10, 13, 10)       

        mov eax, esi                                ;  reset initial value to eax
       
   

hutch--

A couple of examples.

    push esi                    ; at start of proc

    mov esi, 1000
    print str$(esi)
    print chr$(13,10,13,10)

    pop esi                     ; before you call "ret" at end of proc



    mov eax, 1000
    push eax

    print str$(eax),13,10

    pop eax


A couple more examples


; -------------------------------------------
    push ebx   ; save at start of proc
    push esi
    push edi

    mov ebx, 1
    mov esi, 2
    mov edi, 3

  ; call some proc using ebx esi + edi

    pop edi
    pop esi
    pop ebx   ; restore before ret at end of proc

    ret
; -------------------------------------------
    mov eax, 1   ; save all 3
    mov ecx, 2
    mov edx, 3

    push eax
    push ecx
    push edx

  ; call some proc using eax ecx + edx

    pop edx   ; restore all 3
    pop ecx
    pop eax
; -------------------------------------------


Also note that registers are pushed and popped on a first on, last off order.

LoGiCaL__