[llvm-commits] [PATCH 9/10] Initial support for PowerPC64 MCJIT
Roman Divacky
rdivacky at freebsd.org
Wed Sep 19 11:09:45 PDT 2012
Some comments below.
On Wed, Sep 19, 2012 at 10:04:20AM -0300, Adhemerval Zanella wrote:
> On 09/18/2012 05:34 PM, Jim Grosbach wrote:
> > Yeah, there is unfortunately some current code which already violates the host/target relationship. I'm in the process of cleaning some of that up, partly because it sets a misleading example.
> >
> > Anyways, thanks again for working on this for PPC. It's great to see all the progress there recently.
> >
> > -Jim
>
> I believe this patch has a better approach now: both the stub and relocation are done
> using byte stores. I also corrected the indentation in switch/case you pointed
> early.
>
>
> --
> Adhemerval Zanella Netto
> Software Engineer
> Linux Technology Center Brazil
> Toolchain / GLIBC on Power Architecture
> azanella at linux.vnet.ibm.com / azanella at br.ibm.com
> +55 61 8642-9890
>
> >From a48b8044780c1764a55fbfccfb63681b7c944009 Mon Sep 17 00:00:00 2001
> From: Adhemerval Zanella <azanella at linux.vnet.ibm.com>
> Date: Mon, 17 Sep 2012 12:32:35 -0500
> Subject: [PATCH 10/12] Initial support for PowerPC64 MCJIT
>
> ---
> lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | 18 ++
> lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 276 +++++++++++++++++++-
> lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h | 11 +
> lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h | 33 +++
> 4 files changed, 336 insertions(+), 2 deletions(-)
>
> diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
> index 880129d..5ffb68a 100644
> --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
> +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
> @@ -362,6 +362,24 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
> StubAddr++;
> *StubAddr = NopInstr;
> return Addr;
> + } else if (Arch == Triple::ppc64) {
> + // PowerPC64 stub: the address points to a function descriptor
> + // instead of the function itself. Load the function address
> + // on r11 and sets it to control register. Also loads the function
> + // TOC in r2 and environment pointer to r11.
> + writeInt32BE(Addr, 0x3D800000); // lis r12, highest(addr)
> + writeInt32BE(Addr+4, 0x618C0000); // ori r12, higher(addr)
> + writeInt32BE(Addr+8, 0x798C07C6); // sldi r12, r12, 32
> + writeInt32BE(Addr+12, 0x658C0000); // oris r12, r12, h(addr)
> + writeInt32BE(Addr+16, 0x618C0000); // ori r12, r12, l(addr)
> + writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1)
> + writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12)
> + writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12)
> + writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11
> + writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2)
> + writeInt32BE(Addr+40, 0x4E800420); // bctr
> +
> + return Addr;
> }
> return Addr;
> }
> diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
> index a1c0e40..5742a1d 100644
> --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
> +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
> @@ -27,6 +27,14 @@ using namespace llvm::object;
>
> namespace {
>
> +static inline
> +error_code Check(error_code Err) {
> + if (Err) {
> + report_fatal_error(Err.message());
> + }
> + return Err;
> +}
> +
> template<support::endianness target_endianness, bool is64Bits>
> class DyldELFObject : public ELFObjectFile<target_endianness, is64Bits> {
> LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
> @@ -343,6 +351,180 @@ void RuntimeDyldELF::resolveMIPSRelocation(uint8_t *LocalAddress,
> }
> }
>
> +// Return the .TOC. section address to R_PPC64_TOC relocations.
> +uint64_t RuntimeDyldELF::findPPC64TOC() const {
> + // The TOC consists of sections .got, .toc, .tocbss, .plt in that
> + // order. The TOC starts where the first of these sections starts.
> + SectionList::const_iterator it = Sections.begin();
> + for (; it != Sections.end(); ++it) {
Dont evaluate Sections.end() on every iteration. Create ie = Sections.end()
and check against it. Thats the preferred llvm style.
> + if (it->Name == ".got")
> + break;
> + if (it->Name == ".toc")
> + break;
> + if (it->Name == ".tocbss")
> + break;
> + if (it->Name == ".plt")
> + break;
> + }
Can you reflow this to use else if?
> + if (it == Sections.end()) {
> + // This may happen for
> + // * references to TOC base base (sym at toc, .odp relocation) without
> + // a .toc directive.
> + // In this case just use the first section (which is usually
> + // the .odp) since the code won't reference the .toc base
> + // directly.
> + it = Sections.begin();
> + }
> + assert (it != Sections.end());
> + // Per the ppc64-elf-linux ABI, The TOC base if TOC value plus 0x8000
> + // thus permitting a full 64 Kbytes segment.
> + return (*it).LoadAddress + 0x8000;
Use it->LoadAddress.
> +}
> +
> +// Returns the sections and offset associated with the ODP entry referenced
> +// by Symbol.
> +void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj,
> + ObjSectionToIDMap &LocalSections,
> + RelocationValueRef &Rel) {
> + // Get the ELF symbol value (st_value) to compare with Relocation offset in
> + // .opd entries
> +
> + error_code err;
> + for (section_iterator si = Obj.begin_sections(),
> + se = Obj.end_sections(); si != se; si.increment(err)) {
> + StringRef SectionName;
> + Check(si->getName(SectionName));
> + if (SectionName != ".opd")
> + continue;
> +
> + for (relocation_iterator i = si->begin_relocations(),
> + e = si->end_relocations(); i != e;) {
> + Check(err);
> +
> + // The R_PPC64_ADDR64 relocation indicates the first field
> + // of a .opd entry
> + uint64_t TypeFunc;
> + Check(i->getType(TypeFunc));
> + if (TypeFunc != ELF::R_PPC64_ADDR64) {
> + i.increment(err);
> + continue;
> + }
> +
> + SymbolRef TargetSymbol;
> + Check(i->getSymbol(TargetSymbol));
> + uint64_t TargetSymbolOffset;
> + Check(i->getOffset(TargetSymbolOffset));
> + int64_t TargetAdditionalInfo;
> + Check(i->getAdditionalInfo(TargetAdditionalInfo));
Please declare all variables first and then Check all of them at once.
> +
> + i = i.increment(err);
> + if (i == e)
> + break;
> + Check(err);
> +
> + // Just check if following relocation is a R_PPC64_TOC
> + uint64_t TypeTOC;
> + Check(i->getType(TypeTOC));
> + if (TypeTOC != ELF::R_PPC64_TOC)
> + continue;
> +
> + // Finally compares the Symbol value and the target symbol offset
> + // to check if this .opd entry refers to the symbol the relocation
> + // points to.
> + if (Rel.Addend != (intptr_t)TargetSymbolOffset)
> + continue;
> +
> + section_iterator tsi(Obj.end_sections());
> + Check(TargetSymbol.getSection(tsi));
> + Rel.SectionID = findOrEmitSection(Obj, (*tsi), true, LocalSections);
> + Rel.Addend = (intptr_t)TargetAdditionalInfo;
> + return;
> + }
> + }
> + llvm_unreachable("Attempting to get address of ODP entry!");
> +}
> +
> +// Relocation masks following the #lo(value), #hi(value), #higher(value),
> +// and #highest(value) macros defined in section 4.5.1. Relocation Types
> +// in PPC-elf64abi document.
> +//
> +static inline
> +uint16_t applyPPClo (uint64_t value)
> +{
> + return value & 0xffff;
> +}
> +
> +static inline
> +uint16_t applyPPChi (uint64_t value)
> +{
> + return (value >> 16) & 0xffff;
> +}
> +
> +static inline
> +uint16_t applyPPChigher (uint64_t value)
> +{
> + return (value >> 32) & 0xffff;
> +}
> +
> +static inline
> +uint16_t applyPPChighest (uint64_t value)
> +{
> + return (value >> 48) & 0xffff;
> +}
> +
> +void RuntimeDyldELF::resolvePPC64Relocation(uint8_t *LocalAddress,
> + uint64_t FinalAddress,
> + uint64_t Value,
> + uint32_t Type,
> + int64_t Addend) {
> + switch (Type) {
> + default:
> + llvm_unreachable("Relocation type not implemented yet!");
> + break;
> + case ELF::R_PPC64_ADDR16_LO :
> + writeInt16BE(LocalAddress, applyPPClo (Value + Addend));
> + break;
> + case ELF::R_PPC64_ADDR16_HI :
> + writeInt16BE(LocalAddress, applyPPChi (Value + Addend));
> + break;
> + case ELF::R_PPC64_ADDR16_HIGHER :
> + writeInt16BE(LocalAddress, applyPPChigher (Value + Addend));
> + break;
> + case ELF::R_PPC64_ADDR16_HIGHEST :
> + writeInt16BE(LocalAddress, applyPPChighest (Value + Addend));
> + break;
> + case ELF::R_PPC64_ADDR14 : {
> + assert(((Value + Addend) & 3) == 0);
> + uint16_t *insn = ((uint16_t*)LocalAddress+1);
> + writeInt16BE(LocalAddress + 2, (*insn & 3) | ((Value + Addend) & 0xfffc));
Can you please add the comment here why +1 and +2? It's not obvious.
> + } break;
> + case ELF::R_PPC64_REL24 : {
> + int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend);
> + if (SignExtend32<24>(delta) != delta)
> + llvm_unreachable("Relocation R_PPC64_REL24 overflow");
> + // Generates a 'bl <address>' instruction
> + writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC));
> + } break;
> + case ELF::R_PPC64_ADDR64 :
> + writeInt64BE(LocalAddress, Value + Addend);
> + break;
> + case ELF::R_PPC64_TOC :
> + writeInt64BE(LocalAddress, findPPC64TOC());
> + break;
> + case ELF::R_PPC64_TOC16 : {
> + uint64_t TOCStart = findPPC64TOC();
> + Value = applyPPClo((Value + Addend) - TOCStart);
> + writeInt16BE(LocalAddress, applyPPClo(Value));
> + } break;
> + case ELF::R_PPC64_TOC16_DS : {
> + uint64_t TOCStart = findPPC64TOC();
> + Value = ((Value + Addend) - TOCStart);
> + writeInt16BE(LocalAddress, applyPPClo(Value));
> + } break;
> + }
> +}
> +
> +
> void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
> uint64_t FinalAddress,
> uint64_t Value,
> @@ -369,6 +551,9 @@ void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
> (uint32_t)(Value & 0xffffffffL), Type,
> (uint32_t)(Addend & 0xffffffffL));
> break;
> + case Triple::ppc64:
> + resolvePPC64Relocation(LocalAddress, FinalAddress, Value, Type, Addend);
> + break;
> default: llvm_unreachable("Unsupported CPU type!");
> }
> }
> @@ -393,6 +578,8 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel,
> RelocationValueRef Value;
> // First search for the symbol in the local symbol table
> SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data());
> + SymbolRef::Type SymType;
> + Symbol.getType(SymType);
> if (lsi != Symbols.end()) {
> Value.SectionID = lsi->second.first;
> Value.Addend = lsi->second.second;
> @@ -404,8 +591,6 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel,
> Value.SectionID = gsi->second.first;
> Value.Addend = gsi->second.second;
> } else {
> - SymbolRef::Type SymType;
> - Symbol.getType(SymType);
> switch (SymType) {
> case SymbolRef::ST_Debug: {
> // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously
> @@ -513,6 +698,93 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel,
> Section.StubOffset, RelType, 0);
> Section.StubOffset += getMaxStubSize();
> }
> + } else if (Arch == Triple::ppc64) {
> + if (RelType == ELF::R_PPC64_REL24) {
> + // A PPC branch relocation will need a stub function if the target is
> + // an external symbol (Symbol::ST_Unknown) or if the target address
> + // is not within the signed 24-bits branch address.
> + SectionEntry &Section = Sections[Rel.SectionID];
> + uint8_t *Target = Section.Address + Rel.Offset;
> + bool RangeOverflow = false;
> + if (SymType != SymbolRef::ST_Unknown) {
> + // A function call may points to the .opd entry, so the final symbol value
> + // in calculated based in the relocation values in .opd section.
> + findOPDEntrySection(Obj, ObjSectionToID, Value);
> + uint8_t *RelocTarget = Sections[Value.SectionID].Address + Value.Addend;
> + int32_t delta = static_cast<int32_t>(Target - RelocTarget);
> + // If it is within 24-bits branch range, just set the branch target
> + if (SignExtend32<24>(delta) == delta) {
> + RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
> + if (Value.SymbolName)
> + addRelocationForSymbol(RE, Value.SymbolName);
> + else
> + addRelocationForSection(RE, Value.SectionID);
> + } else {
> + RangeOverflow = true;
> + }
> + }
> + if (SymType == SymbolRef::ST_Unknown || RangeOverflow == true) {
> + // It is an external symbol (SymbolRef::ST_Unknown) or within a range
> + // larger than 24-bits.
> + StubMap::const_iterator i = Stubs.find(Value);
> + if (i != Stubs.end()) {
> + // Symbol function stub already created, just relocate to it
> + resolveRelocation(Target, (uint64_t)Target, (uint64_t)Section.Address
> + + i->second, RelType, 0);
> + DEBUG(dbgs() << " Stub function found\n");
> + } else {
> + // Create a new stub function.
> + DEBUG(dbgs() << " Create a new stub function\n");
> + Stubs[Value] = Section.StubOffset;
> + uint8_t *StubTargetAddr = createStubFunction(Section.Address +
> + Section.StubOffset);
> + RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address,
> + ELF::R_PPC64_ADDR64, Value.Addend);
> +
> + // Generates the 64-bits address loads as exemplified in section
> + // 4.5.1 in PPC64 ELF ABI.
> + RelocationEntry REhst(Rel.SectionID,
> + StubTargetAddr - Section.Address + 2,
> + ELF::R_PPC64_ADDR16_HIGHEST, Value.Addend);
> + RelocationEntry REhr(Rel.SectionID,
> + StubTargetAddr - Section.Address + 6,
> + ELF::R_PPC64_ADDR16_HIGHER, Value.Addend);
> + RelocationEntry REh(Rel.SectionID,
> + StubTargetAddr - Section.Address + 14,
> + ELF::R_PPC64_ADDR16_HI, Value.Addend);
> + RelocationEntry REl(Rel.SectionID,
> + StubTargetAddr - Section.Address + 18,
> + ELF::R_PPC64_ADDR16_LO, Value.Addend);
> +
> + if (Value.SymbolName) {
> + addRelocationForSymbol(REhst, Value.SymbolName);
> + addRelocationForSymbol(REhr, Value.SymbolName);
> + addRelocationForSymbol(REh, Value.SymbolName);
> + addRelocationForSymbol(REl, Value.SymbolName);
> + } else {
> + addRelocationForSection(REhst, Value.SectionID);
> + addRelocationForSection(REhr, Value.SectionID);
> + addRelocationForSection(REh, Value.SectionID);
> + addRelocationForSection(REl, Value.SectionID);
> + }
> +
> + resolveRelocation(Target, (uint64_t)Target, (uint64_t)Section.Address
> + + Section.StubOffset, RelType, 0);
> + if (SymType == SymbolRef::ST_Unknown)
> + // Restore the TOC for external calls
> + *((uint32_t*)Target+1) = 0xE8410028; // ld r2,40(r1)
Is the alignment ok here as Jim Grosbnach mentioned?
> + Section.StubOffset += getMaxStubSize();
> + }
> + }
> + } else {
> + RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
> + // Extra check to avoid relocation againt empty symbols (usually
> + // the R_PPC64_TOC).
> + if (Value.SymbolName && !TargetName.empty())
> + addRelocationForSymbol(RE, Value.SymbolName);
> + else
> + addRelocationForSection(RE, Value.SectionID);
> + }
> } else {
> RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
> if (Value.SymbolName)
> diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
> index eade49e..997351b 100644
> --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
> +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
> @@ -48,6 +48,12 @@ protected:
> uint32_t Type,
> int32_t Addend);
>
> + void resolvePPC64Relocation(uint8_t *LocalAddress,
> + uint64_t FinalAddress,
> + uint64_t Value,
> + uint32_t Type,
> + int64_t Addend);
> +
> virtual void resolveRelocation(uint8_t *LocalAddress,
> uint64_t FinalAddress,
> uint64_t Value,
> @@ -63,6 +69,11 @@ protected:
> virtual ObjectImage *createObjectImage(const MemoryBuffer *InputBuffer);
> virtual void handleObjectLoaded(ObjectImage *Obj);
>
> + uint64_t findPPC64TOC() const;
> + void findOPDEntrySection(ObjectImage &Obj,
> + ObjSectionToIDMap &LocalSections,
> + RelocationValueRef &Rel);
> +
> public:
> RuntimeDyldELF(RTDyldMemoryManager *mm)
> : RuntimeDyldImpl(mm), LoadedObject(0) {}
> diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
> index b29ff40..444d095 100644
> --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
> +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
> @@ -24,6 +24,8 @@
> #include "llvm/Support/Debug.h"
> #include "llvm/Support/ErrorHandling.h"
> #include "llvm/Support/Format.h"
> +#include "llvm/Support/Host.h"
> +#include "llvm/Support/SwapByteOrder.h"
> #include "llvm/Support/raw_ostream.h"
> #include "llvm/Support/system_error.h"
> #include <map>
> @@ -166,6 +168,8 @@ protected:
> return 8; // 32-bit instruction and 32-bit address
> else if (Arch == Triple::mipsel)
> return 16;
> + else if (Arch == Triple::ppc64)
> + return 44;
> else
> return 0;
> }
> @@ -188,6 +192,35 @@ protected:
> return (uint8_t*)Sections[SectionID].Address;
> }
>
> + void writeInt16BE(uint8_t *Addr, uint16_t Value) {
> + if (sys::isLittleEndianHost())
> + Value = sys::SwapByteOrder(Value);
> + *Addr = (Value >> 8) & 0xFF;
> + *(Addr+1) = Value & 0xFF;
> + }
> +
> + void writeInt32BE(uint8_t *Addr, uint32_t Value) {
> + if (sys::isLittleEndianHost())
> + Value = sys::SwapByteOrder(Value);
> + *Addr = (Value >> 24) & 0xFF;
> + *(Addr+1) = (Value >> 16) & 0xFF;
> + *(Addr+2) = (Value >> 8) & 0xFF;
> + *(Addr+3) = Value & 0xFF;
> + }
> +
> + void writeInt64BE(uint8_t *Addr, uint64_t Value) {
> + if (sys::isLittleEndianHost())
> + Value = sys::SwapByteOrder(Value);
> + *Addr = (Value >> 56) & 0xFF;
> + *(Addr+1) = (Value >> 48) & 0xFF;
> + *(Addr+2) = (Value >> 40) & 0xFF;
> + *(Addr+3) = (Value >> 32) & 0xFF;
> + *(Addr+4) = (Value >> 24) & 0xFF;
> + *(Addr+5) = (Value >> 16) & 0xFF;
> + *(Addr+6) = (Value >> 8) & 0xFF;
> + *(Addr+7) = Value & 0xFF;
> + }
> +
> /// \brief Given the common symbols discovered in the object file, emit a
> /// new section for them and update the symbol mappings in the object and
> /// symbol table.
> --
> 1.7.1
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list