kernel/eka/include/x86hlp_gcc.inl
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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 "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-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");
	}

}