diff --git a/llvm/include/llvm/BinaryFormat/DynamicTags.def b/llvm/include/llvm/BinaryFormat/DynamicTags.def index 1502d375f5c4..2d4596c81ba8 100644 --- a/llvm/include/llvm/BinaryFormat/DynamicTags.def +++ b/llvm/include/llvm/BinaryFormat/DynamicTags.def @@ -86,6 +86,10 @@ DYNAMIC_TAG(RELRSZ, 35) // Size of Relr relocation table. DYNAMIC_TAG(RELR, 36) // Address of relocation table (Relr entries). DYNAMIC_TAG(RELRENT, 37) // Size of a Relr relocation entry. +// TODO: Experimental CREL relocations. LLVM will change the value and +// break compatibility in the future. +DYNAMIC_TAG(CREL, 0x40000026) // CREL relocation table + DYNAMIC_TAG_MARKER(LOOS, 0x60000000) // Start of environment specific tags. DYNAMIC_TAG_MARKER(HIOS, 0x6FFFFFFF) // End of environment specific tags. DYNAMIC_TAG_MARKER(LOPROC, 0x70000000) // Start of processor specific tags. diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index dfba18014991..32cc9ff8cbb7 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1082,7 +1082,10 @@ enum : unsigned { SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries. // Experimental support for SHT_RELR sections. For details, see proposal // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg - SHT_RELR = 19, // Relocation entries; only offsets. + SHT_RELR = 19, // Relocation entries; only offsets. + // TODO: Experimental CREL relocations. LLVM will change the value and + // break compatibility in the future. + SHT_CREL = 0x40000014, SHT_LOOS = 0x60000000, // Lowest operating system-specific type. // Android packed relocation section types. // https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#37 @@ -1937,6 +1940,8 @@ enum { ELFCOMPRESS_HIPROC = 0x7fffffff // End of processor-specific. }; +constexpr unsigned CREL_HDR_ADDEND = 4; + /// Convert an architecture name into ELF's e_machine value. uint16_t convertArchNameToEMachine(StringRef Arch); diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h index 0cf2806bd480..98317712250b 100644 --- a/llvm/include/llvm/MC/MCTargetOptions.h +++ b/llvm/include/llvm/MC/MCTargetOptions.h @@ -61,6 +61,9 @@ public: bool Dwarf64 : 1; + // Use CREL relocation format for ELF. + bool Crel = false; + // If true, prefer R_X86_64_[REX_]GOTPCRELX to R_X86_64_GOTPCREL on x86-64 // ELF. bool X86RelaxRelocations = true; diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h index dc33f7461ab2..c419f2998a38 100644 --- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -51,6 +51,8 @@ bool getNoTypeCheck(); bool getSaveTempLabels(); +bool getCrel(); + bool getX86RelaxRelocations(); std::string getABIName(); diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index 78b6b40cbddf..0986379ce76f 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -321,6 +321,11 @@ public: std::vector decode_relrs(Elf_Relr_Range relrs) const; + Expected getCrelHeader(ArrayRef Content) const; + using RelsOrRelas = std::pair, std::vector>; + Expected decodeCrel(ArrayRef Content) const; + Expected crels(const Elf_Shdr &Sec) const; + Expected> android_relas(const Elf_Shdr &Sec) const; /// Iterate over program header table. diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h index ec10762a5df3..c393dc54efb7 100644 --- a/llvm/include/llvm/Object/ELFTypes.h +++ b/llvm/include/llvm/Object/ELFTypes.h @@ -32,6 +32,7 @@ template struct Elf_Sym_Impl; template struct Elf_Dyn_Impl; template struct Elf_Phdr_Impl; template struct Elf_Rel_Impl; +template struct Elf_Crel_Impl; template struct Elf_Verdef_Impl; template struct Elf_Verdaux_Impl; template struct Elf_Verneed_Impl; @@ -62,6 +63,7 @@ public: using Phdr = Elf_Phdr_Impl>; using Rel = Elf_Rel_Impl, false>; using Rela = Elf_Rel_Impl, true>; + using Crel = Elf_Crel_Impl; using Relr = packed; using Verdef = Elf_Verdef_Impl>; using Verdaux = Elf_Verdaux_Impl>; @@ -117,6 +119,7 @@ using ELF64BE = ELFType; using Elf_Phdr = typename ELFT::Phdr; \ using Elf_Rel = typename ELFT::Rel; \ using Elf_Rela = typename ELFT::Rela; \ + using Elf_Crel = typename ELFT::Crel; \ using Elf_Relr = typename ELFT::Relr; \ using Elf_Verdef = typename ELFT::Verdef; \ using Elf_Verdaux = typename ELFT::Verdaux; \ @@ -385,6 +388,7 @@ template struct Elf_Rel_Impl, false> { LLVM_ELF_IMPORT_TYPES(Endianness, false) static const bool HasAddend = false; + static const bool IsCrel = false; Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Word r_info; // Symbol table index and type of relocation to apply @@ -421,6 +425,7 @@ struct Elf_Rel_Impl, true> : public Elf_Rel_Impl, false> { LLVM_ELF_IMPORT_TYPES(Endianness, false) static const bool HasAddend = true; + static const bool IsCrel = false; Elf_Sword r_addend; // Compute value for relocatable field by adding this }; @@ -428,6 +433,7 @@ template struct Elf_Rel_Impl, false> { LLVM_ELF_IMPORT_TYPES(Endianness, true) static const bool HasAddend = false; + static const bool IsCrel = false; Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Xword r_info; // Symbol table index and type of relocation to apply @@ -474,9 +480,29 @@ struct Elf_Rel_Impl, true> : public Elf_Rel_Impl, false> { LLVM_ELF_IMPORT_TYPES(Endianness, true) static const bool HasAddend = true; + static const bool IsCrel = false; Elf_Sxword r_addend; // Compute value for relocatable field by adding this. }; +// In-memory representation. The serialized representation uses LEB128. +template struct Elf_Crel_Impl { + using uint = std::conditional_t; + static const bool IsRela = true; + static const bool IsCrel = true; + uint r_offset; + uint32_t r_symidx; + uint32_t r_type; + std::conditional_t r_addend; + + // Dummy bool parameter is for compatibility with Elf_Rel_Impl. + uint32_t getType(bool) const { return r_type; } + uint32_t getSymbol(bool) const { return r_symidx; } + void setSymbolAndType(uint32_t s, unsigned char t, bool) { + r_symidx = s; + r_type = t; + } +}; + template struct Elf_Ehdr_Impl { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index a451c707b306..8543b978eff2 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -39,6 +39,7 @@ #include "llvm/MC/StringTableBuilder.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" @@ -256,7 +257,7 @@ public: void recordRelocation(MCAssembler &Asm, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) override; - bool usesRela(const MCSectionELF &Sec) const; + bool usesRela(const MCTargetOptions *TO, const MCSectionELF &Sec) const; void executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) override; @@ -810,7 +811,15 @@ MCSectionELF *ELFWriter::createRelocationSection(MCContext &Ctx, Flags = ELF::SHF_GROUP; const StringRef SectionName = Sec.getName(); - const bool Rela = OWriter.usesRela(Sec); + const MCTargetOptions *TO = Ctx.getTargetOptions(); + if (TO && TO->Crel) { + MCSectionELF *RelaSection = + Ctx.createELFRelSection(".crel" + SectionName, ELF::SHT_CREL, Flags, + /*EntrySize=*/1, Sec.getGroup(), &Sec); + return RelaSection; + } + + const bool Rela = OWriter.usesRela(TO, Sec); unsigned EntrySize; if (Rela) EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); @@ -912,20 +921,61 @@ void ELFWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, WriteWord(EntrySize); // sh_entsize } +template +static void encodeCrel(ArrayRef Relocs, raw_ostream &OS) { + uint OffsetMask = 8, Offset = 0, Addend = 0; + uint32_t SymIdx = 0, Type = 0; + // hdr & 4 indicates 3 flag bits in delta offset and flags members. + for (const ELFRelocationEntry &Entry : Relocs) + OffsetMask |= Entry.Offset; + const int Shift = llvm::countr_zero(OffsetMask); + encodeULEB128(Relocs.size() * 8 + ELF::CREL_HDR_ADDEND + Shift, OS); + for (const ELFRelocationEntry &Entry : Relocs) { + // The delta offset and flags member may be larger than uint64_t. Special + // case the first byte (3 flag bits and 4 offset bits). Other ULEB128 bytes + // encode the remaining delta offset bits. + auto DeltaOffset = static_cast((Entry.Offset - Offset) >> Shift); + Offset = Entry.Offset; + uint32_t CurSymIdx = Entry.Symbol ? Entry.Symbol->getIndex() : 0; + uint8_t B = (DeltaOffset << 3) + (SymIdx != CurSymIdx) + + (Type != Entry.Type ? 2 : 0) + (Addend != Entry.Addend ? 4 : 0); + if (DeltaOffset < 0x10) { + OS << char(B); + } else { + OS << char(B | 0x80); + encodeULEB128(DeltaOffset >> 4, OS); + } + // Delta symidx/type/addend members (SLEB128). + if (B & 1) { + encodeSLEB128(static_cast(CurSymIdx - SymIdx), OS); + SymIdx = CurSymIdx; + } + if (B & 2) { + encodeSLEB128(static_cast(Entry.Type - Type), OS); + Type = Entry.Type; + } + if (B & 4) { + encodeSLEB128(std::make_signed_t(Entry.Addend - Addend), OS); + Addend = Entry.Addend; + } + } +} + void ELFWriter::writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec) { std::vector &Relocs = OWriter.Relocations[&Sec]; - const bool Rela = OWriter.usesRela(Sec); + const MCTargetOptions *TO = Asm.getContext().getTargetOptions(); + const bool Rela = OWriter.usesRela(TO, Sec); // Sort the relocation entries. MIPS needs this. OWriter.TargetObjectWriter->sortRelocs(Asm, Relocs); if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) { for (const ELFRelocationEntry &Entry : Relocs) { - uint32_t Symidx = Entry.Symbol ? Entry.Symbol->getIndex() : 0; + uint32_t SymIdx = Entry.Symbol ? Entry.Symbol->getIndex() : 0; if (is64Bit()) { write(Entry.Offset); - write(uint32_t(Symidx)); + write(uint32_t(SymIdx)); write(OWriter.TargetObjectWriter->getRSsym(Entry.Type)); write(OWriter.TargetObjectWriter->getRType3(Entry.Type)); write(OWriter.TargetObjectWriter->getRType2(Entry.Type)); @@ -935,7 +985,7 @@ void ELFWriter::writeRelocations(const MCAssembler &Asm, } else { write(uint32_t(Entry.Offset)); ELF::Elf32_Rela ERE32; - ERE32.setSymbolAndType(Symidx, Entry.Type); + ERE32.setSymbolAndType(SymIdx, Entry.Type); write(ERE32.r_info); if (Rela) write(uint32_t(Entry.Addend)); @@ -955,24 +1005,29 @@ void ELFWriter::writeRelocations(const MCAssembler &Asm, } } } - return; - } - for (const ELFRelocationEntry &Entry : Relocs) { - uint32_t Symidx = Entry.Symbol ? Entry.Symbol->getIndex() : 0; - if (is64Bit()) { - write(Entry.Offset); - ELF::Elf64_Rela ERE; - ERE.setSymbolAndType(Symidx, Entry.Type); - write(ERE.r_info); - if (Rela) - write(Entry.Addend); - } else { - write(uint32_t(Entry.Offset)); - ELF::Elf32_Rela ERE; - ERE.setSymbolAndType(Symidx, Entry.Type); - write(ERE.r_info); - if (Rela) - write(uint32_t(Entry.Addend)); + } else if (TO && TO->Crel) { + if (is64Bit()) + encodeCrel(Relocs, W.OS); + else + encodeCrel(Relocs, W.OS); + } else { + for (const ELFRelocationEntry &Entry : Relocs) { + uint32_t Symidx = Entry.Symbol ? Entry.Symbol->getIndex() : 0; + if (is64Bit()) { + write(Entry.Offset); + ELF::Elf64_Rela ERE; + ERE.setSymbolAndType(Symidx, Entry.Type); + write(ERE.r_info); + if (Rela) + write(Entry.Addend); + } else { + write(uint32_t(Entry.Offset)); + ELF::Elf32_Rela ERE; + ERE.setSymbolAndType(Symidx, Entry.Type); + write(ERE.r_info); + if (Rela) + write(uint32_t(Entry.Addend)); + } } } } @@ -992,7 +1047,8 @@ void ELFWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, llvm_unreachable("SHT_DYNAMIC in a relocatable object"); case ELF::SHT_REL: - case ELF::SHT_RELA: { + case ELF::SHT_RELA: + case ELF::SHT_CREL: { sh_link = SymbolTableIndex; assert(sh_link && ".symtab not found"); const MCSection *InfoSection = Section.getLinkedToSection(); @@ -1417,6 +1473,7 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, uint64_t C = Target.getConstant(); uint64_t FixupOffset = Asm.getFragmentOffset(*Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); + const MCTargetOptions *TO = Ctx.getTargetOptions(); if (const MCSymbolRefExpr *RefB = Target.getSymB()) { const auto &SymB = cast(RefB->getSymbol()); @@ -1472,7 +1529,7 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, FixedValue = !RelocateWithSymbol && SymA && !SymA->isUndefined() ? C + Asm.getSymbolOffset(*SymA) : C; - if (usesRela(FixupSection)) { + if (usesRela(TO, FixupSection)) { Addend = FixedValue; FixedValue = 0; } @@ -1501,9 +1558,11 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, Relocations[&FixupSection].push_back(Rec); } -bool ELFObjectWriter::usesRela(const MCSectionELF &Sec) const { - return hasRelocationAddend() && - Sec.getType() != ELF::SHT_LLVM_CALL_GRAPH_PROFILE; +bool ELFObjectWriter::usesRela(const MCTargetOptions *TO, + const MCSectionELF &Sec) const { + return (hasRelocationAddend() && + Sec.getType() != ELF::SHT_LLVM_CALL_GRAPH_PROFILE) || + (TO && TO->Crel); } bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp index 2c378643797d..42d9b7056e9e 100644 --- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp +++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp @@ -47,6 +47,7 @@ MCOPT(bool, NoWarn) MCOPT(bool, NoDeprecatedWarn) MCOPT(bool, NoTypeCheck) MCOPT(bool, SaveTempLabels) +MCOPT(bool, Crel) MCOPT(bool, X86RelaxRelocations) MCOPT(std::string, ABIName) MCOPT(std::string, AsSecureLogFile) @@ -128,6 +129,10 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() { "save-temp-labels", cl::desc("Don't discard temporary labels")); MCBINDOPT(SaveTempLabels); + static cl::opt Crel("crel", + cl::desc("Use CREL relocation format for ELF")); + MCBINDOPT(Crel); + static cl::opt X86RelaxRelocations( "x86-relax-relocations", cl::desc( @@ -162,6 +167,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() { Options.MCNoDeprecatedWarn = getNoDeprecatedWarn(); Options.MCNoTypeCheck = getNoTypeCheck(); Options.MCSaveTempLabels = getSaveTempLabels(); + Options.Crel = getCrel(); Options.X86RelaxRelocations = getX86RelaxRelocations(); Options.EmitDwarfUnwind = getEmitDwarfUnwind(); Options.EmitCompactUnwindNonCanonical = getEmitCompactUnwindNonCanonical(); diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 0ac4e7a57759..18a116754f45 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -303,6 +303,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { STRINGIFY_ENUM_CASE(ELF, SHT_GROUP); STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX); STRINGIFY_ENUM_CASE(ELF, SHT_RELR); + STRINGIFY_ENUM_CASE(ELF, SHT_CREL); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELR); @@ -392,6 +393,73 @@ ELFFile::decode_relrs(Elf_Relr_Range relrs) const { return Relocs; } +template +Expected +ELFFile::getCrelHeader(ArrayRef Content) const { + DataExtractor Data(Content, isLE(), sizeof(typename ELFT::Addr)); + Error Err = Error::success(); + uint64_t Hdr = 0; + Hdr = Data.getULEB128(&Hdr, &Err); + if (Err) + return Err; + return Hdr; +} + +template +Expected::RelsOrRelas> +ELFFile::decodeCrel(ArrayRef Content) const { + DataExtractor Data(Content, isLE(), sizeof(typename ELFT::Addr)); + DataExtractor::Cursor Cur(0); + const uint64_t Hdr = Data.getULEB128(Cur); + const size_t Count = Hdr / 8; + const size_t FlagBits = Hdr & ELF::CREL_HDR_ADDEND ? 3 : 2; + const size_t Shift = Hdr % ELF::CREL_HDR_ADDEND; + std::vector Rels; + std::vector Relas; + if (Hdr & ELF::CREL_HDR_ADDEND) + Relas.resize(Count); + else + Rels.resize(Count); + typename ELFT::uint Offset = 0, Addend = 0; + uint32_t SymIdx = 0, Type = 0; + for (size_t I = 0; I != Count; ++I) { + // The delta offset and flags member may be larger than uint64_t. Special + // case the first byte (2 or 3 flag bits; the rest are offset bits). Other + // ULEB128 bytes encode the remaining delta offset bits. + const uint8_t B = Data.getU8(Cur); + Offset += B >> FlagBits; + if (B >= 0x80) + Offset += (Data.getULEB128(Cur) << (7 - FlagBits)) - (0x80 >> FlagBits); + // Delta symidx/type/addend members (SLEB128). + if (B & 1) + SymIdx += Data.getSLEB128(Cur); + if (B & 2) + Type += Data.getSLEB128(Cur); + if (B & 4 & Hdr) + Addend += Data.getSLEB128(Cur); + if (Hdr & ELF::CREL_HDR_ADDEND) { + Relas[I].r_offset = Offset << Shift; + Relas[I].setSymbolAndType(SymIdx, Type, false); + Relas[I].r_addend = Addend; + } else { + Rels[I].r_offset = Offset << Shift; + Rels[I].setSymbolAndType(SymIdx, Type, false); + } + } + if (!Cur) + return std::move(Cur.takeError()); + return std::make_pair(std::move(Rels), std::move(Relas)); +} + +template +Expected::RelsOrRelas> +ELFFile::crels(const Elf_Shdr &Sec) const { + Expected> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + return decodeCrel(*ContentsOrErr); +} + template Expected> ELFFile::android_relas(const Elf_Shdr &Sec) const { diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp index b7118a543fae..79ddee43dd35 100644 --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -123,6 +123,12 @@ public: return encodeULEB128(Val, OS); } + unsigned writeSLEB128(int64_t Val) { + if (!checkLimit(10)) + return 0; + return encodeSLEB128(Val, OS); + } + template void write(T Val, llvm::endianness E) { if (checkLimit(sizeof(T))) support::endian::write(OS, Val, E); @@ -1269,7 +1275,8 @@ void ELFState::writeSectionContent( Elf_Shdr &SHeader, const ELFYAML::RelocationSection &Section, ContiguousBlobAccumulator &CBA) { assert((Section.Type == llvm::ELF::SHT_REL || - Section.Type == llvm::ELF::SHT_RELA) && + Section.Type == llvm::ELF::SHT_RELA || + Section.Type == llvm::ELF::SHT_CREL) && "Section type is not SHT_REL nor SHT_RELA"); if (!Section.RelocatableSec.empty()) @@ -1278,29 +1285,70 @@ void ELFState::writeSectionContent( if (!Section.Relocations) return; + const bool IsCrel = Section.Type == llvm::ELF::SHT_CREL; const bool IsRela = Section.Type == llvm::ELF::SHT_RELA; + typename ELFT::uint OffsetMask = 8, Offset = 0, Addend = 0; + uint32_t SymIdx = 0, Type = 0; + uint64_t CurrentOffset = CBA.getOffset(); + if (IsCrel) + for (const ELFYAML::Relocation &Rel : *Section.Relocations) + OffsetMask |= Rel.Offset; + const int Shift = llvm::countr_zero(OffsetMask); + if (IsCrel) + CBA.writeULEB128(Section.Relocations->size() * 8 + ELF::CREL_HDR_ADDEND + + Shift); for (const ELFYAML::Relocation &Rel : *Section.Relocations) { const bool IsDynamic = Section.Link && (*Section.Link == ".dynsym"); - unsigned SymIdx = + uint32_t CurSymIdx = Rel.Symbol ? toSymbolIndex(*Rel.Symbol, Section.Name, IsDynamic) : 0; - if (IsRela) { + if (IsCrel) { + // The delta offset and flags member may be larger than uint64_t. Special + // case the first byte (3 flag bits and 4 offset bits). Other ULEB128 + // bytes encode the remaining delta offset bits. + auto DeltaOffset = + (static_cast(Rel.Offset) - Offset) >> Shift; + Offset = Rel.Offset; + uint8_t B = + DeltaOffset * 8 + (SymIdx != CurSymIdx) + (Type != Rel.Type ? 2 : 0) + + (Addend != static_cast(Rel.Addend) ? 4 : 0); + if (DeltaOffset < 0x10) { + CBA.write(B); + } else { + CBA.write(B | 0x80); + CBA.writeULEB128(DeltaOffset >> 4); + } + // Delta symidx/type/addend members (SLEB128). + if (B & 1) { + CBA.writeSLEB128( + std::make_signed_t(CurSymIdx - SymIdx)); + SymIdx = CurSymIdx; + } + if (B & 2) { + CBA.writeSLEB128(static_cast(Rel.Type - Type)); + Type = Rel.Type; + } + if (B & 4) { + CBA.writeSLEB128( + std::make_signed_t(Rel.Addend - Addend)); + Addend = Rel.Addend; + } + } else if (IsRela) { Elf_Rela REntry; zero(REntry); REntry.r_offset = Rel.Offset; REntry.r_addend = Rel.Addend; - REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc)); + REntry.setSymbolAndType(CurSymIdx, Rel.Type, isMips64EL(Doc)); CBA.write((const char *)&REntry, sizeof(REntry)); } else { Elf_Rel REntry; zero(REntry); REntry.r_offset = Rel.Offset; - REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc)); + REntry.setSymbolAndType(CurSymIdx, Rel.Type, isMips64EL(Doc)); CBA.write((const char *)&REntry, sizeof(REntry)); } } - SHeader.sh_size = (IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)) * - Section.Relocations->size(); + SHeader.sh_size = CBA.getOffset() - CurrentOffset; } template diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 0fee299994bc..cb099efe5130 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -688,6 +688,7 @@ void ScalarEnumerationTraits::enumeration( ECase(SHT_GROUP); ECase(SHT_SYMTAB_SHNDX); ECase(SHT_RELR); + ECase(SHT_CREL); ECase(SHT_ANDROID_REL); ECase(SHT_ANDROID_RELA); ECase(SHT_ANDROID_RELR); @@ -1622,6 +1623,7 @@ void MappingTraits>::mapping( break; case ELF::SHT_REL: case ELF::SHT_RELA: + case ELF::SHT_CREL: if (!IO.outputting()) Section.reset(new ELFYAML::RelocationSection()); sectionMapping(IO, *cast(Section.get())); diff --git a/llvm/test/MC/ELF/crel-32.s b/llvm/test/MC/ELF/crel-32.s new file mode 100644 index 000000000000..61b501e15597 --- /dev/null +++ b/llvm/test/MC/ELF/crel-32.s @@ -0,0 +1,19 @@ +# REQUIRES: arm-registered-target +## Test CREL for a 32-bit big-endian target. +## CREL enables the RELA form even if ARM normally uses REL. + +# RUN: llvm-mc -filetype=obj -crel -triple=armv8 %s -o %t.o +# RUN: llvm-readelf -Sr %t.o | FileCheck %s + +# CHECK: [ 3] .data PROGBITS 00000000 {{.*}} 000008 00 WA 0 0 1 +# CHECK-NEXT: [ 4] .crel.data CREL 00000000 {{.*}} 00000a 01 I 5 3 1 + +# CHECK: Relocation section '.crel.data' at offset {{.*}} contains 2 entries: +# CHECK-NEXT: Offset Info Type Sym. Value Symbol's Name + Addend +# CHECK-NEXT: 00000000 {{.*}} R_ARM_NONE 00000000 a0 - 1 +# CHECK-NEXT: 00000004 {{.*}} R_ARM_ABS32 00000000 a3 + 4000 + +.data +.reloc .+0, BFD_RELOC_NONE, a0-1 +.reloc .+4, BFD_RELOC_32, a3+0x4000 +.quad 0 diff --git a/llvm/test/MC/ELF/crel.s b/llvm/test/MC/ELF/crel.s new file mode 100644 index 000000000000..0d60cc441b9f --- /dev/null +++ b/llvm/test/MC/ELF/crel.s @@ -0,0 +1,106 @@ +# RUN: llvm-mc -filetype=obj -crel -triple=x86_64 %s -o %t.o +# RUN: llvm-readelf -Sr -x .crelrodata2 -x .crelrodata16 %t.o | FileCheck %s + +# RUN: %if aarch64-registered-target %{ llvm-mc -filetype=obj -crel -triple=aarch64_be %s -o %t.be.o %} +# RUN: %if aarch64-registered-target %{ llvm-readelf -r %t.be.o | FileCheck %s --check-prefix=A64BE %} + +# CHECK: [ 4] .data PROGBITS 0000000000000000 {{.*}} 000008 00 WA 0 0 1 +# CHECK-NEXT: [ 5] .crel.data CREL 0000000000000000 {{.*}} 00002c 01 I 14 4 1 +# CHECK-NEXT: [ 6] .rodata PROGBITS 0000000000000000 {{.*}} 00002b 00 A 0 0 1 +# CHECK-NEXT: [ 7] .crel.rodata CREL 0000000000000000 {{.*}} 000010 01 I 14 6 1 +# CHECK-NEXT: [ 8] rodata2 PROGBITS 0000000000000000 {{.*}} 000008 00 A 0 0 1 +# CHECK-NEXT: [ 9] .crelrodata2 CREL 0000000000000000 {{.*}} 000005 01 I 14 8 1 +# CHECK-NEXT: [10] rodata16 PROGBITS 0000000000000000 {{.*}} 000010 00 A 0 0 1 +# CHECK-NEXT: [11] .crelrodata16 CREL 0000000000000000 {{.*}} 000004 01 I 14 10 1 +# CHECK-NEXT: [12] noalloc PROGBITS 0000000000000000 {{.*}} 000004 00 0 0 1 +# CHECK-NEXT: [13] .crelnoalloc CREL 0000000000000000 {{.*}} 000005 01 I 14 12 1 +# CHECK-NEXT: [14] .symtab SYMTAB + +# CHECK: Relocation section '.crel.data' at offset {{.*}} contains 8 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000000 {{.*}} R_X86_64_NONE 0000000000000000 a0 + 0 +# CHECK-NEXT: 0000000000000001 {{.*}} R_X86_64_NONE 0000000000000000 a1 - 1 +# CHECK-NEXT: 0000000000000002 {{.*}} R_X86_64_NONE 0000000000000000 a2 - 1 +# CHECK-NEXT: 0000000000000004 {{.*}} R_X86_64_32 0000000000000000 a3 + 4000 +# CHECK-NEXT: 0000000000000005 {{.*}} R_X86_64_64 0000000000000000 a3 - 8000000000000000 +# CHECK-NEXT: 0000000000000005 {{.*}} R_X86_64_64 0000000000000000 a1 + 7fffffffffffffff +# CHECK-NEXT: 0000000000000005 {{.*}} R_X86_64_32 0000000000000000 a1 - 1 +# CHECK-NEXT: 0000000000000005 {{.*}} R_X86_64_64 0000000000000000 a2 - 1 +# CHECK-EMPTY: +# CHECK-NEXT: Relocation section '.crel.rodata' at offset {{.*}} contains 4 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000000 {{.*}} R_X86_64_PC32 0000000000000000 foo + 0 +# CHECK-NEXT: 000000000000000f {{.*}} R_X86_64_PC32 0000000000000000 foo + 3f +# CHECK-NEXT: 000000000000001f {{.*}} R_X86_64_PC64 0000000000000000 foo + 7f +# CHECK-NEXT: 0000000000000027 {{.*}} R_X86_64_PC32 0000000000000000 _start - 1f81 +# CHECK-EMPTY: +# CHECK-NEXT: Relocation section '.crelrodata2' at offset {{.*}} contains 2 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000002 {{.*}} R_X86_64_32 0000000000000000 .data + 0 +# CHECK-NEXT: 0000000000000008 {{.*}} R_X86_64_32 0000000000000000 .data + 0 +# CHECK-EMPTY: +# CHECK-NEXT: Relocation section '.crelrodata16' at offset {{.*}} contains 1 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000008 {{.*}} R_X86_64_64 0000000000000000 rodata16 + 0 +# CHECK-EMPTY: +# CHECK-NEXT: Relocation section '.crelnoalloc' at offset {{.*}} contains 1 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000000 {{.*}} R_X86_64_32 0000000000000000 .text + 4 + +## count * 8 + 4 + shift = 2*8+4+1 = 21 +# CHECK: Hex dump of section '.crelrodata2': +# CHECK-NEXT: 0x00000000 150b020a 18 . +## count * 8 + 4 + shift = 1*8+4+3 = 15 +# CHECK: Hex dump of section '.crelrodata16': +# CHECK-NEXT: 0x00000000 0f0b0301 . + +# A64BE: 0000000000000000 {{.*}} R_AARCH64_NONE 0000000000000000 a0 + 0 +# A64BE-NEXT: 0000000000000001 {{.*}} R_AARCH64_NONE 0000000000000000 a1 - 1 +# A64BE-NEXT: 0000000000000002 {{.*}} R_AARCH64_NONE 0000000000000000 a2 - 1 +# A64BE-NEXT: 0000000000000004 {{.*}} R_AARCH64_ABS32 0000000000000000 a3 + 4000 +# A64BE-NEXT: 0000000000000005 {{.*}} R_AARCH64_ABS64 0000000000000000 a3 - 8000000000000000 +# A64BE-NEXT: 0000000000000005 {{.*}} R_AARCH64_ABS64 0000000000000000 a1 + 7fffffffffffffff +# A64BE-NEXT: 0000000000000005 {{.*}} R_AARCH64_ABS32 0000000000000000 a1 - 1 +# A64BE-NEXT: 0000000000000005 {{.*}} R_AARCH64_ABS64 0000000000000000 a2 - 1 +# A64BE-EMPTY: + +.globl _start +_start: + ret + +.section .text.1,"ax" + ret + +## Test various combinations of delta offset and flags, delta symbol index +## (if present), delta type (if present), delta addend (if present). +.data +.reloc .+0, BFD_RELOC_NONE, a0 +.reloc .+1, BFD_RELOC_NONE, a1-1 // same type +.reloc .+2, BFD_RELOC_NONE, a2-1 // same type and addend +.reloc .+4, BFD_RELOC_32, a3+0x4000 +.reloc .+5, BFD_RELOC_64, a3-0x8000000000000000 // same symbol index +.reloc .+5, BFD_RELOC_64, a1+0x7fffffffffffffff // same offset and type; addend+=UINT64_MAX +.reloc .+5, BFD_RELOC_32, a1-1 // same offset and symbol index +.reloc .+5, BFD_RELOC_64, a2-1 // same offset and addend +.quad 0 + +.section .rodata,"a" +.long foo - . +.space 15-4 +.long foo - . + 63 // offset+=15 +.space 16-4 +.quad foo - . + 127 // offset+=16 +.long _start - . - 8065 + +.section rodata2,"a" +.space 2 +.reloc ., BFD_RELOC_32, .data +.space 6 +.reloc ., BFD_RELOC_32, .data + +.section rodata16,"a" +.quad 0 +.quad rodata16 + +.section noalloc +.long .text + 4 diff --git a/llvm/test/tools/llvm-readobj/ELF/crel.test b/llvm/test/tools/llvm-readobj/ELF/crel.test new file mode 100644 index 000000000000..04df90994b65 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/crel.test @@ -0,0 +1,230 @@ +# RUN: yaml2obj --docnum=1 %s -o %t +# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=LLVM --match-full-lines +# RUN: llvm-readelf -r %t | FileCheck %s --check-prefix=GNU --match-full-lines + +# LLVM: Relocations [ +# LLVM-NEXT: Section ([[#]]) .crel.text { +# LLVM-NEXT: 0x1 R_X86_64_32 g1 0x1 +# LLVM-NEXT: 0x2 R_X86_64_64 l1 0x2 +# LLVM-NEXT: 0x0 R_X86_64_32S g1 0xFFFFFFFFFFFFFFFF +# LLVM-NEXT: 0x4 R_X86_64_32S .text 0x8000000000000000 +# LLVM-NEXT: } +# LLVM-NEXT: Section ([[#]]) .crelnonalloc { +# LLVM-NEXT: 0x10 R_X86_64_64 g1 0x1 +# LLVM-NEXT: 0x20 R_X86_64_64 g2 0x2 +# LLVM-NEXT: } +# LLVM-NEXT: ] + +# GNU: Relocation section '.crel.text' at offset 0x48 contains 4 entries: +# GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# GNU-NEXT: 0000000000000001 000000030000000a R_X86_64_32 0000000000000000 g1 + 1 +# GNU-NEXT: 0000000000000002 0000000200000001 R_X86_64_64 0000000000000000 l1 + 2 +# GNU-NEXT: 0000000000000000 000000030000000b R_X86_64_32S 0000000000000000 g1 - 1 +# GNU-NEXT: 0000000000000004 000000010000000b R_X86_64_32S 0000000000000000 .text - 8000000000000000 +# GNU-EMPTY: +# GNU-NEXT: Relocation section '.crelnonalloc' at offset 0xa2 contains 2 entries: +# GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# GNU-NEXT: 0000000000000010 0000000300000001 R_X86_64_64 0000000000000000 g1 + 1 +# GNU-NEXT: 0000000000000020 0000000400000001 R_X86_64_64 0000000000000000 g2 + 2 + +--- !ELF +FileHeader: !FileHeader + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +Sections: +- Name: .text + Type: SHT_PROGBITS + Content: "0000000000000000" + Flags: [SHF_ALLOC] +- Name: .crel.text + Type: SHT_CREL + Info: .text + Link: .symtab + Relocations: + - Offset: 0x1 + Symbol: g1 + Type: R_X86_64_32 + Addend: 1 + - Offset: 0x2 + Symbol: l1 + Type: R_X86_64_64 + Addend: 2 + - Offset: 0x0 + Symbol: g1 + Type: R_X86_64_32S + Addend: 0xffffffffffffffff + - Offset: 0x4 + Symbol: .text + Type: R_X86_64_32S + Addend: 0x8000000000000000 +- Name: nonalloc + Type: SHT_PROGBITS + Size: 0x30 +- Name: .crelnonalloc + Type: SHT_CREL + Info: nonalloc + Link: .symtab + Relocations: + - Offset: 0x10 + Symbol: g1 + Type: R_X86_64_64 + Addend: 1 + - Offset: 0x20 + Symbol: g2 + Type: R_X86_64_64 + Addend: 2 + +Symbols: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: l1 + - Name: g1 + Section: .text + Value: 0x0 + Size: 4 + Binding: STB_GLOBAL + - Name: g2 + Binding: STB_GLOBAL + +## Check relocation formatting on ELFCLASS32 as well. +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readobj -r %t2 | FileCheck %s --check-prefix=LLVM2 --match-full-lines +# RUN: llvm-readelf -r %t2 | FileCheck %s --check-prefix=GNU2 --match-full-lines + +# LLVM2: Relocations [ +# LLVM2-NEXT: Section (2) .crel.text { +# LLVM2-NEXT: 0x8 R_386_PC32 l1 0x1 +# LLVM2-NEXT: 0x4 R_386_32 g1 0x0 +# LLVM2-NEXT: } +# LLVM2-NEXT: ] + +# GNU2: Relocation section '.crel.text' at offset {{.*}} contains 2 entries: +# GNU2-NEXT: Offset Info Type Sym. Value Symbol's Name + Addend +# GNU2-NEXT: 00000008 00000102 R_386_PC32 00000000 l1 + 1 +# GNU2-NEXT: 00000004 00000201 R_386_32 00000000 g1 + 0 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: +- Name: .text + Type: SHT_PROGBITS + Size: 0x10 +- Name: .crel.text + Type: SHT_CREL + Info: .text + Link: .symtab + Relocations: + - Offset: 0x8 + Symbol: l1 + Type: R_386_PC32 + Addend: 1 + - Offset: 0x4 + Symbol: g1 + Type: R_386_32 +Symbols: + - Name: l1 + - Name: g1 + Binding: STB_GLOBAL + +## Check CREL with implicit addends. +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-readobj -r %t3 | FileCheck %s --check-prefix=LLVM3 --match-full-lines +# RUN: llvm-readelf -r %t3 | FileCheck %s --check-prefix=GNU3 --match-full-lines + +# LLVM3: Relocations [ +# LLVM3-NEXT: Section (3) .crel.data { +# LLVM3-NEXT: 0x1F R_X86_64_32 g1 +# LLVM3-NEXT: 0x3F R_X86_64_64 g1 +# LLVM3-NEXT: 0x0 R_X86_64_32S l1 +# LLVM3-NEXT: } +# LLVM3-NEXT: ] + +# GNU3: Relocation section '.crel.data' at offset {{.*}} contains 3 entries: +# GNU3-NEXT: Offset Info Type Symbol's Value Symbol's Name +# GNU3-NEXT: 000000000000001f 000000030000000a R_X86_64_32 0000000000000000 g1 +# GNU3-NEXT: 000000000000003f 0000000300000001 R_X86_64_64 0000000000000000 g1 +# GNU3-NEXT: 0000000000000000 000000020000000b R_X86_64_32S 0000000000000000 l1 +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + - Name: .data + Type: SHT_PROGBITS + - Name: .crel.data + Type: SHT_CREL + Flags: [ SHF_INFO_LINK ] + Link: .symtab + Info: .data + Content: 187f030a82017787feffffffffffffff077f0a +Symbols: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: l1 + Section: .text + - Name: g1 + Section: .text + Binding: STB_GLOBAL + +## Test errors. See also relocation-errors.test. +# RUN: yaml2obj --docnum=4 %s -o %t.err +# RUN: llvm-readobj -r %t.err 2>&1 | FileCheck %s --check-prefix=ERR-LLVM -DFILE=%t.err +# RUN: llvm-readelf -r %t.err 2>&1 | FileCheck %s --check-prefix=ERR-GNU -DFILE=%t.err + +# ERR-LLVM: Section ([[#]]) .crel.data { +# ERR-LLVM-NEXT: warning: '[[FILE]]': unable to read relocations from SHT_CREL section with index 3: unable to decode LEB128 at offset 0x00000000: malformed uleb128, extends past end +# ERR-LLVM-NEXT: } + +# ERR-GNU: warning: '[[FILE]]': unable to get the number of relocations in SHT_CREL section with index 3: unable to decode LEB128 at offset 0x00000000: malformed uleb128, extends past end +# ERR-GNU-EMPTY: +# ERR-GNU-NEXT: Relocation section '.crel.data' at offset 0x40 contains entries: +# ERR-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name +# ERR-GNU-NOT: {{.}} + +# RUN: yaml2obj --docnum=4 -DCONTENT=08 %s -o %t.err2 +# RUN: llvm-readobj -r %t.err2 2>&1 | FileCheck %s --check-prefix=ERR2-LLVM -DFILE=%t.err2 +# RUN: llvm-readelf -r %t.err2 2>&1 | FileCheck %s --check-prefix=ERR2-GNU -DFILE=%t.err2 + +# ERR2-LLVM: Section ([[#]]) .crel.data { +# ERR2-LLVM-NEXT: warning: '[[FILE]]': unable to read relocations from SHT_CREL section with index 3: unexpected end of data at offset 0x1 while reading [0x1, 0x2) +# ERR2-LLVM-NEXT: } + +# ERR2-GNU: Relocation section '.crel.data' at offset 0x40 contains 1 entries: +# ERR2-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name +# ERR2-GNU: warning: '[[FILE]]': unable to read relocations from SHT_CREL section with index 3: unexpected end of data at offset 0x1 while reading [0x1, 0x2) +# ERR2-GNU-NOT: {{.}} + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + - Name: .data + Type: SHT_PROGBITS + - Name: .crel.data + Type: SHT_CREL + Flags: [] + Link: .symtab + Info: .data + Content: [[CONTENT=""]] +Symbols: + - Name: .text + Type: STT_SECTION + Section: .text diff --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test index 89702b963c11..1e5b9e2e3c21 100644 --- a/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test +++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test @@ -32,12 +32,17 @@ FileHeader: # RUN: --match-full-lines --check-prefixes=GNU-RELOCS,GNU-PLTRELA # LLVM-RELOCS: Dynamic Relocations { +# LLVM-RELOCS-NEXT: 0x8 R_X86_64_64 foo 0x0 # LLVM-RELOCS-NEXT: 0x1 R_X86_64_NONE foo 0x0 # LLVM-RELOCS-NEXT: 0x2 R_X86_64_NONE foo -# LLVM-RELOCS-NEXT: 0x4 R_X86_64_RELATIVE +# LLVM-RELOCS-NEXT: 0x4 R_X86_64_RELATIVE - # LLVM-RELOCS-NEXT: 0x8 R_X86_64_NONE foo # LLVM-RELOCS-NEXT: } +# GNU-RELOCS:'CREL' relocation section at offset 0xa8: +# GNU-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name +# GNU-RELOCS-NEXT:0000000000000008 0000000100000001 R_X86_64_64 0000000000000000 foo + 0 +# GNU-RELOCS-EMPTY: # GNU-RELOCS:'RELA' relocation section at offset 0x78 contains 24 bytes: # GNU-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend # GNU-RELOCS-NEXT:0000000000000001 0000000100000000 R_X86_64_NONE 0000000000000000 foo + 0 @@ -50,10 +55,10 @@ FileHeader: # GNU-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name # GNU-RELOCS-NEXT:0000000000000004 0000000000000008 R_X86_64_RELATIVE {{$}} # GNU-RELOCS-EMPTY: -# GNU-PLTREL-NEXT:'PLT' relocation section at offset 0xa8 contains 16 bytes: +# GNU-PLTREL-NEXT:'PLT' relocation section at offset 0xac contains 16 bytes: # GNU-PLTREL-NEXT: Offset Info Type Symbol's Value Symbol's Name # GNU-PLTREL-NEXT:0000000000000008 0000000100000000 R_X86_64_NONE 0000000000000000 foo -# GNU-PLTRELA-NEXT:'PLT' relocation section at offset 0xa8 contains 24 bytes: +# GNU-PLTRELA-NEXT:'PLT' relocation section at offset 0xac contains 24 bytes: # GNU-PLTRELA-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend # GNU-PLTRELA-NEXT:0000000000000008 0000000100000000 R_X86_64_NONE 0000000000000000 foo + 0 # GNU-RELOCS-EMPTY: @@ -82,6 +87,12 @@ Sections: Type: SHT_RELR Flags: [ SHF_ALLOC ] Entries: [ 0x0000000000000004 ] + - Name: .crel.dyn + Type: SHT_CREL + Relocations: + - Type: R_X86_64_64 + Offset: 0x8 + Symbol: foo - Name: .plt Type: [[PLTTYPE=SHT_REL]] Relocations: @@ -111,9 +122,12 @@ Sections: Value: 0x8 - Tag: DT_RELRENT Value: 0x8 -## 0x30 == offset of .plt section in the segment. - - Tag: DT_JMPREL +## 0x30 == offset of .crel.dyn section in the segment. + - Tag: DT_CREL Value: 0x30 +## 0x34 == offset of .plt section in the segment. + - Tag: DT_JMPREL + Value: 0x34 - Tag: DT_PLTREL Value: [[DTPLTREL=17]] ## 17 == DT_REL - Tag: DT_PLTRELSZ @@ -140,6 +154,7 @@ ProgramHeaders: # PLTRELUNKNOWN-LLVM: warning: '[[FILE]]': unknown DT_PLTREL value of 255 # PLTRELUNKNOWN-LLVM: Dynamic Relocations { +# PLTRELUNKNOWN-LLVM-NEXT: 0x8 R_X86_64_64 foo 0x0 # PLTRELUNKNOWN-LLVM-NEXT: 0x1 R_X86_64_NONE foo 0x0 # PLTRELUNKNOWN-LLVM-NEXT: 0x2 R_X86_64_NONE foo{{$}} # PLTRELUNKNOWN-LLVM-NEXT: 0x4 R_X86_64_RELATIVE -{{$}} @@ -148,6 +163,10 @@ ProgramHeaders: # PLTRELUNKNOWN-GNU: warning: '[[FILE]]': unknown DT_PLTREL value of 255 # PLTRELUNKNOWN-GNU-EMPTY: +# PLTRELUNKNOWN-GNU-NEXT: 'CREL' relocation section at offset 0xa8: +# PLTRELUNKNOWN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name +# PLTRELUNKNOWN-GNU-NEXT: 0000000000000008 0000000100000001 R_X86_64_64 0000000000000000 foo + 0 +# PLTRELUNKNOWN-GNU-EMPTY: # PLTRELUNKNOWN-GNU-NEXT: 'RELA' relocation section at offset 0x78 contains 24 bytes: # PLTRELUNKNOWN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend # PLTRELUNKNOWN-GNU-NEXT: 0000000000000001 0000000100000000 R_X86_64_NONE 0000000000000000 foo + 0 @@ -160,6 +179,6 @@ ProgramHeaders: # PLTRELUNKNOWN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name # PLTRELUNKNOWN-GNU-NEXT: 0000000000000004 0000000000000008 R_X86_64_RELATIVE # PLTRELUNKNOWN-GNU-EMPTY: -# PLTRELUNKNOWN-GNU-NEXT: 'PLT' relocation section at offset 0xa8 contains 16 bytes: +# PLTRELUNKNOWN-GNU-NEXT: 'PLT' relocation section at offset 0xac contains 16 bytes: # PLTRELUNKNOWN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name # PLTRELUNKNOWN-GNU-NEXT: warning: '[[FILE]]': invalid DT_PLTRELSZ value (0x10) or PLTREL entry size (0x0) diff --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test index e25f64ca2202..e0f293ae5273 100644 --- a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test +++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test @@ -11,7 +11,7 @@ # RUN: llvm-readelf --dynamic-table --pretty-print --elf-output-style=JSON %t1 \ # RUN: | FileCheck %s --strict-whitespace --check-prefix=JSON64 -# LLVM64:DynamicSection [ (61 entries) +# LLVM64:DynamicSection [ (62 entries) # LLVM64-NEXT: Tag Type Name/Value # LLVM64-NEXT: 0x0000000000000001 NEEDED Shared library: D # LLVM64-NEXT: 0x0000000000000002 PLTRELSZ 16 (bytes) @@ -49,6 +49,7 @@ # LLVM64-NEXT: 0x0000000000000023 RELRSZ 16 (bytes) # LLVM64-NEXT: 0x0000000000000024 RELR 0x1000 # LLVM64-NEXT: 0x0000000000000025 RELRENT 17185 (bytes) +# LLVM64-NEXT: 0x0000000040000026 CREL 0x40 # LLVM64-NEXT: 0x000000006000000F ANDROID_REL 0x1000 # LLVM64-NEXT: 0x0000000060000010 ANDROID_RELSZ 16 (bytes) # LLVM64-NEXT: 0x0000000060000011 ANDROID_RELA 0x1000 @@ -76,7 +77,7 @@ # LLVM64-NEXT: 0x0000000000000000 NULL 0x0 # LLVM64-NEXT:] -# GNU64:Dynamic section at offset {{.*}} contains 61 entries: +# GNU64:Dynamic section at offset {{.*}} contains 62 entries: # GNU64-NEXT: Tag Type Name/Value # GNU64-NEXT: 0x0000000000000001 (NEEDED) Shared library: D # GNU64-NEXT: 0x0000000000000002 (PLTRELSZ) 16 (bytes) @@ -114,6 +115,7 @@ # GNU64-NEXT: 0x0000000000000023 (RELRSZ) 16 (bytes) # GNU64-NEXT: 0x0000000000000024 (RELR) 0x1000 # GNU64-NEXT: 0x0000000000000025 (RELRENT) 17185 (bytes) +# GNU64-NEXT: 0x0000000040000026 (CREL) 0x40 # GNU64-NEXT: 0x000000006000000f (ANDROID_REL) 0x1000 # GNU64-NEXT: 0x0000000060000010 (ANDROID_RELSZ) 16 (bytes) # GNU64-NEXT: 0x0000000060000011 (ANDROID_RELA) 0x1000 @@ -339,6 +341,11 @@ # JSON64-NEXT: "Value": 17185 # JSON64-NEXT: }, # JSON64-NEXT: { +# JSON64-NEXT: "Tag": 1073741862, +# JSON64-NEXT: "Type": "CREL", +# JSON64-NEXT: "Value": 64 +# JSON64-NEXT: }, +# JSON64-NEXT: { # JSON64-NEXT: "Tag": 1610612751, # JSON64-NEXT: "Type": "ANDROID_REL", # JSON64-NEXT: "Value": 4096 @@ -585,6 +592,8 @@ Sections: Value: 0x1000 - Tag: DT_RELRENT Value: 0x4321 + - Tag: DT_CREL + Value: 0x40 - Tag: DT_ANDROID_REL Value: 0x1000 - Tag: DT_ANDROID_RELSZ @@ -659,7 +668,7 @@ ProgramHeaders: # RUN: | FileCheck %s --check-prefix=GNU32 --strict-whitespace --match-full-lines # RUN: llvm-readelf -d %t2 | FileCheck %s --check-prefix=GNU32 --strict-whitespace --match-full-lines -# LLVM32:DynamicSection [ (61 entries) +# LLVM32:DynamicSection [ (62 entries) # LLVM32-NEXT: Tag Type Name/Value # LLVM32-NEXT: 0x00000001 NEEDED Shared library: D # LLVM32-NEXT: 0x00000002 PLTRELSZ 16 (bytes) @@ -697,6 +706,7 @@ ProgramHeaders: # LLVM32-NEXT: 0x00000023 RELRSZ 16 (bytes) # LLVM32-NEXT: 0x00000024 RELR 0x1000 # LLVM32-NEXT: 0x00000025 RELRENT 17185 (bytes) +# LLVM32-NEXT: 0x40000026 CREL 0x40 # LLVM32-NEXT: 0x6000000F ANDROID_REL 0x1000 # LLVM32-NEXT: 0x60000010 ANDROID_RELSZ 16 (bytes) # LLVM32-NEXT: 0x60000011 ANDROID_RELA 0x1000 @@ -724,7 +734,7 @@ ProgramHeaders: # LLVM32-NEXT: 0x00000000 NULL 0x0 # LLVM32-NEXT:] -# GNU32:Dynamic section at offset 0x84 contains 61 entries: +# GNU32:Dynamic section at offset 0x84 contains 62 entries: # GNU32-NEXT: Tag Type Name/Value # GNU32-NEXT: 0x00000001 (NEEDED) Shared library: D # GNU32-NEXT: 0x00000002 (PLTRELSZ) 16 (bytes) @@ -762,6 +772,7 @@ ProgramHeaders: # GNU32-NEXT: 0x00000023 (RELRSZ) 16 (bytes) # GNU32-NEXT: 0x00000024 (RELR) 0x1000 # GNU32-NEXT: 0x00000025 (RELRENT) 17185 (bytes) +# GNU32-NEXT: 0x40000026 (CREL) 0x40 # GNU32-NEXT: 0x6000000f (ANDROID_REL) 0x1000 # GNU32-NEXT: 0x60000010 (ANDROID_RELSZ) 16 (bytes) # GNU32-NEXT: 0x60000011 (ANDROID_RELA) 0x1000 @@ -848,13 +859,14 @@ Sections: # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_JMPREL: invalid e_phentsize: 1 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_SYMTAB_SHNDX: invalid e_phentsize: 1 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_RELR: invalid e_phentsize: 1 +# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_CREL: invalid e_phentsize: 1 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_ANDROID_RELR: invalid e_phentsize: 1 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_GNU_HASH: invalid e_phentsize: 1 # PHENTSIZE-LLVM: warning: '[[FILE]]': string table was not found # PHENTSIZE-LLVM-NEXT: LoadName: -# PHENTSIZE-LLVM: DynamicSection [ (61 entries) +# PHENTSIZE-LLVM: DynamicSection [ (62 entries) # PHENTSIZE-LLVM-NEXT: Tag Type Name/Value # PHENTSIZE-LLVM-NEXT: 0x0000000000000001 NEEDED Shared library: # PHENTSIZE-LLVM-NEXT: 0x0000000000000002 PLTRELSZ 16 (bytes) @@ -892,6 +904,7 @@ Sections: # PHENTSIZE-LLVM-NEXT: 0x0000000000000023 RELRSZ 16 (bytes) # PHENTSIZE-LLVM-NEXT: 0x0000000000000024 RELR 0x1000 # PHENTSIZE-LLVM-NEXT: 0x0000000000000025 RELRENT 17185 (bytes) +# PHENTSIZE-LLVM-NEXT: 0x0000000040000026 CREL 0x40 # PHENTSIZE-LLVM-NEXT: 0x000000006000000F ANDROID_REL 0x1000 # PHENTSIZE-LLVM-NEXT: 0x0000000060000010 ANDROID_RELSZ 16 (bytes) # PHENTSIZE-LLVM-NEXT: 0x0000000060000011 ANDROID_RELA 0x1000 @@ -919,7 +932,7 @@ Sections: # PHENTSIZE-LLVM-NEXT: 0x0000000000000000 NULL 0x0 # PHENTSIZE-LLVM-NEXT: ] -# PHENTSIZE-GNU: Dynamic section at offset 0xc0 contains 61 entries: +# PHENTSIZE-GNU: Dynamic section at offset 0xc0 contains 62 entries: # PHENTSIZE-GNU-NEXT: Tag Type Name/Value # PHENTSIZE-GNU-NEXT: warning: '[[FILE]]': string table was not found # PHENTSIZE-GNU-NEXT: 0x0000000000000001 (NEEDED) Shared library: @@ -958,6 +971,7 @@ Sections: # PHENTSIZE-GNU-NEXT: 0x0000000000000023 (RELRSZ) 16 (bytes) # PHENTSIZE-GNU-NEXT: 0x0000000000000024 (RELR) 0x1000 # PHENTSIZE-GNU-NEXT: 0x0000000000000025 (RELRENT) 17185 (bytes) +# PHENTSIZE-GNU-NEXT: 0x0000000040000026 (CREL) 0x40 # PHENTSIZE-GNU-NEXT: 0x000000006000000f (ANDROID_REL) 0x1000 # PHENTSIZE-GNU-NEXT: 0x0000000060000010 (ANDROID_RELSZ) 16 (bytes) # PHENTSIZE-GNU-NEXT: 0x0000000060000011 (ANDROID_RELA) 0x1000 diff --git a/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test b/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test index 22d1855c0116..87aab76de4c2 100644 --- a/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test +++ b/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test @@ -37,6 +37,23 @@ # GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend # GNU-NEXT: warning: '[[FILE]]': unable to print relocation 0 in SHT_RELA section with index 4: invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM +# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t64.crel +# RUN: llvm-readelf --relocations %t64.crel 2>&1 | FileCheck %s -DFILE=%t64.crel --check-prefix=CREL-GNU + +# CREL-GNU: Relocation section '.rel.text' at offset 0x41 contains 7 entries: +# CREL-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 0 in SHT_CREL section with index 3: unable to read an entry with index 4278124286 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 1 in SHT_CREL section with index 3: unable to read an entry with index 4278124286 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: 0000000000000002 0000000000000000 R_X86_64_NONE 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 3 in SHT_CREL section with index 3: unable to read an entry with index 2 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 4 in SHT_CREL section with index 3: unable to read an entry with index 4 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 5 in SHT_CREL section with index 3: unable to read an entry with index 3 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 6 in SHT_CREL section with index 3: unable to read an entry with index 5 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-EMPTY: +# CREL-GNU-NEXT: Relocation section '.rela.text' at offset 0x5a contains 1 entries: +# CREL-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 0 in SHT_RELA section with index 4: invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM + --- !ELF FileHeader: Class: ELFCLASS64 @@ -51,7 +68,7 @@ Sections: Type: SHT_PROGBITS ShName: 0xFEFEFEFE - Name: .rel.text - Type: SHT_REL + Type: [[TYPE=SHT_REL]] Info: .text Relocations: ## Case 1: There is no symbol with index 0xFEFEFEFE. diff --git a/llvm/test/tools/llvm-readobj/ELF/section-types.test b/llvm/test/tools/llvm-readobj/ELF/section-types.test index 071ca8057584..a428666c6ada 100644 --- a/llvm/test/tools/llvm-readobj/ELF/section-types.test +++ b/llvm/test/tools/llvm-readobj/ELF/section-types.test @@ -37,6 +37,8 @@ # LLVM: Type: SHT_SYMTAB_SHNDX # LLVM: Name: relr # LLVM: Type: SHT_RELR +# LLVM: Name: crel +# LLVM: Type: SHT_CREL (0x40000014) # LLVM: Name: android_rel # LLVM: Type: SHT_ANDROID_REL # LLVM: Name: android_rela @@ -110,6 +112,7 @@ # GNU-NEXT: group GROUP # GNU-NEXT: symtab_shndx SYMTAB SECTION INDICES # GNU-NEXT: relr RELR +# GNU-NEXT: crel CREL # GNU-NEXT: android_rel ANDROID_REL # GNU-NEXT: android_rela ANDROID_RELA # GNU-NEXT: android_relr ANDROID_RELR @@ -185,6 +188,8 @@ Sections: Entries: [ 0, 1 ] - Name: relr Type: SHT_RELR + - Name: crel + Type: SHT_CREL - Name: android_rel Type: SHT_ANDROID_REL - Name: android_rela diff --git a/llvm/test/tools/yaml2obj/ELF/dynamic-relocations.yaml b/llvm/test/tools/yaml2obj/ELF/dynamic-relocations.yaml index 8964877467f4..c788a40e6778 100644 --- a/llvm/test/tools/yaml2obj/ELF/dynamic-relocations.yaml +++ b/llvm/test/tools/yaml2obj/ELF/dynamic-relocations.yaml @@ -4,6 +4,9 @@ # RUN: yaml2obj %s -o %t # RUN: llvm-readelf -r %t | FileCheck %s +# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t.crel +# RUN: llvm-readelf -r %t.crel | FileCheck %s + # CHECK: Relocation section '.rela.dyn' at offset {{.*}} contains 2 entries: # CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name # CHECK-NEXT: 0000000000000000 0000000100000000 R_X86_64_NONE 0000000012345678 dynamic @@ -24,7 +27,7 @@ Sections: - Name: .data Type: SHT_PROGBITS - Name: .rela.dyn - Type: SHT_REL + Type: [[TYPE=SHT_REL]] Link: .dynsym Info: .data Relocations: diff --git a/llvm/test/tools/yaml2obj/ELF/reloc-sec-entry-size.yaml b/llvm/test/tools/yaml2obj/ELF/reloc-sec-entry-size.yaml index 43f6465c0a82..6168b8826bce 100644 --- a/llvm/test/tools/yaml2obj/ELF/reloc-sec-entry-size.yaml +++ b/llvm/test/tools/yaml2obj/ELF/reloc-sec-entry-size.yaml @@ -12,6 +12,7 @@ # ELF64: .relr.default RELR 0000000000000000 000040 000000 08 # ELF64: .rela.custom RELA 0000000000000000 000040 000000 ff # ELF64: .rel.custom REL 0000000000000000 000040 000000 ff +# ELF64: .crel.custom CREL 0000000000000000 000040 000000 ff # ELF64: .relr.custom RELR 0000000000000000 000040 000000 ff # ELF32: Name Type Address Off Size ES @@ -20,6 +21,7 @@ # ELF32: .relr.default RELR 00000000 000034 000000 04 # ELF32: .rela.custom RELA 00000000 000034 000000 ff # ELF32: .rel.custom REL 00000000 000034 000000 ff +# ELF32: .crel.custom CREL 00000000 000034 000000 ff # ELF32: .relr.custom RELR 00000000 000034 000000 ff --- !ELF @@ -42,6 +44,9 @@ Sections: - Name: .rel.custom Type: SHT_REL EntSize: 0xFF + - Name: .crel.custom + Type: SHT_CREL + EntSize: 0xFF - Name: .relr.custom Type: SHT_RELR EntSize: 0xFF diff --git a/llvm/test/tools/yaml2obj/ELF/relocation-crel.yaml b/llvm/test/tools/yaml2obj/ELF/relocation-crel.yaml new file mode 100644 index 000000000000..fc56745ca1ef --- /dev/null +++ b/llvm/test/tools/yaml2obj/ELF/relocation-crel.yaml @@ -0,0 +1,92 @@ +# RUN: rm -rf %t && mkdir %t && cd %t +# RUN: yaml2obj %s -o out +# RUN: llvm-readelf -r out | FileCheck %s + +# CHECK: Relocation section '.crel.text' at offset {{.*}} contains 7 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000001 0000000100000004 R_X86_64_PLT32 0000000000000000 a0 - 4 +# CHECK-NEXT: 0000000000000005 0000000200000004 R_X86_64_PLT32 0000000000000000 a1 - 4 +# CHECK-NEXT: 000000000000000a 0000000300000004 R_X86_64_PLT32 0000000000000000 a2 + 0 +# CHECK-NEXT: 0000000000000010 0000000200000001 R_X86_64_64 0000000000000000 a1 - 4 +# CHECK-NEXT: 0000000000000018 0000000100000001 R_X86_64_64 0000000000000000 a0 + 80 +# CHECK-NEXT: 0000000000000020 0000000000000008 R_X86_64_RELATIVE 8000000000000000{{$}} +# CHECK-NEXT: 0000000000000028 0000000400000001 R_X86_64_64 0000000000000000 a3 + 7fffffffffffffff + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + - Name: .crel.text + Type: SHT_CREL + Info: .text + Link: .symtab + Relocations: + - Offset: 1 + Type: R_X86_64_PLT32 + Symbol: a0 + Addend: -4 + - Offset: 5 + Type: R_X86_64_PLT32 + Symbol: a1 + Addend: -4 + - Offset: 10 + Type: R_X86_64_PLT32 + Symbol: a2 + Addend: 0 + - Offset: 16 + Type: R_X86_64_64 + Symbol: a1 + Addend: -4 + - Offset: 24 + Type: R_X86_64_64 + Symbol: a0 + Addend: 128 + - Offset: 32 + Type: R_X86_64_RELATIVE + Addend: 0x8000000000000000 + - Offset: 40 + Type: R_X86_64_64 + Symbol: a3 + Addend: 0x7fffffffffffffff +Symbols: + - Name: a0 + - Name: a1 + Binding: STB_GLOBAL + - Name: a2 + Binding: STB_GLOBAL + - Name: a3 + Binding: STB_GLOBAL + +## See output-limit.yaml. While estimating the size of the last byte of .crel.text +## (a SLEB128), checkLimit thinks 10 byte headroom is needed while only 1 is used. +## The file end is 1 byte away from the end of .crel.text (one-byte .strtab). +## Therefore, the --max-size= value has to be at least 10-1-1 larger than the +## actual file size. +# RUN: not yaml2obj %s --docnum=2 --max-size=76 -o /dev/null +# RUN: yaml2obj %s --docnum=2 --max-size=77 -o out +# RUN: %python -c 'import os; print(os.path.getsize("out"))' | FileCheck %s --check-prefix=SIZE + +# SIZE: 69 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + - Name: .crel.text + Type: SHT_CREL + Relocations: + - Offset: 1 + Type: R_X86_64_64 + Addend: -4 + - Type: SectionHeaderTable + NoHeaders: true diff --git a/llvm/test/tools/yaml2obj/ELF/relocation-missing-symbol.yaml b/llvm/test/tools/yaml2obj/ELF/relocation-missing-symbol.yaml index 2f8d98dee18a..1eb376fb5c1a 100644 --- a/llvm/test/tools/yaml2obj/ELF/relocation-missing-symbol.yaml +++ b/llvm/test/tools/yaml2obj/ELF/relocation-missing-symbol.yaml @@ -2,6 +2,7 @@ ## does not exist. # RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s +# RUN: not yaml2obj -DTYPE=SHT_CREL %s -o %t 2>&1 | FileCheck %s ## Check we are able to report multiple errors. @@ -18,7 +19,7 @@ Sections: - Name: .text Type: SHT_PROGBITS - Name: .rela.text - Type: SHT_RELA + Type: [[TYPE=SHT_RELA]] Info: .text Link: .symtab Relocations: diff --git a/llvm/test/tools/yaml2obj/ELF/relocation-type.yaml b/llvm/test/tools/yaml2obj/ELF/relocation-type.yaml index 67d451df2f7f..0aabde4ce199 100644 --- a/llvm/test/tools/yaml2obj/ELF/relocation-type.yaml +++ b/llvm/test/tools/yaml2obj/ELF/relocation-type.yaml @@ -3,6 +3,8 @@ ## Show that yaml2obj is able to produce relocations for an unknown e_machine kind properly. # RUN: yaml2obj %s -o %t1 -DMACHINE=0x1234 # RUN: llvm-readelf %t1 --relocations | FileCheck %s -DFIRST=Unknown -DSECOND=Unknown +# RUN: yaml2obj %s -o %t1 -DMACHINE=0x1234 -DTYPE=SHT_CREL +# RUN: llvm-readelf %t1 --relocations | FileCheck %s -DFIRST=Unknown -DSECOND=Unknown # CHECK: Relocation section '.rela.text' at offset 0x40 contains 4 entries: # CHECK: Offset Info Type @@ -23,7 +25,7 @@ FileHeader: Machine: [[MACHINE]] Sections: - Name: .rela.text - Type: SHT_RELA + Type: [[TYPE=SHT_RELA]] Relocations: ## Test a few noticeable possible values: 0, 1, max(int8_t)=127, max(uint8_t)=0xFF=-1 - Offset: 0x9 diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index a986ba88fdcf..1b6600637800 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -378,6 +378,7 @@ protected: DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; + DynRegionInfo DynCrelRegion; DynRegionInfo DynRelrRegion; DynRegionInfo DynPLTRelRegion; std::optional DynSymRegion; @@ -1909,7 +1910,7 @@ ELFDumper::ELFDumper(const object::ELFObjectFile &O, ScopedPrinter &Writer) : ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()), FileName(O.getFileName()), DynRelRegion(O, *this), - DynRelaRegion(O, *this), DynRelrRegion(O, *this), + DynRelaRegion(O, *this), DynCrelRegion(O, *this), DynRelrRegion(O, *this), DynPLTRelRegion(O, *this), DynSymTabShndxRegion(O, *this), DynamicTable(O, *this) { if (!O.IsContentValid()) @@ -2068,6 +2069,9 @@ template void ELFDumper::parseDynamicTable() { DynRelaRegion.EntSize = Dyn.getVal(); DynRelaRegion.EntSizePrintName = "DT_RELAENT value"; break; + case ELF::DT_CREL: + DynCrelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); + break; case ELF::DT_SONAME: SONameOffset = Dyn.getVal(); break; @@ -2108,6 +2112,8 @@ template void ELFDumper::parseDynamicTable() { DynPLTRelRegion.EntSize = sizeof(Elf_Rel); else if (Dyn.getVal() == DT_RELA) DynPLTRelRegion.EntSize = sizeof(Elf_Rela); + else if (Dyn.getVal() == DT_CREL) + DynPLTRelRegion.EntSize = 1; else reportUniqueWarning(Twine("unknown DT_PLTREL value of ") + Twine((uint64_t)Dyn.getVal())); @@ -2433,6 +2439,8 @@ std::string ELFDumper::getDynamicEntry(uint64_t Type, return "REL"; if (Value == DT_RELA) return "RELA"; + if (Value == DT_CREL) + return "CREL"; [[fallthrough]]; case DT_PLTGOT: case DT_HASH: @@ -2447,6 +2455,7 @@ std::string ELFDumper::getDynamicEntry(uint64_t Type, case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: case DT_DEBUG: + case DT_CREL: case DT_VERDEF: case DT_VERNEED: case DT_VERSYM: @@ -3845,14 +3854,15 @@ void GNUELFDumper::printRelRelaReloc(const Relocation &R, template static void printRelocHeaderFields(formatted_raw_ostream &OS, unsigned SType, - const typename ELFT::Ehdr &EHeader) { + const typename ELFT::Ehdr &EHeader, + uint64_t CrelHdr = 0) { bool IsRela = SType == ELF::SHT_RELA || SType == ELF::SHT_ANDROID_RELA; if (ELFT::Is64Bits) OS << " Offset Info Type Symbol's " "Value Symbol's Name"; else OS << " Offset Info Type Sym. Value Symbol's Name"; - if (IsRela) + if (IsRela || (SType == ELF::SHT_CREL && (CrelHdr & CREL_HDR_ADDEND))) OS << " + Addend"; OS << "\n"; } @@ -3862,7 +3872,10 @@ void GNUELFDumper::printDynamicRelocHeader(unsigned Type, StringRef Name, const DynRegionInfo &Reg) { uint64_t Offset = Reg.Addr - this->Obj.base(); OS << "\n'" << Name.str().c_str() << "' relocation section at offset 0x" - << utohexstr(Offset, /*LowerCase=*/true) << " contains " << Reg.Size << " bytes:\n"; + << utohexstr(Offset, /*LowerCase=*/true); + if (Type != ELF::SHT_CREL) + OS << " contains " << Reg.Size << " bytes"; + OS << ":\n"; printRelocHeaderFields(OS, Type, this->Obj.getHeader()); } @@ -3870,7 +3883,8 @@ template static bool isRelocationSec(const typename ELFT::Shdr &Sec, const typename ELFT::Ehdr &EHeader) { return Sec.sh_type == ELF::SHT_REL || Sec.sh_type == ELF::SHT_RELA || - Sec.sh_type == ELF::SHT_RELR || Sec.sh_type == ELF::SHT_ANDROID_REL || + Sec.sh_type == ELF::SHT_RELR || Sec.sh_type == ELF::SHT_CREL || + Sec.sh_type == ELF::SHT_ANDROID_REL || Sec.sh_type == ELF::SHT_ANDROID_RELA || Sec.sh_type == ELF::SHT_ANDROID_RELR || (EHeader.e_machine == EM_AARCH64 && @@ -3896,6 +3910,17 @@ template void GNUELFDumper::printRelocations() { return RelasOrErr->size(); } + if (Sec.sh_type == ELF::SHT_CREL) { + Expected> ContentsOrErr = + this->Obj.getSectionContents(Sec); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + auto NumOrErr = this->Obj.getCrelHeader(*ContentsOrErr); + if (!NumOrErr) + return NumOrErr.takeError(); + return *NumOrErr / 8; + } + if (PrintAsRelr(Sec)) { Expected RelrsOrErr = this->Obj.relrs(Sec); if (!RelrsOrErr) @@ -3929,8 +3954,17 @@ template void GNUELFDumper::printRelocations() { if (PrintAsRelr(Sec)) { printRelr(Sec); } else { - printRelocHeaderFields(OS, Sec.sh_type, this->Obj.getHeader()); - this->printRelocationsHelper(Sec); + uint64_t CrelHdr = 0; + // For CREL, read the header and call printRelocationsHelper only if + // GetEntriesNum(Sec) succeeded. + if (Sec.sh_type == ELF::SHT_CREL && EntriesNum != "") { + CrelHdr = cantFail(this->Obj.getCrelHeader( + cantFail(this->Obj.getSectionContents(Sec)))); + } + printRelocHeaderFields(OS, Sec.sh_type, this->Obj.getHeader(), + CrelHdr); + if (Sec.sh_type != ELF::SHT_CREL || EntriesNum != "") + this->printRelocationsHelper(Sec); } } if (!HasRelocSections) @@ -4893,6 +4927,34 @@ void ELFDumper::printRelocationsHelper(const Elf_Shdr &Sec) { template void ELFDumper::printDynamicRelocationsHelper() { const bool IsMips64EL = this->Obj.isMips64EL(); + auto DumpCrelRegion = [&](DynRegionInfo &Region) { + // While the size is unknown, a valid CREL has at least one byte. We can + // check whether Addr is in bounds, and then decode CREL until the file + // end. + Region.Size = Region.EntSize = 1; + if (!Region.template getAsArrayRef().empty()) { + const uint64_t Offset = + Region.Addr - reinterpret_cast( + ObjF.getMemoryBufferRef().getBufferStart()); + const uint64_t ObjSize = ObjF.getMemoryBufferRef().getBufferSize(); + auto RelsOrRelas = + Obj.decodeCrel(ArrayRef(Region.Addr, ObjSize - Offset)); + if (!RelsOrRelas) { + reportUniqueWarning(toString(RelsOrRelas.takeError())); + } else { + for (const Elf_Rel &R : RelsOrRelas->first) + printDynamicReloc(Relocation(R, false)); + for (const Elf_Rela &R : RelsOrRelas->second) + printDynamicReloc(Relocation(R, false)); + } + } + }; + + if (this->DynCrelRegion.Addr) { + printDynamicRelocHeader(ELF::SHT_CREL, "CREL", this->DynCrelRegion); + DumpCrelRegion(this->DynCrelRegion); + } + if (this->DynRelaRegion.Size > 0) { printDynamicRelocHeader(ELF::SHT_RELA, "RELA", this->DynRelaRegion); for (const Elf_Rela &Rela : @@ -4921,6 +4983,8 @@ template void ELFDumper::printDynamicRelocationsHelper() { for (const Elf_Rela &Rela : this->DynPLTRelRegion.template getAsArrayRef()) printDynamicReloc(Relocation(Rela, IsMips64EL)); + } else if (this->DynPLTRelRegion.EntSize == 1) { + DumpCrelRegion(this->DynPLTRelRegion); } else { printDynamicRelocHeader(ELF::SHT_REL, "PLT", this->DynPLTRelRegion); for (const Elf_Rel &Rel : @@ -6415,6 +6479,17 @@ void ELFDumper::forEachRelocationDo( /*SymTab=*/nullptr); break; } + case ELF::SHT_CREL: { + if (auto RelsOrRelas = Obj.crels(Sec)) { + for (const Elf_Rel &R : RelsOrRelas->first) + RelRelaFn(Relocation(R, false), RelNdx++, Sec, SymTab); + for (const Elf_Rela &R : RelsOrRelas->second) + RelRelaFn(Relocation(R, false), RelNdx++, Sec, SymTab); + } else { + Warn(RelsOrRelas.takeError()); + } + break; + } case ELF::SHT_ANDROID_REL: case ELF::SHT_ANDROID_RELA: if (Expected> RelasOrErr = Obj.android_relas(Sec)) {