Page 2 of 2
Re:
Posted: Tue Sep 22, 2009 1:04 am
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.

Re: Re:
Posted: Tue Sep 22, 2009 2:41 pm
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.

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.
Re: SwapMemory()
Posted: Tue Sep 22, 2009 5:14 pm
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.
Re: SwapMemory()
Posted: Tue Sep 22, 2009 7:56 pm
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
Re: SwapMemory()
Posted: Wed Sep 23, 2009 3:31 pm
by Trond
Can some one tell me why the first parameter on x64 is on rsp+48?
Because x64 mode was made by monkeys.
Re: SwapMemory()
Posted: Wed Sep 23, 2009 3:58 pm
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.
Re: SwapMemory()
Posted: Wed Sep 23, 2009 4:17 pm
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.
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
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. ^^
Re: SwapMemory()
Posted: Wed Sep 23, 2009 4:51 pm
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]
Re: SwapMemory()
Posted: Wed Sep 23, 2009 5:36 pm
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.

Re: SwapMemory()
Posted: Wed Sep 23, 2009 6:59 pm
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