aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/ELFObjectWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC/ELFObjectWriter.cpp')
-rw-r--r--llvm/lib/MC/ELFObjectWriter.cpp117
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(