static std::error_code getRelocationValueString(const ELFObjectFileBase *Obj, const RelocationRef &RelRef, SmallVectorImpl<char> &Result) { DataRefImpl Rel = RelRef.getRawDataRefImpl(); if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj)) return getRelocationValueString(ELF32LE, Rel, Result); if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj)) return getRelocationValueString(ELF64LE, Rel, Result); if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj)) return getRelocationValueString(ELF32BE, Rel, Result); auto *ELF64BE = cast<ELF64BEObjectFile>(Obj); return getRelocationValueString(ELF64BE, Rel, Result); }
/// Given a relocation from __compact_unwind, consisting of the RelocationRef /// and data being relocated, determine the best base Name and Addend to use for /// display purposes. /// /// 1. An Extern relocation will directly reference a symbol (and the data is /// then already an addend), so use that. /// 2. Otherwise the data is an offset in the object file's layout; try to find // a symbol before it in the same section, and use the offset from there. /// 3. Finally, if all that fails, fall back to an offset from the start of the /// referenced section. static void findUnwindRelocNameAddend(const MachOObjectFile *Obj, std::map<uint64_t, SymbolRef> &Symbols, const RelocationRef &Reloc, uint64_t Addr, StringRef &Name, uint64_t &Addend) { if (Reloc.getSymbol() != Obj->symbol_end()) { Reloc.getSymbol()->getName(Name); Addend = Addr; return; } auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl()); SectionRef RelocSection = Obj->getRelocationSection(RE); uint64_t SectionAddr; RelocSection.getAddress(SectionAddr); auto Sym = Symbols.upper_bound(Addr); if (Sym == Symbols.begin()) { // The first symbol in the object is after this reference, the best we can // do is section-relative notation. RelocSection.getName(Name); Addend = Addr - SectionAddr; return; } // Go back one so that SymbolAddress <= Addr. --Sym; section_iterator SymSection = Obj->section_end(); Sym->second.getSection(SymSection); if (RelocSection == *SymSection) { // There's a valid symbol in the same section before this reference. Sym->second.getName(Name); Addend = Addr - Sym->first; return; } // There is a symbol before this reference, but it's in a different // section. Probably not helpful to mention it, so use the section name. RelocSection.getName(Name); Addend = Addr - SectionAddr; }
void RuntimeDyldMachO::processRelocationRef(unsigned SectionID, RelocationRef RelI, ObjectImage &Obj, ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols, StubMap &Stubs) { const ObjectFile *OF = Obj.getObjectFile(); const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF); MachO::any_relocation_info RE= MachO->getRelocation(RelI.getRawDataRefImpl()); uint32_t RelType = MachO->getAnyRelocationType(RE); // FIXME: Properly handle scattered relocations. // For now, optimistically skip these: they can often be ignored, as // the static linker will already have applied the relocation, and it // only needs to be reapplied if symbols move relative to one another. // Note: This will fail horribly where the relocations *do* need to be // applied, but that was already the case. if (MachO->isRelocationScattered(RE)) return; RelocationValueRef Value; SectionEntry &Section = Sections[SectionID]; bool isExtern = MachO->getPlainRelocationExternal(RE); bool IsPCRel = MachO->getAnyRelocationPCRel(RE); unsigned Size = MachO->getAnyRelocationLength(RE); uint64_t Offset; RelI.getOffset(Offset); uint8_t *LocalAddress = Section.Address + Offset; unsigned NumBytes = 1 << Size; uint64_t Addend = 0; memcpy(&Addend, LocalAddress, NumBytes); if (isExtern) { // Obtain the symbol name which is referenced in the relocation symbol_iterator Symbol = RelI.getSymbol(); StringRef TargetName; Symbol->getName(TargetName); // First search for the symbol in the local symbol table SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); if (lsi != Symbols.end()) { Value.SectionID = lsi->second.first; Value.Addend = lsi->second.second + Addend; } else { // Search for the symbol in the global symbol table SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); if (gsi != GlobalSymbolTable.end()) { Value.SectionID = gsi->second.first; Value.Addend = gsi->second.second + Addend; } else { Value.SymbolName = TargetName.data(); Value.Addend = Addend; } } } else { SectionRef Sec = MachO->getRelocationSection(RE); bool IsCode = false; Sec.isText(IsCode); Value.SectionID = findOrEmitSection(Obj, Sec, IsCode, ObjSectionToID); uint64_t Addr; Sec.getAddress(Addr); Value.Addend = Addend - Addr; if (IsPCRel) Value.Addend += Offset + NumBytes; } if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT || RelType == MachO::X86_64_RELOC_GOT_LOAD)) { assert(IsPCRel); assert(Size == 2); StubMap::const_iterator i = Stubs.find(Value); uint8_t *Addr; if (i != Stubs.end()) { Addr = Section.Address + i->second; } else { Stubs[Value] = Section.StubOffset; uint8_t *GOTEntry = Section.Address + Section.StubOffset; RelocationEntry RE(SectionID, Section.StubOffset, MachO::X86_64_RELOC_UNSIGNED, 0, false, 3); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else addRelocationForSection(RE, Value.SectionID); Section.StubOffset += 8; Addr = GOTEntry; } resolveRelocation(Section, Offset, (uint64_t)Addr, MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, 2); } else if (Arch == Triple::arm && (RelType & 0xf) == MachO::ARM_RELOC_BR24) { // This is an ARM branch relocation, need to use a stub function. // Look up for existing stub. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, RelType, 0, IsPCRel, Size); else { // Create a new stub function. Stubs[Value] = Section.StubOffset; uint8_t *StubTargetAddr = createStubFunction(Section.Address + Section.StubOffset); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, MachO::GENERIC_RELOC_VANILLA, Value.Addend); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else addRelocationForSection(RE, Value.SectionID); resolveRelocation(Section, Offset, (uint64_t)Section.Address + Section.StubOffset, RelType, 0, IsPCRel, Size); Section.StubOffset += getMaxStubSize(); } } else { RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, IsPCRel, Size); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else addRelocationForSection(RE, Value.SectionID); } }
static std::error_code getRelocationValueString(const MachOObjectFile *Obj, const RelocationRef &RelRef, SmallVectorImpl<char> &Result) { DataRefImpl Rel = RelRef.getRawDataRefImpl(); MachO::any_relocation_info RE = Obj->getRelocation(Rel); unsigned Arch = Obj->getArch(); std::string fmtbuf; raw_string_ostream fmt(fmtbuf); unsigned Type = Obj->getAnyRelocationType(RE); bool IsPCRel = Obj->getAnyRelocationPCRel(RE); // Determine any addends that should be displayed with the relocation. // These require decoding the relocation type, which is triple-specific. // X86_64 has entirely custom relocation types. if (Arch == Triple::x86_64) { bool isPCRel = Obj->getAnyRelocationPCRel(RE); switch (Type) { case MachO::X86_64_RELOC_GOT_LOAD: case MachO::X86_64_RELOC_GOT: { printRelocationTargetName(Obj, RE, fmt); fmt << "@GOT"; if (isPCRel) fmt << "PCREL"; break; } case MachO::X86_64_RELOC_SUBTRACTOR: { DataRefImpl RelNext = Rel; Obj->moveRelocationNext(RelNext); MachO::any_relocation_info RENext = Obj->getRelocation(RelNext); // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type // X86_64_RELOC_UNSIGNED. // NOTE: Scattered relocations don't exist on x86_64. unsigned RType = Obj->getAnyRelocationType(RENext); if (RType != MachO::X86_64_RELOC_UNSIGNED) report_fatal_error("Expected X86_64_RELOC_UNSIGNED after " "X86_64_RELOC_SUBTRACTOR."); // The X86_64_RELOC_UNSIGNED contains the minuend symbol; // X86_64_RELOC_SUBTRACTOR contains the subtrahend. printRelocationTargetName(Obj, RENext, fmt); fmt << "-"; printRelocationTargetName(Obj, RE, fmt); break; } case MachO::X86_64_RELOC_TLV: printRelocationTargetName(Obj, RE, fmt); fmt << "@TLV"; if (isPCRel) fmt << "P"; break; case MachO::X86_64_RELOC_SIGNED_1: printRelocationTargetName(Obj, RE, fmt); fmt << "-1"; break; case MachO::X86_64_RELOC_SIGNED_2: printRelocationTargetName(Obj, RE, fmt); fmt << "-2"; break; case MachO::X86_64_RELOC_SIGNED_4: printRelocationTargetName(Obj, RE, fmt); fmt << "-4"; break; default: printRelocationTargetName(Obj, RE, fmt); break; } // X86 and ARM share some relocation types in common. } else if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc) { // Generic relocation types... switch (Type) { case MachO::GENERIC_RELOC_PAIR: // prints no info return std::error_code(); case MachO::GENERIC_RELOC_SECTDIFF: { DataRefImpl RelNext = Rel; Obj->moveRelocationNext(RelNext); MachO::any_relocation_info RENext = Obj->getRelocation(RelNext); // X86 sect diff's must be followed by a relocation of type // GENERIC_RELOC_PAIR. unsigned RType = Obj->getAnyRelocationType(RENext); if (RType != MachO::GENERIC_RELOC_PAIR) report_fatal_error("Expected GENERIC_RELOC_PAIR after " "GENERIC_RELOC_SECTDIFF."); printRelocationTargetName(Obj, RE, fmt); fmt << "-"; printRelocationTargetName(Obj, RENext, fmt); break; } } if (Arch == Triple::x86 || Arch == Triple::ppc) { switch (Type) { case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: { DataRefImpl RelNext = Rel; Obj->moveRelocationNext(RelNext); MachO::any_relocation_info RENext = Obj->getRelocation(RelNext); // X86 sect diff's must be followed by a relocation of type // GENERIC_RELOC_PAIR. unsigned RType = Obj->getAnyRelocationType(RENext); if (RType != MachO::GENERIC_RELOC_PAIR) report_fatal_error("Expected GENERIC_RELOC_PAIR after " "GENERIC_RELOC_LOCAL_SECTDIFF."); printRelocationTargetName(Obj, RE, fmt); fmt << "-"; printRelocationTargetName(Obj, RENext, fmt); break; } case MachO::GENERIC_RELOC_TLV: { printRelocationTargetName(Obj, RE, fmt); fmt << "@TLV"; if (IsPCRel) fmt << "P"; break; } default: printRelocationTargetName(Obj, RE, fmt); } } else { // ARM-specific relocations switch (Type) { case MachO::ARM_RELOC_HALF: case MachO::ARM_RELOC_HALF_SECTDIFF: { // Half relocations steal a bit from the length field to encode // whether this is an upper16 or a lower16 relocation. bool isUpper = Obj->getAnyRelocationLength(RE) >> 1; if (isUpper) fmt << ":upper16:("; else fmt << ":lower16:("; printRelocationTargetName(Obj, RE, fmt); DataRefImpl RelNext = Rel; Obj->moveRelocationNext(RelNext); MachO::any_relocation_info RENext = Obj->getRelocation(RelNext); // ARM half relocs must be followed by a relocation of type // ARM_RELOC_PAIR. unsigned RType = Obj->getAnyRelocationType(RENext); if (RType != MachO::ARM_RELOC_PAIR) report_fatal_error("Expected ARM_RELOC_PAIR after " "ARM_RELOC_HALF"); // NOTE: The half of the target virtual address is stashed in the // address field of the secondary relocation, but we can't reverse // engineer the constant offset from it without decoding the movw/movt // instruction to find the other half in its immediate field. // ARM_RELOC_HALF_SECTDIFF encodes the second section in the // symbol/section pointer of the follow-on relocation. if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { fmt << "-"; printRelocationTargetName(Obj, RENext, fmt); } fmt << ")"; break; } default: { printRelocationTargetName(Obj, RE, fmt); } } } } else
static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj, const RelocationRef &RelRef, SmallVectorImpl<char> &Result) { const ELFFile<ELFT> &EF = *Obj->getELFFile(); DataRefImpl Rel = RelRef.getRawDataRefImpl(); auto SecOrErr = EF.getSection(Rel.d.a); if (!SecOrErr) return SecOrErr.takeError(); int64_t Addend = 0; // If there is no Symbol associated with the relocation, we set the undef // boolean value to 'true'. This will prevent us from calling functions that // requires the relocation to be associated with a symbol. // // In SHT_REL case we would need to read the addend from section data. // GNU objdump does not do that and we just follow for simplicity atm. bool Undef = false; if ((*SecOrErr)->sh_type == ELF::SHT_RELA) { const typename ELFT::Rela *ERela = Obj->getRela(Rel); Addend = ERela->r_addend; Undef = ERela->getSymbol(false) == 0; } else if ((*SecOrErr)->sh_type != ELF::SHT_REL) { return make_error<BinaryError>(); } // Default scheme is to print Target, as well as "+ <addend>" for nonzero // addend. Should be acceptable for all normal purposes. std::string FmtBuf; raw_string_ostream Fmt(FmtBuf); if (!Undef) { symbol_iterator SI = RelRef.getSymbol(); const typename ELFT::Sym *Sym = Obj->getSymbol(SI->getRawDataRefImpl()); if (Sym->getType() == ELF::STT_SECTION) { Expected<section_iterator> SymSI = SI->getSection(); if (!SymSI) return SymSI.takeError(); const typename ELFT::Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl()); auto SecName = EF.getSectionName(SymSec); if (!SecName) return SecName.takeError(); Fmt << *SecName; } else { Expected<StringRef> SymName = SI->getName(); if (!SymName) return SymName.takeError(); if (Demangle) Fmt << demangle(*SymName); else Fmt << *SymName; } } else { Fmt << "*ABS*"; } if (Addend != 0) Fmt << (Addend < 0 ? "" : "+") << Addend; Fmt.flush(); Result.append(FmtBuf.begin(), FmtBuf.end()); return Error::success(); }