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 (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:
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.
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
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.
Sweet, much appreciated!