SwapMemory()

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re:

Post by Demivec »

Thorium wrote:Just wrote a "real" Assembler procedure. real = pure assembler, no PB in procedure.
I noticed you did not preserve the contents of the registers ebx,edi, and esi. I know they are not considered volatile. Are they reset by PureBasic before returning from the procedure? Does that make your procedure a reliable and safe one considering these things? I'm simply curious. :wink:
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: Re:

Post by Thorium »

Demivec wrote:
Thorium wrote:Just wrote a "real" Assembler procedure. real = pure assembler, no PB in procedure.
I noticed you did not preserve the contents of the registers ebx,edi, and esi. I know they are not considered volatile. Are they reset by PureBasic before returning from the procedure? Does that make your procedure a reliable and safe one considering these things? I'm simply curious. :wink:
I don't know. ^^
Just check the asm output of PB, i never did.
But i think purebasic saves and restores registers in procedures, because i allways put my asm code in procedures and never save registers and never had a problem with it. But i did get problems if i mixed up asm and PB code. Thats why i allways put it in procedures. Well registers are not a problem but stack is. So you have to fix the stack if you mess around with it.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: SwapMemory()

Post by Trond »

All registers except eax, ecx and edx must always be preserved, else you may end up with wrong expression results in the caller.
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: SwapMemory()

Post by Thorium »

Trond wrote:All registers except eax, ecx and edx must always be preserved, else you may end up with wrong expression results in the caller.
Ok, seems i must update some of my procedures. ^^

Can some one tell me why the first parameter on x64 is on rsp+48?
On x86 it is on esp+4 which makes sense. 4 bytes for the return address.
For what are the 40 bytes of stack used on x64?

Updated SwapMemoryASM3 x86 and x64.

Code: Select all

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Procedure MemorySwapASM3(*src, *dst, len.i)

  !push esi
  !push edi

  !mov esi,[esp+12]
  !mov edi,[esp+16]
  !mov ecx,[esp+20]
 
  !push ecx
  !shr ecx,2
 
  !align 4
  !MemorySwapASM3_LoopStart1:
  !cmp ecx,0
  !je MemorySwapASM3_LoopEnd1

    !mov eax,[esi]
    !mov edx,[edi]
    !mov [esi],edx
    !mov [edi],eax
    !add esi,4
    !add edi,4
    !dec ecx

  !jmp MemorySwapASM3_LoopStart1
  !MemorySwapASM3_LoopEnd1:
 
  !pop ecx
  !and ecx,3
 
  !MemorySwapASM3_LoopStart2:
  !cmp ecx,0
  !je MemorySwapASM3_LoopEnd2
 
    !mov al,[esi]
    !mov dl,[edi]
    !mov [esi],dl
    !mov [edi],al
    !inc esi
    !inc edi
    !dec ecx
 
  !jmp MemorySwapASM3_LoopStart2
  !MemorySwapASM3_LoopEnd2:

  !pop edi
  !pop esi
  
  ProcedureReturn #True
 
EndProcedure
CompilerElse
Procedure MemorySwapASM3(*src, *dst, len.i)

  !push rsi
  !push rdi

  !mov rsi,[rsp+64]
  !mov rdi,[rsp+72]
  !mov rcx,[rsp+80]
  
  !push rcx
  !shr rcx,3
  
  !align 4
  !MemorySwapASM3_LoopStart1:
  !cmp rcx,0
  !je MemorySwapASM3_LoopEnd1

    !mov rax,[rsi]
    !mov rdx,[rdi]
    !mov [rsi],rdx
    !mov [rdi],rax
    !add rsi,8
    !add rdi,8
    !dec rcx

  !jmp MemorySwapASM3_LoopStart1
  !MemorySwapASM3_LoopEnd1:
  
  !pop rcx
  !and rcx,7
  
  !MemorySwapASM3_LoopStart2:
  !cmp rcx,0
  !je MemorySwapASM3_LoopEnd2
  
    !mov al,[rsi]
    !mov dl,[rdi]
    !mov [rsi],dl
    !mov [rdi],al
    !inc rsi
    !inc rdi
    !dec rcx
  
  !jmp MemorySwapASM3_LoopStart2
  !MemorySwapASM3_LoopEnd2:

  !pop rdi
  !pop rsi

  ProcedureReturn #True
  
EndProcedure
CompilerEndIf
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: SwapMemory()

Post by Trond »

Can some one tell me why the first parameter on x64 is on rsp+48?
Because x64 mode was made by monkeys.
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: SwapMemory()

Post by freak »

> For what are the 40 bytes of stack used on x64?

On x64 you have to provide stack space for the up to 4 register parameters when calling a function (this is for vararg support mainly). PB allocates this space beforehand so it does not have to do it for every further call. The remaining 8 bytes are for alignment iirc.

Just use the "p.v_variable" notation to address parameters instead of the fixed offsets and you don't have to care about this:
http://www.purebasic.com/documentation/ ... edasm.html

Btw, x64 has more volatile registers. You should be able to do it without needing to save any registers:
http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx

Note that all this is Windows only. Linux x64 has a different ABI.
quidquid Latine dictum sit altum videtur
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: SwapMemory()

Post by Thorium »

freak wrote: On x64 you have to provide stack space for the up to 4 register parameters when calling a function (this is for vararg support mainly). PB allocates this space beforehand so it does not have to do it for every further call. The remaining 8 bytes are for alignment iirc.
Thank you for that interesting information. :)
freak wrote: Just use the "p.v_variable" notation to address parameters instead of the fixed offsets and you don't have to care about this:
http://www.purebasic.com/documentation/ ... edasm.html
The problem is that i have to save registers. The only way i know doing that is pushing them on the stack which will change the stack addresses of the parameter variables.

This is not working, and it should not work. ^^

Code: Select all

Global Test1.i
Global Test2.i


Procedure Test(Param1.i, Param2.i)

  !push esi
  !push edi

  !mov esi,[p.v_Param1]
  !mov edi,[p.v_Param2]

  !mov [v_Test1], esi
  !mov [v_Test2], edi

  !pop edi
  !pop esi

EndProcedure

Test(123, 456)

Debug Test1
Debug Test2
freak wrote: Btw, x64 has more volatile registers. You should be able to do it without needing to save any registers:
http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
Yes i know them but don't used them a lot. Will change this. ^^
But it's not solving the problem for x86. Well it's not realy a problem that a simple calculator can not solve. ^^
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: SwapMemory()

Post by freak »

> The problem is that i have to save registers.

Just add your additional offset to the location:

Code: Select all

  !mov esi,[p.v_Param1+8]
  !mov edi,[p.v_Param2+8]
quidquid Latine dictum sit altum videtur
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: SwapMemory()

Post by Thorium »

freak wrote:> The problem is that i have to save registers.

Just add your additional offset to the location:

Code: Select all

  !mov esi,[p.v_Param1+8]
  !mov edi,[p.v_Param2+8]
Ah, that is possible. Thank you. :)
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: SwapMemory()

Post by Thorium »

Ok, updated the swap memory procedure for the last time, i hope. ^^
Should be save to use now. x64 version don't use the stack anymore.

Code: Select all

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Procedure MemorySwapASM3(*src, *dst, len.i)

  !push esi
  !push edi

  !mov esi,[p.p_src+8]
  !mov edi,[p.p_dst+8]
  !mov ecx,[p.v_len+8]
 
  !push ecx
  !shr ecx,2
 
  !align 4
  !MemorySwapASM3_LoopStart1:
  !cmp ecx,0
  !je MemorySwapASM3_LoopEnd1

    !mov eax,[esi]
    !mov edx,[edi]
    !mov [esi],edx
    !mov [edi],eax
    !add esi,4
    !add edi,4
    !dec ecx

  !jmp MemorySwapASM3_LoopStart1
  !MemorySwapASM3_LoopEnd1:
 
  !pop ecx
  !and ecx,3
 
  !MemorySwapASM3_LoopStart2:
  !cmp ecx,0
  !je MemorySwapASM3_LoopEnd2
 
    !mov al,[esi]
    !mov dl,[edi]
    !mov [esi],dl
    !mov [edi],al
    !inc esi
    !inc edi
    !dec ecx
 
  !jmp MemorySwapASM3_LoopStart2
  !MemorySwapASM3_LoopEnd2:

  !pop edi
  !pop esi
  
  ProcedureReturn #True
 
EndProcedure
CompilerElse
Procedure MemorySwapASM3(*src, *dst, len.i)

  !mov r8,[p.p_src]
  !mov r9,[p.p_dst]
  !mov rcx,[p.v_len]
  
  !mov r10,rcx
  !shr rcx,3
  
  !align 4
  !MemorySwapASM3_LoopStart1:
  !cmp rcx,0
  !je MemorySwapASM3_LoopEnd1

    !mov rax,[r8]
    !mov rdx,[r9]
    !mov [r8],rdx
    !mov [r9],rax
    !add r8,8
    !add r9,8
    !dec rcx

  !jmp MemorySwapASM3_LoopStart1
  !MemorySwapASM3_LoopEnd1:
  
  !and r10,7
  
  !MemorySwapASM3_LoopStart2:
  !cmp r10,0
  !je MemorySwapASM3_LoopEnd2
  
    !mov al,[r8]
    !mov dl,[r9]
    !mov [r8],dl
    !mov [r9],al
    !inc r8
    !inc r9
    !dec r10
  
  !jmp MemorySwapASM3_LoopStart2
  !MemorySwapASM3_LoopEnd2:

  ProcedureReturn #True
  
EndProcedure
CompilerEndIf
Post Reply