I'm learning more MASM through the eyes of so co-workers and getting to answer their questions. I'm taking things I don't know to the forum for some help. Here's another question:
When I code in MASM I normally stick to EAX, EBX, ECX, and EDX. I'm learning more about ESI and EDI and that I can use them just as frequently as long as I don't need registers to the lower parts of the register. I have not run into an issue yet (so let me know if I'm doing something wrong). But I see that EBP and ESP are also available as general registers.
I have not used EBP or ESP for anything yet and know that in 16-bit mode these seem to be more significant. Base and section seem to really be not too important because I'm just using a flat model. Is there something else that these registers are used for that I might be stepping on if I start using them as just another general register?
I'd like to see what people say about this but after reading more from this forum I know this is way beyond my level right now. I'm having a hard time understanding what these two registers are used for ... but I know it's important. I think for now (until I understand what's going on) I'll just avoid them. Seems fair to me.
ESP = extended stack pointer register
the CPU does use it automatically when you PUSH or POP or when you ENTER or LEAVE a PROCEDURE or on RET.
When you are advanced enough ESP can be used for tricks but you must be extremely careful.
You are right here: until you learn and understand more you should let the CPU do it own job with ESP and avoid using it as a general purpose register.
EBP - extended base pointer register
Can be used as a general purpose register but it was designed (mainly in 16 bits) to be used as a STACK FRAME base pointer (no not other "bases"). This default use as a stack frame base pointer did continue in 32 bits and it is used by MASM's PROC as a base for PROC argument and for LOCAL's.
It is slightly more easy to use EBP as a general purpose register but only IF you do not use PROC/ ENDP in standard ways.
However AGAIN... until you do understand and learn more you should "stick to fishing into normal waters from now on". That means: avoid using EBP as a general purpose register until you have a desperate need in an optimized inner loop and you can handle the consequences. Or at least until you can understand stack frames into great details.
Thomas,
You will rarely need ESP and EBP - LOCAL variables do the job unless you are in desperate need for many fast registers.
Some important hints in a nutshell:
1.
pushad
... you are free to use any registers here except ESP
(and EBP if you do NOT use LOCAL variables)...
popad
2. There is a convention that ACD are promiscuous registers - anybody can use them freely, including the Windows API's. So if you call any macro (e.g. chr$) or API (e.g. MessageBox), you can bet that eAx, eCx and eDx are not the same afterwards.
3. The other side of the coin is that BSD, i.e. eBx, eSi and eDi are protected - after the API call they are still the same. Fine for you - but attention, Windows also counts on you, so you must save these registers before using them! Purists often use
push ebx
push esi
push edi
...
pop edi
pop esi
pop ebx
in their code, instead of the pushad/popad sequence.
4. LOCAL variables are not initialised. If you want zeroes in your LOCAL variables and structures, use the code below at your own risk (it works perfectly but NOT with the MyProc proc uses edi syntax)
Happy coding,
JJ
.data?
EspGlob dd ?
MyCode proc
LOCAL MyCt:DWORD
LOCAL LocBuf[256]:BYTE
LOCAL charfmt:CHARFORMAT2
LOCAL MyPtr:DWORD
call ClearLocals
...
MyCode endp
ClearLocals proc ; first instruction after LOCALS - eax will be zero on exit
pop EspGlob ; save the return address to a global variable - now
; the stack is identical to the calling procedure
xchg eax, ecx ; save ecx
mov ecx, ebp ; base page of calling procedure
sub ecx, esp ; ebp - esp = No. of bytes in locals
mov esp, ebp ; discard existing locals
shr ecx, 2 ; divide by four
@@: push 0 ; dwords on stack
loop @B
xchg eax, ecx ; restore ecx, 0 to eax
push EspGlob ; restore the return address
ret
ClearLocals endp
The stack and base pointers are not easy to use in general purpose coding. With practice you can use EBP if you write a procedure without a stack frame where you have to keep track of ESP directly which can be complcated in larger code and in very limited circumstances you can save ESP to a global memory location to use it but it is difficult to use safely.
In most instances a standard MASM procedure which creates a stack frame does the job fine and in places where the stack frame maters you can usually inline the code to make it faster still. Your real win with writing stack frame free code is having EBP available which is important in larger procedures so you have an extra register to use in speed related areas.
The three registers that must be preserved between function calls in a stack frame are EBX ESI and EDI so if you write a procedure that uses any of the three, preserve any of the three registers that are used and restore them at the end of the procedure. Normal stuff,
push ebx
push esi
push edi
; your code
pop edi
pop esi
pop ebx