symport/e32/include/x86hlp_gcc.inl
changeset 1 0a7b44b10206
child 2 806186ab5e14
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symport/e32/include/x86hlp_gcc.inl	Thu Jun 25 15:59:54 2009 +0100
@@ -0,0 +1,455 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Symbian Foundation License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\common\x86\x86hlp_gcc.inl
+// If there are no exports then GCC 3.4.x does not generate a .reloc 
+// section, without which rombuild can't relocate the .code section
+// to its ROM address. Your ROM then goes boom early in the boot sequence.
+// This unused export forces the PE to be generated with a .reloc section.
+// 
+//
+
+EXPORT_C void __ignore_this_export()
+	{
+	}
+
+static void DivisionByZero()
+	{
+	asm("int 0");
+	}
+
+extern "C" {
+
+void __NAKED__ _alloca()
+{
+	// GCC passes the param in eax and expects no return value
+	asm("pop ecx");
+	asm("sub esp, eax");
+	asm("push ecx");
+	asm("ret");
+}
+
+void __NAKED__ _allmul()
+//
+// Multiply two 64 bit integers returning a 64 bit result
+// On entry:
+//		[esp+4], [esp+8] = arg 1
+//		[esp+12], [esp+16] = arg 1
+// Return result in edx:eax
+// Remove arguments from stack
+//
+	{
+	asm("mov eax, [esp+4]");		// eax = low1
+	asm("mul dword ptr [esp+16]");	// edx:eax = low1*high2
+	asm("mov ecx, eax");			// keep low 32 bits of product
+	asm("mov eax, [esp+8]");		// eax = high1
+	asm("mul dword ptr [esp+12]");	// edx:eax = high1*low2
+	asm("add ecx, eax");			// accumulate low 32 bits of product
+	asm("mov eax, [esp+4]");		// eax = low1
+	asm("mul dword ptr [esp+12]");	// edx:eax = low1*low2
+	asm("add edx, ecx");			// add cross terms to high 32 bits
+	asm("ret");
+	}
+
+void __NAKED__ udiv64_divby0()
+	{
+	asm("int 0");					// division by zero exception
+	asm("ret");
+	}
+
+__NAKED__ /*LOCAL_C*/ void UDiv64()
+	{
+	// unsigned divide edx:eax by edi:esi
+	// quotient in ebx:eax, remainder in edi:edx
+	// ecx, ebp, esi also modified
+	asm("test edi, edi");
+	asm("jnz short UDiv64a");			// branch if divisor >= 2^32
+	asm("test esi, esi");
+	asm("jz %a0": : "i"(&DivisionByZero)); // if divisor=0, branch to error routine
+	asm("mov ebx, eax");				// ebx=dividend low
+	asm("mov eax, edx");				// eax=dividend high
+	asm("xor edx, edx");				// edx=0
+	asm("div esi");						// quotient high now in eax
+	asm("xchg eax, ebx");				// quotient high in ebx, dividend low in eax
+	asm("div esi");						// quotient now in ebx:eax, remainder in edi:edx
+	asm("ret");
+	asm("UDiv64e:");
+	asm("xor eax, eax");				// set result to 0xFFFFFFFF
+	asm("dec eax");
+	asm("jmp short UDiv64f");
+	asm("UDiv64a:");
+	asm("js short UDiv64b");			// skip if divisor msb set
+	asm("bsr ecx, edi");				// ecx=bit number of divisor msb - 32
+	asm("inc cl");
+	asm("push edi");					// save divisor high
+	asm("push esi");					// save divisor low
+	asm("shrd esi, edi, cl");			// shift divisor right so that msb is bit 31
+	asm("mov ebx, edx");				// dividend into ebx:ebp
+	asm("mov ebp, eax");
+	asm("shrd eax, edx, cl");			// shift dividend right same number of bits
+	asm("shr edx, cl");
+	asm("cmp edx, esi");				// check if approx quotient will be 2^32
+	asm("jae short UDiv64e");			// if so, true result must be 0xFFFFFFFF
+	asm("div esi");						// approximate quotient now in eax
+	asm("UDiv64f:");
+	asm("mov ecx, eax");				// into ecx
+	asm("mul edi");						// multiply approx. quotient by divisor high
+	asm("mov esi, eax");				// ls dword into esi, ms into edi
+	asm("mov edi, edx");
+	asm("mov eax, ecx");				// approx. quotient into eax
+	asm("mul dword ptr [esp]");			// multiply approx. quotient by divisor low
+	asm("add edx, esi");				// edi:edx:eax now equals approx. quotient * divisor
+	asm("adc edi, 0");
+	asm("xor esi, esi");
+	asm("sub ebp, eax");				// subtract dividend - approx. quotient *divisor
+	asm("sbb ebx, edx");
+	asm("sbb esi, edi");
+	asm("jnc short UDiv64c");			// if no borrow, result OK
+	asm("dec ecx");						// else result is one too big
+	asm("add ebp, [esp]");				// and add divisor to get correct remainder
+	asm("adc ebx, [esp+4]");
+	asm("UDiv64c:");
+	asm("mov eax, ecx");				// result into ebx:eax, remainder into edi:edx
+	asm("mov edi, ebx");
+	asm("mov edx, ebp");
+	asm("xor ebx, ebx");
+	asm("add esp, 8");					// remove temporary values from stack
+	asm("ret");
+	asm("UDiv64b:");
+	asm("mov ebx, 1");
+	asm("sub eax, esi");				// subtract divisor from dividend
+	asm("sbb edx, edi");
+	asm("jnc short UDiv64d");			// if no borrow, result=1, remainder in edx:eax
+	asm("add eax, esi");				// else add back
+	asm("adc edx, edi");
+	asm("dec ebx");						// and decrement quotient
+	asm("UDiv64d:");
+	asm("mov edi, edx");				// remainder into edi:edx
+	asm("mov edx, eax");
+	asm("mov eax, ebx");				// result in ebx:eax
+	asm("xor ebx, ebx");
+	asm("ret");
+	}
+
+__NAKED__ void _aulldvrm()
+//
+// Divide two 64 bit unsigned integers, returning a 64 bit result
+// and a 64 bit remainder
+//
+// On entry:
+//		[esp+4], [esp+8] = dividend
+//		[esp+12], [esp+16] = divisor
+//
+// Return (dividend / divisor) in edx:eax
+// Return (dividend % divisor) in ebx:ecx
+//
+// Remove arguments from stack
+//
+	{
+	asm("push ebp");
+	asm("push edi");
+	asm("push esi");
+	asm("mov eax, [esp+16]");
+	asm("mov edx, [esp+20]");
+	asm("mov esi, [esp+24]");
+	asm("mov edi, [esp+28]");
+	asm("call %a0": : "i"(&UDiv64));
+	asm("mov ecx, edx");
+	asm("mov edx, ebx");
+	asm("mov ebx, edi");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("ret");
+	}
+
+__NAKED__ void _alldvrm()
+//
+// Divide two 64 bit signed integers, returning a 64 bit result
+// and a 64 bit remainder
+//
+// On entry:
+//		[esp+4], [esp+8] = dividend
+//		[esp+12], [esp+16] = divisor
+//
+// Return (dividend / divisor) in edx:eax
+// Return (dividend % divisor) in ebx:ecx
+//
+// Remove arguments from stack
+//
+	{
+	asm("push ebp");
+	asm("push edi");
+	asm("push esi");
+	asm("mov eax, [esp+16]");
+	asm("mov edx, [esp+20]");
+	asm("mov esi, [esp+24]");
+	asm("mov edi, [esp+28]");
+	asm("test edx, edx");
+	asm("jns alldrvm_dividend_nonnegative");
+	asm("neg edx");
+	asm("neg eax");
+	asm("sbb edx, 0");
+	asm("alldrvm_dividend_nonnegative:");
+	asm("test edi, edi");
+	asm("jns alldrvm_divisor_nonnegative");
+	asm("neg edi");
+	asm("neg esi");
+	asm("sbb edi, 0");
+	asm("alldrvm_divisor_nonnegative:");
+	asm("call %a0": : "i"(&UDiv64));
+	asm("mov ebp, [esp+20]");
+	asm("mov ecx, edx");
+	asm("xor ebp, [esp+28]");
+	asm("mov edx, ebx");
+	asm("mov ebx, edi");
+	asm("jns alldrvm_quotient_nonnegative");
+	asm("neg edx");
+	asm("neg eax");
+	asm("sbb edx, 0");
+	asm("alldrvm_quotient_nonnegative:");
+	asm("cmp dword ptr [esp+20], 0");
+	asm("jns alldrvm_rem_nonnegative");
+	asm("neg ebx");
+	asm("neg ecx");
+	asm("sbb ebx, 0");
+	asm("alldrvm_rem_nonnegative:");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("ret");
+	}
+
+//__NAKED__ void _aulldiv()
+__NAKED__ void __udivdi3 ()
+//
+// Divide two 64 bit unsigned integers returning a 64 bit result
+// On entry:
+//		[esp+4], [esp+8] = dividend
+//		[esp+12], [esp+16] = divisor
+// Return result in edx:eax
+// Remove arguments from stack
+//
+	{
+	asm("push ebp");
+	asm("push edi");
+	asm("push esi");
+	asm("push ebx");
+	asm("mov eax, [esp+20]");
+	asm("mov edx, [esp+24]");
+	asm("mov esi, [esp+28]");
+	asm("mov edi, [esp+32]");
+	asm("call %a0": : "i"(&UDiv64));
+	asm("mov edx, ebx");
+	asm("pop ebx");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("ret");
+	}
+
+
+__NAKED__ void __divdi3()
+
+//
+// Divide two 64 bit signed integers returning a 64 bit result
+// On entry:
+//		[esp+4], [esp+8] = dividend
+//		[esp+12], [esp+16] = divisor
+// Return result in edx:eax
+// Remove arguments from stack
+//
+	{
+	asm("push ebp");
+	asm("push edi");
+	asm("push esi");
+	asm("push ebx");
+	asm("mov eax, [esp+20]");
+	asm("mov edx, [esp+24]");
+	asm("mov esi, [esp+28]");
+	asm("mov edi, [esp+32]");
+	asm("test edx, edx");
+	asm("jns divdi_dividend_nonnegative");
+	asm("neg edx");
+	asm("neg eax");
+	asm("sbb edx, 0");
+	asm("divdi_dividend_nonnegative:");
+	asm("test edi, edi");
+	asm("jns divdi_divisor_nonnegative");
+	asm("neg edi");
+	asm("neg esi");
+	asm("sbb edi, 0");
+	asm("divdi_divisor_nonnegative:");
+	asm("call %a0": : "i"(&UDiv64));
+	asm("mov ecx, [esp+24]");
+	asm("mov edx, ebx");
+	asm("xor ecx, [esp+32]");
+	asm("jns divdi_quotient_nonnegative");
+	asm("neg edx");
+	asm("neg eax");
+	asm("sbb edx, 0");
+	asm("divdi_quotient_nonnegative:");
+	asm("pop ebx");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("ret");
+	}
+
+__NAKED__ void __umoddi3()
+//
+// Divide two 64 bit unsigned integers and return 64 bit remainder
+// On entry:
+//		[esp+4], [esp+8] = dividend
+//		[esp+12], [esp+16] = divisor
+// Return result in edx:eax
+// Remove arguments from stack
+//
+	{
+	asm("push ebp");
+	asm("push edi");
+	asm("push esi");
+	asm("push ebx");
+	asm("mov eax, [esp+20]");
+	asm("mov edx, [esp+24]");
+	asm("mov esi, [esp+28]");
+	asm("mov edi, [esp+32]");
+	asm("call %a0": : "i"(&UDiv64));
+	asm("mov eax, edx");
+	asm("mov edx, edi");
+	asm("pop ebx");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("ret");
+	}
+
+__NAKED__ void __moddi3()
+//
+// Divide two 64 bit signed integers and return 64 bit remainder
+// On entry:
+//		[esp+4], [esp+8] = dividend
+//		[esp+12], [esp+16] = divisor
+// Return result in edx:eax
+// Remove arguments from stack
+//
+	{
+	asm("push ebp");
+	asm("push edi");
+	asm("push esi");
+	asm("push ebx");
+	asm("mov eax, [esp+20]");
+	asm("mov edx, [esp+24]");
+	asm("mov esi, [esp+28]");
+	asm("mov edi, [esp+32]");
+	asm("test edx, edx");
+	asm("jns dividend_nonnegative");
+	asm("neg edx");
+	asm("neg eax");
+	asm("sbb edx, 0");
+	asm("dividend_nonnegative:");
+	asm("test edi, edi");
+	asm("jns divisor_nonnegative");
+	asm("neg edi");
+	asm("neg esi");
+	asm("sbb edi, 0");
+	asm("divisor_nonnegative:");
+	asm("call %a0": : "i"(&UDiv64));
+	asm("mov eax, edx");
+	asm("mov edx, edi");
+	asm("cmp dword ptr [esp+24], 0");
+	asm("jns rem_nonnegative");
+	asm("neg edx");
+	asm("neg eax");
+	asm("sbb edx, 0");
+	asm("rem_nonnegative:");
+	asm("pop ebx");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("ret");
+	}
+
+__NAKED__ void _allshr()
+//
+// Arithmetic shift right EDX:EAX by CL
+//
+	{
+	asm("cmp cl, 64");
+	asm("jae asr_count_ge_64");
+	asm("cmp cl, 32");
+	asm("jae asr_count_ge_32");
+	asm("shrd eax, edx, cl");
+	asm("sar edx, cl");
+	asm("ret");
+	asm("asr_count_ge_32:");
+	asm("sub cl, 32");
+	asm("mov eax, edx");
+	asm("cdq");
+	asm("sar eax, cl");
+	asm("ret");
+	asm("asr_count_ge_64:");
+	asm("sar edx, 32");
+	asm("mov eax, edx");
+	asm("ret");
+	}
+
+__NAKED__ void _allshl()
+//
+// shift left EDX:EAX by CL
+//
+	{
+	asm("cmp cl, 64");
+	asm("jae lsl_count_ge_64");
+	asm("cmp cl, 32");
+	asm("jae lsl_count_ge_32");
+	asm("shld edx, eax, cl");
+	asm("shl eax, cl");
+	asm("ret");
+	asm("lsl_count_ge_32:");
+	asm("sub cl, 32");
+	asm("mov edx, eax");
+	asm("xor eax, eax");
+	asm("shl edx, cl");
+	asm("ret");
+	asm("lsl_count_ge_64:");
+	asm("xor edx, edx");
+	asm("xor eax, eax");
+	asm("ret");
+	}
+
+__NAKED__ void _aullshr()
+//
+// Logical shift right EDX:EAX by CL
+//
+	{
+	asm("cmp cl, 64");
+	asm("jae lsr_count_ge_64");
+	asm("cmp cl, 32");
+	asm("jae lsr_count_ge_32");
+	asm("shrd eax, edx, cl");
+	asm("shr edx, cl");
+	asm("ret");
+	asm("lsr_count_ge_32:");
+	asm("sub cl, 32");
+	asm("mov eax, edx");
+	asm("xor edx, edx");
+	asm("shr eax, cl");
+	asm("ret");
+	asm("lsr_count_ge_64:");
+	asm("xor edx, edx");
+	asm("xor eax, eax");
+	asm("ret");
+	}
+
+}