diff --git a/makefile b/makefile index ccd6c8ada9..50f813d75b 100644 --- a/makefile +++ b/makefile @@ -3,7 +3,11 @@ MAKEFLAGS = -s name = avian version = 0.4 -build-arch := $(shell uname -m | sed 's/^i.86$$/i386/' | sed 's/^arm.*$$/arm/') +build-arch := $(shell uname -m \ + | sed 's/^i.86$$/i386/' \ + | sed 's/^arm.*$$/arm/' \ + | sed 's/ppc/powerpc/') + ifeq (Power,$(filter Power,$(build-arch))) build-arch = powerpc endif diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index 8af5c0cd58..44915282bb 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -35,6 +35,7 @@ #define EV_CURRENT 1 #define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 #define ELFOSABI_SYSV 0 @@ -43,6 +44,7 @@ #define EM_386 3 #define EM_X86_64 62 #define EM_ARM 40 +#define EM_PPC 20 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 @@ -77,7 +79,6 @@ # error #endif -#define Data ELFDATA2LSB #define OSABI ELFOSABI_SYSV namespace { @@ -178,7 +179,7 @@ void writeObject(const uint8_t* data, unsigned size, FILE* out, const char* startName, const char* endName, const char* sectionName, unsigned sectionFlags, - unsigned alignment, int machine) + unsigned alignment, int machine, int encoding) { const unsigned sectionCount = 5; const unsigned symbolCount = 2; @@ -222,7 +223,7 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, fileHeader.e_ident[EI_MAG2] = ELFMAG2; fileHeader.e_ident[EI_MAG3] = ELFMAG3; fileHeader.e_ident[EI_CLASS] = Class; - fileHeader.e_ident[EI_DATA] = Data; + fileHeader.e_ident[EI_DATA] = encoding; fileHeader.e_ident[EI_VERSION] = EV_CURRENT; fileHeader.e_ident[EI_OSABI] = OSABI; fileHeader.e_ident[EI_ABIVERSION] = 0; @@ -349,12 +350,19 @@ MAKE_NAME(writeElf, BITS_PER_WORD, Object) bool writable, bool executable) { int machine; + int encoding; if (strcmp(architecture, "x86_64") == 0) { machine = EM_X86_64; + encoding = ELFDATA2LSB; } else if (strcmp(architecture, "i386") == 0) { machine = EM_386; + encoding = ELFDATA2LSB; } else if (strcmp(architecture, "arm") == 0) { machine = EM_ARM; + encoding = ELFDATA2LSB; + } else if (strcmp(architecture, "powerpc") == 0) { + machine = EM_PPC; + encoding = ELFDATA2MSB; } else { fprintf(stderr, "unsupported architecture: %s\n", architecture); return false; @@ -376,7 +384,7 @@ MAKE_NAME(writeElf, BITS_PER_WORD, Object) } writeObject(data, size, out, startName, endName, sectionName, sectionFlags, - alignment, machine); + alignment, machine, encoding); return true; } diff --git a/src/binaryToObject/main.cpp b/src/binaryToObject/main.cpp index c95f193d3d..41f2951645 100644 --- a/src/binaryToObject/main.cpp +++ b/src/binaryToObject/main.cpp @@ -73,8 +73,10 @@ writeObject(uint8_t* data, unsigned size, FILE* out, const char* startName, success = writeElf64Object (data, size, out, startName, endName, architecture, alignment, writable, executable); - } else if (strcmp("i386", architecture) == 0 || - strcmp("arm", architecture) == 0) { + } else if (strcmp("i386", architecture) == 0 + or strcmp("arm", architecture) == 0 + or strcmp("powerpc", architecture) == 0) + { found = true; success = writeElf32Object (data, size, out, startName, endName, architecture, alignment, diff --git a/src/common.h b/src/common.h index 13957bedfd..5c7160e54c 100644 --- a/src/common.h +++ b/src/common.h @@ -88,7 +88,7 @@ alias(void* p, unsigned offset) # define ARCH_x86_32 # elif defined __x86_64__ # define ARCH_x86_64 -# elif defined __POWERPC__ +# elif (defined __POWERPC__) || (defined __powerpc__) # define ARCH_powerpc # elif defined __arm__ # define ARCH_arm diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 68e4d8acd2..546432beb3 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -13,16 +13,21 @@ .text #define BYTES_PER_WORD 4 -#define LINKAGE_AREA 6 -#define ARGUMENT_BASE BYTES_PER_WORD * LINKAGE_AREA - -#define LOCAL(x) L##x #ifdef __APPLE__ # define GLOBAL(x) _##x +# define LOCAL(x) L##x +# define LINKAGE_AREA 6 +# define RETURN_ADDRESS_OFFSET 8 #else -# define GLOBAL(x) x +# define GLOBAL(x) x +# define LOCAL(x) .L##x +# define LINKAGE_AREA 2 +# define RETURN_ADDRESS_OFFSET 4 +# include "powerpc-regs.S" #endif + +#define ARGUMENT_BASE BYTES_PER_WORD * LINKAGE_AREA #define THREAD_STACK 2148 #define THREAD_CONTINUATION 2156 @@ -42,7 +47,7 @@ GLOBAL(vmInvoke): // save return address mflr r0 - stw r0,8(r1) + stw r0,RETURN_ADDRESS_OFFSET(r1) // r3: thread // r4: function @@ -53,12 +58,10 @@ GLOBAL(vmInvoke): // r9: temporary - // save return type - stw r8,44(r1) - - // allocate stack space, adding room for callee-saved registers + // allocate stack space, adding room for callee-saved registers and + // return type subfic r9,r7,-80 - stwux r1,r1,r9 + stwux r1,r1,r9 // save callee-saved registers add r9,r7,r1 @@ -83,6 +86,9 @@ GLOBAL(vmInvoke): stw r30,68(r9) stw r31,72(r9) + // save return type + stw r8,74(r9) + // we use r13 to hold the thread pointer, by convention mr r13,r3 @@ -213,11 +219,11 @@ LOCAL(vmInvoke_exit): lwz r31,72(r9) // handle return value based on expected type - lwz r8,44(r1) + lwz r8,74(r9) LOCAL(vmInvoke_return): // load return address - lwz r0,8(r1) + lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 // return diff --git a/src/compiler.cpp b/src/compiler.cpp index 18dc98e06f..2d809b1c5e 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2171,9 +2171,9 @@ class MemorySite: public Site { } virtual Site* makeNextWord(Context* c, unsigned index) { - // todo: endianness? return memorySite - (c, base, offset + (index == 1 ? BytesPerWord : -BytesPerWord), + (c, base, offset + ((index == 1) xor c->arch->bigEndian() + ? BytesPerWord : -BytesPerWord), this->index, scale); } @@ -2184,12 +2184,11 @@ class MemorySite: public Site { } virtual SiteMask nextWordMask(Context* c, unsigned index) { - // todo: endianness? int frameIndex; if (base == c->arch->stack()) { assert(c, this->index == NoRegister); frameIndex = static_cast(offsetToFrameIndex(c, offset)) - + (index == 1 ? 1 : -1); + + ((index == 1) xor c->arch->bigEndian() ? 1 : -1); } else { frameIndex = NoFrameIndex; } diff --git a/src/powerpc-regs.S b/src/powerpc-regs.S new file mode 100644 index 0000000000..da5940f403 --- /dev/null +++ b/src/powerpc-regs.S @@ -0,0 +1,64 @@ +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 +#define f0 0 +#define f1 1 +#define f2 2 +#define f3 3 +#define f4 4 +#define f5 5 +#define f6 6 +#define f7 7 +#define f8 8 +#define f9 9 +#define f10 10 +#define f11 11 +#define f12 12 +#define f13 13 +#define f14 14 +#define f15 15 +#define f16 16 +#define f17 17 +#define f18 18 +#define f19 19 +#define f20 20 +#define f21 21 +#define f22 22 +#define f23 23 +#define f24 24 +#define f25 25 +#define f26 26 +#define f27 27 +#define f28 28 +#define f29 29 +#define f30 30 +#define f31 31 diff --git a/src/powerpc.S b/src/powerpc.S index 2b26f7985f..96bf382cfb 100644 --- a/src/powerpc.S +++ b/src/powerpc.S @@ -13,22 +13,28 @@ .text #define BYTES_PER_WORD 4 -#define LINKAGE_AREA 6 #define GPR_COUNT 8 -#define MEMORY_BASE BYTES_PER_WORD * (LINKAGE_AREA + GPR_COUNT) -#define LOCAL(x) L##x #ifdef __APPLE__ # define GLOBAL(x) _##x +# define LOCAL(x) L##x +# define LINKAGE_AREA 6 +# define MEMORY_BASE BYTES_PER_WORD * (LINKAGE_AREA + GPR_COUNT) +# define RETURN_ADDRESS_OFFSET 8 #else -# define GLOBAL(x) x +# define GLOBAL(x) x +# define LOCAL(x) .L##x +# define LINKAGE_AREA 2 +# define MEMORY_BASE BYTES_PER_WORD * LINKAGE_AREA +# define RETURN_ADDRESS_OFFSET 4 +# include "powerpc-regs.S" #endif .globl GLOBAL(vmNativeCall) GLOBAL(vmNativeCall): // save return address mflr r0 - stw r0,8(r1) + stw r0,RETURN_ADDRESS_OFFSET(r1) // r3 aka r13: function // r4 : stackTotal @@ -42,17 +48,26 @@ GLOBAL(vmNativeCall): // r16 : temporary // r17 : temporary // r18 : temporary - - // save registers used for local variables - stw r13,24(r1) - stw r14,28(r1) - stw r15,32(r1) - stw r16,36(r1) - stw r17,40(r1) - stw r18,44(r1) - // allocate stack space - stwux r1,r1,r4 + // allocate stack space, adding room for callee-saved registers and + // scratch space for copying a FP return value into GPRs + subfic r10,r4,-48 + stwux r1,r1,r10 + + // save callee-saved registers used for local variables + add r10,r4,r1 + + // save registers used for local variables + stw r13,0(r10) + stw r14,4(r10) + stw r15,8(r10) + stw r16,12(r10) + stw r17,16(r10) + stw r18,20(r10) + stw r19,24(r10) + + // remember where we saved the local variables + mr r19,r10 // save our argument registers so we can clobber them mr r13,r3 @@ -84,12 +99,14 @@ LOCAL(test): lfd f6,40(r8) lfd f7,48(r8) lfd f8,56(r8) +#ifdef __APPLE__ lfd f9,64(r8) lfd f10,72(r8) lfd f11,80(r8) lfd f12,88(r8) lfd f13,96(r8) - +#endif + LOCAL(gpr): // do we need to load the general-purpose registers? cmpwi r7,0 @@ -128,25 +145,26 @@ LOCAL(float): LOCAL(copy): // move floating point return value to GPRs via memory - stfd f1,8(r1) - lwz r3,8(r1) - lwz r4,12(r1) + stfd f1,32(r19) + lwz r3,32(r19) + lwz r4,36(r19) b LOCAL(exit) LOCAL(exit): + // restore callee-saved registers used for local variables + lwz r13,0(r19) + lwz r14,4(r19) + lwz r15,8(r19) + lwz r16,12(r19) + lwz r17,16(r19) + lwz r18,20(r19) + lwz r19,24(r19) + // restore stack pointer lwz r1,0(r1) - // restore registers used for local variables - lwz r13,24(r1) - lwz r14,28(r1) - lwz r15,32(r1) - lwz r16,36(r1) - lwz r17,40(r1) - lwz r18,44(r1) - // load return address - lwz r0,8(r1) + lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 // return @@ -171,7 +189,7 @@ GLOBAL(vmRun): // r5: checkpoint mflr r0 - stw r0,8(r1) + stw r0,RETURN_ADDRESS_OFFSET(r1) stwu r1,-(MEMORY_BASE+88)(r1) @@ -226,6 +244,6 @@ GLOBAL(vmRun_returnAddress): lwz r31,MEMORY_BASE+72(r1) lwz r1,0(r1) - lwz r0,8(r1) + lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 blr diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 6c721651ba..3644520647 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -162,7 +162,15 @@ carry16(intptr_t v) return static_cast(v) < 0 ? 1 : 0; } +#ifdef __APPLE__ const unsigned FrameFooterSize = 6; +const unsigned ReturnAddressOffset = 2; +const unsigned AlignArguments = false; +#else +const unsigned FrameFooterSize = 2; +const unsigned ReturnAddressOffset = 1; +const unsigned AlignArguments = true; +#endif const unsigned StackAlignmentInBytes = 16; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; @@ -1777,7 +1785,7 @@ nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size, // todo: check for and handle tail calls } - *ip = static_cast(*stack)[offset + 2]; + *ip = static_cast(*stack)[offset + ReturnAddressOffset]; *stack = static_cast(*stack) + offset; } @@ -1940,7 +1948,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual bool argumentAlignment() { - return false; + return AlignArguments; } virtual unsigned argumentRegisterCount() { @@ -2023,7 +2031,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual void* frameIp(void* stack) { - return stack ? static_cast(stack)[2] : 0; + return stack ? static_cast(stack)[ReturnAddressOffset] : 0; } virtual unsigned frameHeaderSize() { @@ -2039,7 +2047,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual int returnAddressOffset() { - return 8 / BytesPerWord; + return ReturnAddressOffset; } virtual int framePointerOffset() { @@ -2261,7 +2269,7 @@ class MyAssembler: public Assembler { Register returnAddress(0); emit(&c, mflr(returnAddress.low)); - Memory returnAddressDst(StackRegister, 8); + Memory returnAddressDst(StackRegister, ReturnAddressOffset * BytesPerWord); moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); Register stack(StackRegister); @@ -2314,7 +2322,7 @@ class MyAssembler: public Assembler { Register returnAddress(0); emit(&c, mflr(returnAddress.low)); - Memory returnAddressDst(StackRegister, 8); + Memory returnAddressDst(StackRegister, ReturnAddressOffset * BytesPerWord); moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); Register stack(StackRegister); @@ -2337,7 +2345,7 @@ class MyAssembler: public Assembler { moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); Register returnAddress(0); - Memory returnAddressSrc(StackRegister, 8); + Memory returnAddressSrc(StackRegister, ReturnAddressOffset * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress); emit(&c, mtlr(returnAddress.low)); @@ -2351,7 +2359,8 @@ class MyAssembler: public Assembler { if (TailCalls) { if (offset) { Register tmp(0); - Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord)); + Memory returnAddressSrc + (StackRegister, (ReturnAddressOffset + footprint) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); emit(&c, mtlr(tmp.low)); @@ -2366,7 +2375,8 @@ class MyAssembler: public Assembler { assert(&c, offset > 0); Register ras(returnAddressSurrogate); - Memory dst(StackRegister, 8 + (offset * BytesPerWord)); + Memory dst + (StackRegister, (ReturnAddressOffset + offset) * BytesPerWord); moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); } diff --git a/src/powerpc.h b/src/powerpc.h index b519ac8064..5fe4543cc7 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -14,8 +14,6 @@ #include "types.h" #include "common.h" -#define VA_LIST(x) (&(x)) - #ifdef __APPLE__ # include "mach/mach_types.h" # include "mach/ppc/thread_act.h" @@ -45,9 +43,17 @@ # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) -#else -# error "non-Apple PowerPC-based platforms not yet supported" -#endif +#define VA_LIST(x) (&(x)) + +#else // not __APPLE__ +# define IP_REGISTER(context) (context->uc_mcontext.regs->gpr[32]) +# define STACK_REGISTER(context) (context->uc_mcontext.regs->gpr[1]) +# define THREAD_REGISTER(context) (context->uc_mcontext.regs->gpr[13]) +# define LINK_REGISTER(context) (context->uc_mcontext.regs->gpr[36]) + +#define VA_LIST(x) (x) + +#endif // not __APPLE__ extern "C" uint64_t vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, @@ -150,13 +156,22 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, unsigned argumentCount, unsigned argumentsSize, unsigned returnType) { +#ifdef __APPLE__ +# define SKIP(var, count) var += count; +# define ALIGN(var) const unsigned LinkageArea = 24; + const unsigned FprCount = 13; +#else +# define SKIP(var, count) +# define ALIGN(var) if (var & 1) ++var; + const unsigned LinkageArea = 8; + const unsigned FprCount = 8; +#endif const unsigned GprCount = 8; uintptr_t gprTable[GprCount]; unsigned gprIndex = 0; - const unsigned FprCount = 13; uint64_t fprTable[FprCount]; unsigned fprIndex = 0; @@ -172,8 +187,8 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, double d = bitsToFloat(arguments[ai]); memcpy(fprTable + fprIndex, &d, 8); ++ fprIndex; - ++ gprIndex; - ++ stackSkip; + SKIP(gprIndex, 1); + SKIP(stackSkip, 1); } else { stack[stackIndex++] = arguments[ai]; } @@ -184,9 +199,10 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, if (fprIndex + (8 / BytesPerWord) <= FprCount) { memcpy(fprTable + fprIndex, arguments + ai, 8); ++ fprIndex; - gprIndex += 8 / BytesPerWord; - stackSkip += 8 / BytesPerWord; + SKIP(gprIndex, 8 / BytesPerWord); + SKIP(stackSkip, 8 / BytesPerWord); } else { + ALIGN(stackIndex); memcpy(stack + stackIndex, arguments + ai, 8); stackIndex += 8 / BytesPerWord; } @@ -195,10 +211,12 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, case INT64_TYPE: { if (gprIndex + (8 / BytesPerWord) <= GprCount) { + ALIGN(gprIndex); memcpy(gprTable + gprIndex, arguments + ai, 8); gprIndex += 8 / BytesPerWord; - stackSkip += 8 / BytesPerWord; + SKIP(stackSkip, 8 / BytesPerWord); } else { + ALIGN(stackIndex); memcpy(stack + stackIndex, arguments + ai, 8); stackIndex += 8 / BytesPerWord; } @@ -208,7 +226,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, default: { if (gprIndex < GprCount) { gprTable[gprIndex++] = arguments[ai]; - ++ stackSkip; + SKIP(stackSkip, 1); } else { stack[stackIndex++] = arguments[ai]; } @@ -219,8 +237,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, return vmNativeCall (function, - - ((((1 + stackSkip + stackIndex) * BytesPerWord) + LinkageArea + 15) - & -16), + (((1 + stackSkip + stackIndex) * BytesPerWord) + LinkageArea + 15) & -16, stack, stackIndex * BytesPerWord, (gprIndex ? gprTable : 0), (fprIndex ? fprTable : 0), returnType);