News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Free RBP with Static RSP

Started by habran, April 25, 2013, 06:31:40 AM

Previous topic - Next topic

jj2007

Attached a sample code using sLocal (like stack-local). Usage:

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
MyTest proc par1, par2
  push esi               ; save esi
sLocal First:DWORD, rc:RECT, wc:WNDCLASSEX
sLocal Last[1]:BYTE
sLocal
  sub edi, esp
  print str$(sPara(1)), 9, "par1", 13, 10
  print str$(sPara(2)), 9, "par2", 13, 10
  lea eax, First
  sub eax, esp
  print str$(eax), 9, "First", 13, 10
  lea ecx, Last
  sub ecx, esp
  print str$(ecx), 9, "Last", 13, 10, 10
  sLocal end
  pop esi      ; restore the stack
  retn 1*4
MyTest endp


32-bit code, no MasmBasic. One caveat is that you cannot use the same sLocal name in a second proc, since Masm does not allow redefinition of integers in text format. There is a possible workaround using PURGE and macros, but it would be an overkill.

habran

good job jj2007 :t
you are getting closer to my goal, thanks for your effort :biggrin:
if we could get read of 's' in sLOCALS it would be great
for naming vars we can find easy solution

my intention is to keep source looking as usual so that we don't have to rewrite sources
Cod-Father

jj2007

Getting rid of the "s" is easy:
OPTION NOKEYWORD:<LOCAL>
LOCAL equ <sLocal>

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
MyTest proc par1, par2
  push esi ; save esi
LOCAL First:DWORD, rc:RECT, wc:WNDCLASSEX
LOCAL Last[1]:BYTE
LOCAL
  sub edi, esp
  print str$(sPara(1)), 9, "P1", 13, 10
  print str$(sPara(2)), 9, "P2", 13, 10
  lea eax, First
  sub eax, esp
  print str$(eax), 9, "First", 13, 10
  lea ecx, Last
  sub ecx, esp
  print str$(ecx), 9, "Last", 13, 10, 10
  LOCAL end
  pop esi ; restore the stack
  retn 1*4
MyTest endp


But the question is "what for?"...
I was always told 64-bit is so much faster because you never run short of registers :P

Gunther

Jochen,

Quote from: jj2007 on April 26, 2013, 03:41:36 PM
But the question is "what for?"...
I was always told 64-bit is so much faster because you never run short of registers :P

you're quiet right. I don't understand, because parameters are passed via registers (according to the Windows 64 bit ABI).

Gunther
You have to know the facts before you can distort them.

dedndave

you may want to time these code methods
in the end, it may be better to use RBP/EBP the normal way and use a couple locals to store extra values
i think the processors have been optimized to access stack data using the base pointer register

i sometimes use "fake" register names to write a loop
then, when i am done, the lesser-often accessed items get moved to locals
and the more-often accessed items get registers   :P
push and pop aren't bad, either

i remember writing a loop, where i needed EBP for some rather intensive and long math code
i needed one extra variable at the end of the loop - the count, accessed once each pass
i used a global dword - seemed to work pretty well

jj2007

Quote from: dedndave on April 26, 2013, 09:07:43 PM
you may want to time these code methods

No time for that ;)

Anyway, useful or not, it was a nice exercise in macro writing. Here is the luxury version, with "uses" and push & pop and stack balance control:

MyTest proc par1, par2        ; two paras passed
LOCAL First:DWORD, rc:RECT, wc:WNDCLASSEX
LOCAL Last[1]:BYTE
LOCAL uses esi edi        ; we preserve two regs
  mov rc.left, 12300
  xPush eax                ; don't use normal push...!
  xPush 999
  add rc.left, 45                ; result should be 12345
  print hex$(sPara(1)), 9, "par1", 13, 10        ; show the two paras passed ...
  print hex$(sPara(2)), 9, "par2", 13, 10        ; ... correctly, despite the two xPushes
  xPop ecx
  mov ecx, rc.left
  print str$(ecx), 9, "rc.left - works because 'mov ecx, rc.left' yields correct result", 13, 10
  print str$(rc.left), 9, "rc.left - fails because 'print' pushes paras!!", 13, 10, 10
  xPop edx
  LOCAL end                ; macro will shout at you if your stack is not balanced
  retn 2*DWORD
MyTest endp

habran

#21
Well done JJ2077 :t
that one is the deluxe macro
now you have left with one mo job:  overkill or underkill try to make locals reusable, please ;)

Hey guys, I want to explain to you why is it that I want to free RBP
when you work with a lot of structures it is much easier and faster to use nonvolatile register
as well as in loops
instead of writing for example:

  LOCAL   Mystruct :GOODSTRUCT
   mov rax, Mystruct
   mov rax,[rax].GOODSTRUCT.txt
   mov rax,[rax].TEXTSTRUCT.data
   .if !rax
     jmp aexit
   .endif
   mov rax, Mystruct
   mov rax,[rax].GOODSTRUCT.opt
   mov rax,[rax].OPTSTRUCT.data
   .if !rax
     jmp aexit
   .endif

I can write like this:

  LOCAL   Mystruct :GOODSTRUCT
   mov rbp, Mystruct
   mov r15,[rbp].GOODSTRUCT.txt 
   mov r12,[rbp].GOODSTRUCT.opt
   mov rcx,[r15].TEXTSTRUCT.data
   mov rax,[r12].OPTSTRUCT.data 

now I don't need to reshuffle again and again my pointers but they are ready to access immediately

so, now if I am working with several structures, any additional nonvolatile register is welcome

and when working with .while or .for    ebx  or ebp can be used as counters because they don't get changed
when you call some function
Cod-Father