uint64_t Offset,
uint64_t Value,
uint32_t Type,
- int64_t Addend) {
+ int64_t Addend,
+ uint64_t SymOffset) {
switch (Type) {
default:
llvm_unreachable("Relocation type not implemented yet!");
<< " at " << format("%p\n",Target));
break;
}
+ case ELF::R_X86_64_GOTPCREL: {
+ // findGOTEntry returns the 'G + GOT' part of the relocation calculation
+ // based on the load/target address of the GOT (not the current/local addr).
+ uint64_t GOTAddr = findGOTEntry(Value, SymOffset);
+ uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset);
+ uint64_t FinalAddress = Section.LoadAddress + Offset;
+ // The processRelocationRef method combines the symbol offset and the addend
+ // and in most cases that's what we want. For this relocation type, we need
+ // the raw addend, so we subtract the symbol offset to get it.
+ int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress;
+ assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN);
+ int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
+ *Target = TruncOffset;
+ break;
+ }
case ELF::R_X86_64_PC32: {
// Get the placeholder value from the generated object since
// a previous relocation attempt may have overwritten the loaded version
*Target = TruncOffset;
break;
}
+ case ELF::R_X86_64_PC64: {
+ // Get the placeholder value from the generated object since
+ // a previous relocation attempt may have overwritten the loaded version
+ uint64_t *Placeholder = reinterpret_cast<uint64_t*>(Section.ObjAddress
+ + Offset);
+ uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + Offset);
+ uint64_t FinalAddress = Section.LoadAddress + Offset;
+ *Target = *Placeholder + Value + Addend - FinalAddress;
+ break;
+ }
}
}
// 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)
+ if (Rel.Addend != (int64_t)TargetSymbolOffset)
continue;
section_iterator tsi(Obj.end_sections());
void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE,
uint64_t Value) {
const SectionEntry &Section = Sections[RE.SectionID];
- return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend);
+ return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
+ RE.SymOffset);
}
void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
uint64_t Offset,
uint64_t Value,
uint32_t Type,
- int64_t Addend) {
+ int64_t Addend,
+ uint64_t SymOffset) {
switch (Arch) {
case Triple::x86_64:
- resolveX86_64Relocation(Section, Offset, Value, Type, Addend);
+ resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset);
break;
case Triple::x86:
resolveX86Relocation(Section, Offset,
}
if (lsi != Symbols.end()) {
Value.SectionID = lsi->second.first;
+ Value.Offset = lsi->second.second;
Value.Addend = lsi->second.second + Addend;
} else {
// Search for the symbol in the global symbol table
gsi = GlobalSymbolTable.find(TargetName.data());
if (gsi != GlobalSymbolTable.end()) {
Value.SectionID = gsi->second.first;
+ Value.Offset = gsi->second.second;
Value.Addend = gsi->second.second + Addend;
} else {
switch (SymType) {
Value.Addend = Addend;
break;
}
+ case SymbolRef::ST_Data:
case SymbolRef::ST_Unknown: {
Value.SymbolName = TargetName.data();
Value.Addend = Addend;
ELF::R_390_PC32DBL, Addend);
else
resolveRelocation(Section, Offset, StubAddress, RelType, Addend);
+ } else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) {
+ // The way the PLT relocations normally work is that the linker allocates the
+ // PLT and this relocation makes a PC-relative call into the PLT. The PLT
+ // entry will then jump to an address provided by the GOT. On first call, the
+ // GOT address will point back into PLT code that resolves the symbol. After
+ // the first call, the GOT entry points to the actual function.
+ //
+ // For local functions we're ignoring all of that here and just replacing
+ // the PLT32 relocation type with PC32, which will translate the relocation
+ // into a PC-relative call directly to the function. For external symbols we
+ // can't be sure the function will be within 2^32 bytes of the call site, so
+ // we need to create a stub, which calls into the GOT. This case is
+ // equivalent to the usual PLT implementation except that we use the stub
+ // mechanism in RuntimeDyld (which puts stubs at the end of the section)
+ // rather than allocating a PLT section.
+ if (Value.SymbolName) {
+ // This is a call to an external function.
+ // Look for an existing stub.
+ SectionEntry &Section = Sections[SectionID];
+ StubMap::const_iterator i = Stubs.find(Value);
+ uintptr_t StubAddress;
+ if (i != Stubs.end()) {
+ StubAddress = uintptr_t(Section.Address) + i->second;
+ DEBUG(dbgs() << " Stub function found\n");
+ } else {
+ // Create a new stub function (equivalent to a PLT entry).
+ DEBUG(dbgs() << " Create a new stub function\n");
+
+ uintptr_t BaseAddress = uintptr_t(Section.Address);
+ uintptr_t StubAlignment = getStubAlignment();
+ StubAddress = (BaseAddress + Section.StubOffset +
+ StubAlignment - 1) & -StubAlignment;
+ unsigned StubOffset = StubAddress - BaseAddress;
+ Stubs[Value] = StubOffset;
+ createStubFunction((uint8_t *)StubAddress);
+
+ // Create a GOT entry for the external function.
+ GOTEntries.push_back(Value);
+
+ // Make our stub function a relative call to the GOT entry.
+ RelocationEntry RE(SectionID, StubOffset + 2,
+ ELF::R_X86_64_GOTPCREL, -4);
+ addRelocationForSymbol(RE, Value.SymbolName);
+
+ // Bump our stub offset counter
+ Section.StubOffset = StubOffset + getMaxStubSize();
+ }
+
+ // Make the target call a call into the stub table.
+ resolveRelocation(Section, Offset, StubAddress,
+ ELF::R_X86_64_PC32, Addend);
+ } else {
+ RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend,
+ Value.Offset);
+ addRelocationForSection(RE, Value.SectionID);
+ }
} else {
- RelocationEntry RE(SectionID, Offset, RelType, Value.Addend);
+ if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_GOTPCREL) {
+ GOTEntries.push_back(Value);
+ }
+ RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, Value.Offset);
if (Value.SymbolName)
addRelocationForSymbol(RE, Value.SymbolName);
else
}
}
+void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) {
+ for (int i = 0, e = GOTEntries.size(); i != e; ++i) {
+ if (GOTEntries[i].SymbolName != 0 && GOTEntries[i].SymbolName == Name) {
+ GOTEntries[i].Offset = Addr;
+ }
+ }
+}
+
+size_t RuntimeDyldELF::getGOTEntrySize() {
+ // We don't use the GOT in all of these cases, but it's essentially free
+ // to put them all here.
+ size_t Result = 0;
+ switch (Arch) {
+ case Triple::x86_64:
+ case Triple::aarch64:
+ case Triple::ppc64:
+ case Triple::ppc64le:
+ case Triple::systemz:
+ Result = sizeof(uint64_t);
+ break;
+ case Triple::x86:
+ case Triple::arm:
+ case Triple::thumb:
+ case Triple::mips:
+ case Triple::mipsel:
+ Result = sizeof(uint32_t);
+ break;
+ default: llvm_unreachable("Unsupported CPU type!");
+ }
+ return Result;
+}
+
+uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress,
+ uint64_t Offset) {
+ assert(GOTSectionID != 0
+ && "Attempting to lookup GOT entry but the GOT was never allocated.");
+ if (GOTSectionID == 0) {
+ return 0;
+ }
+
+ size_t GOTEntrySize = getGOTEntrySize();
+
+ // Find the matching entry in our vector.
+ int GOTIndex = -1;
+ uint64_t SymbolOffset = 0;
+ for (int i = 0, e = GOTEntries.size(); i != e; ++i) {
+ if (GOTEntries[i].SymbolName == 0) {
+ if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress &&
+ GOTEntries[i].Offset == Offset) {
+ GOTIndex = i;
+ SymbolOffset = GOTEntries[i].Offset;
+ break;
+ }
+ } else {
+ // GOT entries for external symbols use the addend as the address when
+ // the external symbol has been resolved.
+ if (GOTEntries[i].Offset == LoadAddress) {
+ GOTIndex = i;
+ // Don't use the Addend here. The relocation handler will use it.
+ break;
+ }
+ }
+ }
+ assert(GOTIndex != -1 && "Unable to find requested GOT entry.");
+ if (GOTIndex == -1)
+ return 0;
+
+ if (GOTEntrySize == sizeof(uint64_t)) {
+ uint64_t *LocalGOTAddr = (uint64_t*)getSectionAddress(GOTSectionID);
+ // Fill in this entry with the address of the symbol being referenced.
+ LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset;
+ } else {
+ uint32_t *LocalGOTAddr = (uint32_t*)getSectionAddress(GOTSectionID);
+ // Fill in this entry with the address of the symbol being referenced.
+ LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset);
+ }
+
+ // Calculate the load address of this entry
+ return getSectionLoadAddress(GOTSectionID) + (GOTIndex * GOTEntrySize);
+}
+
+void RuntimeDyldELF::finalizeLoad() {
+ // Allocate the GOT if necessary
+ size_t numGOTEntries = GOTEntries.size();
+ if (numGOTEntries != 0) {
+ // Allocate memory for the section
+ unsigned SectionID = Sections.size();
+ size_t TotalSize = numGOTEntries * getGOTEntrySize();
+ uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, getGOTEntrySize(),
+ SectionID, false);
+ if (!Addr)
+ report_fatal_error("Unable to allocate memory for GOT!");
+ Sections.push_back(SectionEntry(".got", Addr, TotalSize, 0));
+ // For now, initialize all GOT entries to zero. We'll fill them in as
+ // needed when GOT-based relocations are applied.
+ memset(Addr, 0, TotalSize);
+ GOTSectionID = SectionID;
+ }
+}
+
bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const {
if (Buffer->getBufferSize() < strlen(ELF::ElfMagic))
return false;
unsigned SectionID;
/// Offset - offset into the section.
- uintptr_t Offset;
+ uint64_t Offset;
/// RelType - relocation type.
uint32_t RelType;
/// Addend - the relocation addend encoded in the instruction itself. Also
/// used to make a relocation section relative instead of symbol relative.
- intptr_t Addend;
+ int64_t Addend;
+
+ /// SymOffset - Section offset of the relocation entry's symbol (used for GOT
+ /// lookup).
+ uint64_t SymOffset;
/// True if this is a PCRel relocation (MachO specific).
bool IsPCRel;
RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend)
: SectionID(id), Offset(offset), RelType(type), Addend(addend),
- IsPCRel(false), Size(0) {}
+ SymOffset(0), IsPCRel(false), Size(0) {}
+
+ RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,
+ uint64_t symoffset)
+ : SectionID(id), Offset(offset), RelType(type), Addend(addend),
+ SymOffset(symoffset), IsPCRel(false), Size(0) {}
RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,
bool IsPCRel, unsigned Size)
: SectionID(id), Offset(offset), RelType(type), Addend(addend),
- IsPCRel(IsPCRel), Size(Size) {}
+ SymOffset(0), IsPCRel(IsPCRel), Size(Size) {}
};
class RelocationValueRef {
public:
unsigned SectionID;
- intptr_t Addend;
+ uint64_t Offset;
+ int64_t Addend;
const char *SymbolName;
- RelocationValueRef(): SectionID(0), Addend(0), SymbolName(0) {}
+ RelocationValueRef(): SectionID(0), Offset(0), Addend(0), SymbolName(0) {}
inline bool operator==(const RelocationValueRef &Other) const {
return std::memcmp(this, &Other, sizeof(RelocationValueRef)) == 0;
else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le)
return 44;
else if (Arch == Triple::x86_64)
- return 8; // GOT
+ return 6; // 2-byte jmp instruction + 32-bit relative address
else if (Arch == Triple::systemz)
return 16;
else
/// \brief Resolve relocations to external symbols.
void resolveExternalSymbols();
+
+ /// \brief Update GOT entries for external symbols.
+ // The base class does nothing. ELF overrides this.
+ virtual void updateGOTEntries(StringRef Name, uint64_t Addr) {}
+
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
public:
RuntimeDyldImpl(RTDyldMemoryManager *mm) : MemMgr(mm), HasError(false) {}
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0;
virtual StringRef getEHFrameSection();
+
+ virtual void finalizeLoad() {}
};
} // end namespace llvm