diff options
Diffstat (limited to 'llvm/lib/MC/ELFObjectWriter.cpp')
-rw-r--r-- | llvm/lib/MC/ELFObjectWriter.cpp | 117 |
1 files changed, 88 insertions, 29 deletions
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index a451c70..8543b97 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 <class uint> +static void encodeCrel(ArrayRef<ELFRelocationEntry> 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<uint>((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<int32_t>(CurSymIdx - SymIdx), OS); + SymIdx = CurSymIdx; + } + if (B & 2) { + encodeSLEB128(static_cast<int32_t>(Entry.Type - Type), OS); + Type = Entry.Type; + } + if (B & 4) { + encodeSLEB128(std::make_signed_t<uint>(Entry.Addend - Addend), OS); + Addend = Entry.Addend; + } + } +} + void ELFWriter::writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec) { std::vector<ELFRelocationEntry> &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<uint64_t>(Relocs, W.OS); + else + encodeCrel<uint32_t>(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<MCSymbolELF>(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( |