summaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCObjectStreamer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC/MCObjectStreamer.cpp')
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp306
1 files changed, 90 insertions, 216 deletions
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index 5cc9bed2669d..d5b8f2246389 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -46,37 +46,9 @@ MCAssembler *MCObjectStreamer::getAssemblerPtr() {
return nullptr;
}
-// When fixup's offset is a forward declared label, e.g.:
-//
-// .reloc 1f, R_MIPS_JALR, foo
-// 1: nop
-//
-// postpone adding it to Fixups vector until the label is defined and its offset
-// is known.
-void MCObjectStreamer::resolvePendingFixups() {
- for (PendingMCFixup &PendingFixup : PendingFixups) {
- if (!PendingFixup.Sym || PendingFixup.Sym->isUndefined ()) {
- getContext().reportError(PendingFixup.Fixup.getLoc(),
- "unresolved relocation offset");
- continue;
- }
- PendingFixup.Fixup.setOffset(PendingFixup.Sym->getOffset() +
- PendingFixup.Fixup.getOffset());
-
- // If the location symbol to relocate is in MCEncodedFragment,
- // put the Fixup into location symbol's fragment. Otherwise
- // put into PendingFixup.DF
- MCFragment *SymFragment = PendingFixup.Sym->getFragment();
- if (auto *F = dyn_cast<MCEncodedFragment>(SymFragment))
- F->addFixup(PendingFixup.Fixup);
- else
- PendingFixup.DF->addFixup(PendingFixup.Fixup);
- }
- PendingFixups.clear();
-}
-
// As a compile-time optimization, avoid allocating and evaluating an MCExpr
-// tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment.
+// tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment's fixed
+// part.
static std::optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi,
const MCSymbol *Lo) {
assert(Hi && Lo);
@@ -84,9 +56,13 @@ static std::optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi,
return 0;
if (Hi->isVariable() || Lo->isVariable())
return std::nullopt;
- auto *LoF = dyn_cast_or_null<MCDataFragment>(Lo->getFragment());
+ auto *LoF = Lo->getFragment();
if (!LoF || Hi->getFragment() != LoF || LoF->isLinkerRelaxable())
return std::nullopt;
+ // If either symbol resides in the variable part, bail out.
+ auto Fixed = LoF->getFixedSize();
+ if (Lo->getOffset() > Fixed || Hi->getOffset() > Fixed)
+ return std::nullopt;
return Hi->getOffset() - Lo->getOffset();
}
@@ -130,30 +106,13 @@ void MCObjectStreamer::emitFrames(MCAsmBackend *MAB) {
MCDwarfFrameEmitter::Emit(*this, MAB, false);
}
-static bool canReuseDataFragment(const MCDataFragment &F,
- const MCAssembler &Assembler,
- const MCSubtargetInfo *STI) {
- if (!F.hasInstructions())
- return true;
- // Do not add data after a linker-relaxable instruction. The difference
- // between a new label and a label at or before the linker-relaxable
- // instruction cannot be resolved at assemble-time.
- if (F.isLinkerRelaxable())
- return false;
- // When bundling is enabled, we don't want to add data to a fragment that
- // already has instructions (see MCELFStreamer::emitInstToData for details)
- if (Assembler.isBundlingEnabled())
- return false;
- // If the subtarget is changed mid fragment we start a new fragment to record
- // the new STI.
- return !STI || F.getSubtargetInfo() == STI;
-}
-
-MCDataFragment *
-MCObjectStreamer::getOrCreateDataFragment(const MCSubtargetInfo *STI) {
- auto *F = dyn_cast<MCDataFragment>(getCurrentFragment());
- if (!F || !canReuseDataFragment(*F, *Assembler, STI)) {
- F = getContext().allocFragment<MCDataFragment>();
+MCFragment *MCObjectStreamer::getOrCreateDataFragment() {
+ // TODO: Start a new fragment whenever finalizing the variable-size tail of a
+ // previous one, so that all getOrCreateDataFragment calls can be replaced
+ // with getCurrentFragment
+ auto *F = getCurrentFragment();
+ if (F->getKind() != MCFragment::FT_Data) {
+ F = getContext().allocFragment<MCFragment>();
insert(F);
}
return F;
@@ -172,7 +131,7 @@ void MCObjectStreamer::emitCFISections(bool EH, bool Debug) {
void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
SMLoc Loc) {
MCStreamer::emitValueImpl(Value, Size, Loc);
- MCDataFragment *DF = getOrCreateDataFragment();
+ MCFragment *DF = getOrCreateDataFragment();
MCDwarfLineEntry::make(this, getCurrentSectionOnly());
@@ -221,7 +180,7 @@ void MCObjectStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
// If there is a current fragment, mark the symbol as pointing into it.
// Otherwise queue the label and set its fragment pointer when we emit the
// next fragment.
- MCDataFragment *F = getOrCreateDataFragment();
+ MCFragment *F = getOrCreateDataFragment();
Symbol->setFragment(F);
Symbol->setOffset(F->getContents().size());
@@ -241,7 +200,7 @@ void MCObjectStreamer::emitPendingAssignments(MCSymbol *Symbol) {
// Emit a label at a previously emitted fragment/offset position. This must be
// within the currently-active section.
void MCObjectStreamer::emitLabelAtPos(MCSymbol *Symbol, SMLoc Loc,
- MCDataFragment &F, uint64_t Offset) {
+ MCFragment &F, uint64_t Offset) {
assert(F.getParent() == getCurrentSectionOnly());
MCStreamer::emitLabel(Symbol, Loc);
getAssembler().registerSymbol(*Symbol);
@@ -255,7 +214,10 @@ void MCObjectStreamer::emitULEB128Value(const MCExpr *Value) {
emitULEB128IntValue(IntValue);
return;
}
- insert(getContext().allocFragment<MCLEBFragment>(*Value, false));
+ auto *F = getOrCreateDataFragment();
+ F->Kind = MCFragment::FT_LEB;
+ F->setLEBSigned(false);
+ F->setLEBValue(Value);
}
void MCObjectStreamer::emitSLEB128Value(const MCExpr *Value) {
@@ -264,7 +226,10 @@ void MCObjectStreamer::emitSLEB128Value(const MCExpr *Value) {
emitSLEB128IntValue(IntValue);
return;
}
- insert(getContext().allocFragment<MCLEBFragment>(*Value, true));
+ auto *F = getOrCreateDataFragment();
+ F->Kind = MCFragment::FT_LEB;
+ F->setLEBSigned(true);
+ F->setLEBValue(Value);
}
void MCObjectStreamer::emitWeakReference(MCSymbol *Alias,
@@ -288,7 +253,7 @@ bool MCObjectStreamer::changeSectionImpl(MCSection *Section,
// If the subsection number is not in the sorted Subsections list, create a
// new fragment list.
if (I == E || Subsections[I].first != Subsection) {
- auto *F = getContext().allocFragment<MCDataFragment>();
+ auto *F = getContext().allocFragment<MCFragment>();
F->setParent(Section);
Subsections.insert(Subsections.begin() + I,
{Subsection, MCSection::FragList{F, F}});
@@ -358,13 +323,8 @@ void MCObjectStreamer::emitInstructionImpl(const MCInst &Inst,
return;
}
- // Otherwise, relax and emit it as data if either:
- // - The RelaxAll flag was passed
- // - Bundling is enabled and this instruction is inside a bundle-locked
- // group. We want to emit all such instructions into the same data
- // fragment.
- if (Assembler.getRelaxAll() ||
- (Assembler.isBundlingEnabled() && Sec->isBundleLocked())) {
+ // Otherwise, relax and emit it as data if RelaxAll is specified.
+ if (Assembler.getRelaxAll()) {
MCInst Relaxed = Inst;
while (Backend.mayNeedRelaxation(Relaxed.getOpcode(), Relaxed.getOperands(),
STI))
@@ -373,57 +333,54 @@ void MCObjectStreamer::emitInstructionImpl(const MCInst &Inst,
return;
}
- // Otherwise emit to a separate fragment.
emitInstToFragment(Inst, STI);
}
void MCObjectStreamer::emitInstToData(const MCInst &Inst,
const MCSubtargetInfo &STI) {
- MCDataFragment *DF = getOrCreateDataFragment();
+ MCFragment *F = getOrCreateDataFragment();
+
+ // Append the instruction to the data fragment.
+ size_t FixupStartIndex = F->getFixups().size();
+ size_t CodeOffset = F->getContents().size();
SmallVector<MCFixup, 1> Fixups;
- SmallString<256> Code;
- getAssembler().getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
+ getAssembler().getEmitter().encodeInstruction(
+ Inst, F->getContentsForAppending(), Fixups, STI);
+ F->doneAppending();
+ if (!Fixups.empty())
+ F->appendFixups(Fixups);
+ F->setHasInstructions(STI);
- auto CodeOffset = DF->getContents().size();
- for (MCFixup &Fixup : Fixups)
+ bool MarkedLinkerRelaxable = false;
+ for (auto &Fixup : MutableArrayRef(F->getFixups()).slice(FixupStartIndex)) {
Fixup.setOffset(Fixup.getOffset() + CodeOffset);
- if (!Fixups.empty())
- DF->appendFixups(Fixups);
- DF->setHasInstructions(STI);
- DF->appendContents(Code);
+ if (!Fixup.isLinkerRelaxable())
+ continue;
+ F->setLinkerRelaxable();
+ // Do not add data after a linker-relaxable instruction. The difference
+ // between a new label and a label at or before the linker-relaxable
+ // instruction cannot be resolved at assemble-time.
+ if (!MarkedLinkerRelaxable) {
+ MarkedLinkerRelaxable = true;
+ getCurrentSectionOnly()->setLinkerRelaxable();
+ newFragment();
+ }
+ }
}
void MCObjectStreamer::emitInstToFragment(const MCInst &Inst,
const MCSubtargetInfo &STI) {
- // Always create a new, separate fragment here, because its size can change
- // during relaxation.
- MCRelaxableFragment *IF =
- getContext().allocFragment<MCRelaxableFragment>(STI);
- insert(IF);
- IF->setInst(Inst);
-
+ auto *F = getOrCreateDataFragment();
+ SmallVector<char, 16> Data;
SmallVector<MCFixup, 1> Fixups;
- getAssembler().getEmitter().encodeInstruction(
- Inst, IF->getContentsForAppending(), Fixups, STI);
- IF->doneAppending();
- IF->appendFixups(Fixups);
-}
-
-#ifndef NDEBUG
-static const char *const BundlingNotImplementedMsg =
- "Aligned bundling is not implemented for this object format";
-#endif
+ getAssembler().getEmitter().encodeInstruction(Inst, Data, Fixups, STI);
-void MCObjectStreamer::emitBundleAlignMode(Align Alignment) {
- llvm_unreachable(BundlingNotImplementedMsg);
-}
-
-void MCObjectStreamer::emitBundleLock(bool AlignToEnd) {
- llvm_unreachable(BundlingNotImplementedMsg);
-}
-
-void MCObjectStreamer::emitBundleUnlock() {
- llvm_unreachable(BundlingNotImplementedMsg);
+ F->Kind = MCFragment::FT_Relaxable;
+ F->STI = &STI;
+ F->HasInstructions = true;
+ F->setVarContents(Data);
+ F->setVarFixups(Fixups);
+ F->setInst(Inst);
}
void MCObjectStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
@@ -485,9 +442,10 @@ void MCObjectStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
return;
}
- const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel, SMLoc());
- insert(getContext().allocFragment<MCDwarfLineAddrFragment>(LineDelta,
- *AddrDelta));
+ auto *F = getOrCreateDataFragment();
+ F->Kind = MCFragment::FT_Dwarf;
+ F->setDwarfAddrDelta(buildSymbolDiff(*this, Label, LastLabel, SMLoc()));
+ F->setDwarfLineDelta(LineDelta);
}
void MCObjectStreamer::emitDwarfLineEndEntry(MCSection *Section,
@@ -515,8 +473,9 @@ void MCObjectStreamer::emitDwarfLineEndEntry(MCSection *Section,
void MCObjectStreamer::emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
const MCSymbol *Label,
SMLoc Loc) {
- const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel, Loc);
- insert(getContext().allocFragment<MCDwarfCallFrameFragment>(*AddrDelta));
+ auto *F = getOrCreateDataFragment();
+ F->Kind = MCFragment::FT_DwarfFrame;
+ F->setDwarfAddrDelta(buildSymbolDiff(*this, Label, LastLabel, Loc));
}
void MCObjectStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo,
@@ -575,17 +534,17 @@ void MCObjectStreamer::emitCVFileChecksumOffsetDirective(unsigned FileNo) {
void MCObjectStreamer::emitBytes(StringRef Data) {
MCDwarfLineEntry::make(this, getCurrentSectionOnly());
- MCDataFragment *DF = getOrCreateDataFragment();
+ MCFragment *DF = getOrCreateDataFragment();
DF->appendContents(ArrayRef(Data.data(), Data.size()));
}
-void MCObjectStreamer::emitValueToAlignment(Align Alignment, int64_t Value,
- unsigned ValueSize,
+void MCObjectStreamer::emitValueToAlignment(Align Alignment, int64_t Fill,
+ uint8_t FillLen,
unsigned MaxBytesToEmit) {
if (MaxBytesToEmit == 0)
MaxBytesToEmit = Alignment.value();
- insert(getContext().allocFragment<MCAlignFragment>(
- Alignment, Value, ValueSize, MaxBytesToEmit));
+ insert(getContext().allocFragment<MCAlignFragment>(Alignment, Fill, FillLen,
+ MaxBytesToEmit));
// Update the maximum alignment on the current section if necessary.
MCSection *CurSec = getCurrentSectionOnly();
@@ -602,8 +561,10 @@ void MCObjectStreamer::emitCodeAlignment(Align Alignment,
// if the alignment is larger than the minimum NOP size.
unsigned Size;
if (getAssembler().getBackend().shouldInsertExtraNopBytesForCodeAlign(*F,
- Size))
+ Size)) {
getCurrentSectionOnly()->setLinkerRelaxable();
+ newFragment();
+ }
}
void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
@@ -612,76 +573,14 @@ void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
insert(getContext().allocFragment<MCOrgFragment>(*Offset, Value, Loc));
}
-static std::optional<std::pair<bool, std::string>>
-getOffsetAndDataFragment(const MCSymbol &Symbol, uint32_t &RelocOffset,
- MCDataFragment *&DF) {
- if (Symbol.isVariable()) {
- const MCExpr *SymbolExpr = Symbol.getVariableValue();
- MCValue OffsetVal;
- if (!SymbolExpr->evaluateAsRelocatable(OffsetVal, nullptr))
- return std::make_pair(false,
- std::string("symbol in .reloc offset is not "
- "relocatable"));
- if (OffsetVal.isAbsolute()) {
- RelocOffset = OffsetVal.getConstant();
- MCFragment *Fragment = Symbol.getFragment();
- // FIXME Support symbols with no DF. For example:
- // .reloc .data, ENUM_VALUE, <some expr>
- if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
- return std::make_pair(false,
- std::string("symbol in offset has no data "
- "fragment"));
- DF = cast<MCDataFragment>(Fragment);
- return std::nullopt;
- }
-
- if (OffsetVal.getSubSym())
- return std::make_pair(false,
- std::string(".reloc symbol offset is not "
- "representable"));
-
- const MCSymbol &SA = *OffsetVal.getAddSym();
- if (!SA.isDefined())
- return std::make_pair(false,
- std::string("symbol used in the .reloc offset is "
- "not defined"));
-
- if (SA.isVariable())
- return std::make_pair(false,
- std::string("symbol used in the .reloc offset is "
- "variable"));
-
- MCFragment *Fragment = SA.getFragment();
- // FIXME Support symbols with no DF. For example:
- // .reloc .data, ENUM_VALUE, <some expr>
- if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
- return std::make_pair(false,
- std::string("symbol in offset has no data "
- "fragment"));
- RelocOffset = SA.getOffset() + OffsetVal.getConstant();
- DF = cast<MCDataFragment>(Fragment);
- } else {
- RelocOffset = Symbol.getOffset();
- MCFragment *Fragment = Symbol.getFragment();
- // FIXME Support symbols with no DF. For example:
- // .reloc .data, ENUM_VALUE, <some expr>
- if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
- return std::make_pair(false,
- std::string("symbol in offset has no data "
- "fragment"));
- DF = cast<MCDataFragment>(Fragment);
- }
- return std::nullopt;
-}
-
-std::optional<std::pair<bool, std::string>>
-MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
- const MCExpr *Expr, SMLoc Loc,
- const MCSubtargetInfo &STI) {
+void MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
+ const MCExpr *Expr, SMLoc Loc) {
std::optional<MCFixupKind> MaybeKind =
Assembler->getBackend().getFixupKind(Name);
- if (!MaybeKind)
- return std::make_pair(true, std::string("unknown relocation name"));
+ if (!MaybeKind) {
+ getContext().reportError(Loc, "unknown relocation name");
+ return;
+ }
MCFixupKind Kind = *MaybeKind;
if (Expr)
@@ -690,38 +589,14 @@ MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
Expr =
MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext());
- MCDataFragment *DF = getOrCreateDataFragment(&STI);
- MCValue OffsetVal;
- if (!Offset.evaluateAsRelocatable(OffsetVal, nullptr))
- return std::make_pair(false,
- std::string(".reloc offset is not relocatable"));
- if (OffsetVal.isAbsolute()) {
- if (OffsetVal.getConstant() < 0)
- return std::make_pair(false, std::string(".reloc offset is negative"));
- DF->addFixup(MCFixup::create(OffsetVal.getConstant(), Expr, Kind));
- return std::nullopt;
+ auto *O = &Offset;
+ int64_t Val;
+ if (Offset.evaluateAsAbsolute(Val, nullptr)) {
+ auto *SecSym = getCurrentSectionOnly()->getBeginSymbol();
+ O = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(SecSym, getContext()),
+ O, getContext(), Loc);
}
- if (OffsetVal.getSubSym())
- return std::make_pair(false,
- std::string(".reloc offset is not representable"));
-
- const MCSymbol &Symbol = *OffsetVal.getAddSym();
- if (Symbol.isDefined()) {
- uint32_t SymbolOffset = 0;
- std::optional<std::pair<bool, std::string>> Error =
- getOffsetAndDataFragment(Symbol, SymbolOffset, DF);
-
- if (Error != std::nullopt)
- return Error;
-
- DF->addFixup(
- MCFixup::create(SymbolOffset + OffsetVal.getConstant(), Expr, Kind));
- return std::nullopt;
- }
-
- PendingFixups.emplace_back(
- &Symbol, DF, MCFixup::create(OffsetVal.getConstant(), Expr, Kind));
- return std::nullopt;
+ getAssembler().addRelocDirective({*O, Expr, Kind});
}
void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
@@ -804,6 +679,5 @@ void MCObjectStreamer::finishImpl() {
// Emit pseudo probes for the current module.
MCPseudoProbeTable::emit(this);
- resolvePendingFixups();
getAssembler().Finish();
}