diff options
Diffstat (limited to 'llvm/lib/MC/MCAssembler.cpp')
-rw-r--r-- | llvm/lib/MC/MCAssembler.cpp | 242 |
1 files changed, 108 insertions, 134 deletions
diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index 3e96bdf..e142ac1 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -8,7 +8,6 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" @@ -196,12 +195,12 @@ uint64_t MCAssembler::computeFragmentSize(const MCFragment &F) const { switch (F.getKind()) { case MCFragment::FT_Data: case MCFragment::FT_Relaxable: + case MCFragment::FT_Align: case MCFragment::FT_LEB: case MCFragment::FT_Dwarf: case MCFragment::FT_DwarfFrame: case MCFragment::FT_CVInlineLines: case MCFragment::FT_CVDefRange: - case MCFragment::FT_PseudoProbe: return F.getSize(); case MCFragment::FT_Fill: { auto &FF = cast<MCFillFragment>(F); @@ -227,28 +226,6 @@ uint64_t MCAssembler::computeFragmentSize(const MCFragment &F) const { case MCFragment::FT_SymbolId: return 4; - case MCFragment::FT_Align: { - const MCAlignFragment &AF = cast<MCAlignFragment>(F); - unsigned Offset = getFragmentOffset(AF); - unsigned Size = offsetToAlignment(Offset, AF.getAlignment()); - - // Insert extra Nops for code alignment if the target define - // shouldInsertExtraNopBytesForCodeAlign target hook. - if (AF.getParent()->useCodeAlign() && AF.hasEmitNops() && - getBackend().shouldInsertExtraNopBytesForCodeAlign(AF, Size)) - return Size; - - // If we are padding with nops, force the padding to be larger than the - // minimum nop size. - if (Size > 0 && AF.hasEmitNops()) { - while (Size % getBackend().getMinimumNopSize()) - Size += AF.getAlignment().value(); - } - if (Size > AF.getMaxBytesToEmit()) - return 0; - return Size; - } - case MCFragment::FT_Org: { const MCOrgFragment &OF = cast<MCOrgFragment>(F); MCValue Value; @@ -384,7 +361,7 @@ uint64_t MCAssembler::getSectionAddressSize(const MCSection &Sec) const { uint64_t MCAssembler::getSectionFileSize(const MCSection &Sec) const { // Virtual sections have no file size. - if (Sec.isVirtualSection()) + if (Sec.isBssSection()) return 0; return getSectionAddressSize(Sec); } @@ -424,8 +401,7 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm, case MCFragment::FT_Dwarf: case MCFragment::FT_DwarfFrame: case MCFragment::FT_CVInlineLines: - case MCFragment::FT_CVDefRange: - case MCFragment::FT_PseudoProbe: { + case MCFragment::FT_CVDefRange: { if (F.getKind() == MCFragment::FT_Data) ++stats::EmittedDataFragments; else if (F.getKind() == MCFragment::FT_Relaxable) @@ -433,48 +409,45 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm, const auto &EF = cast<MCFragment>(F); OS << StringRef(EF.getContents().data(), EF.getContents().size()); OS << StringRef(EF.getVarContents().data(), EF.getVarContents().size()); - break; - } + } break; + case MCFragment::FT_Align: { ++stats::EmittedAlignFragments; - const MCAlignFragment &AF = cast<MCAlignFragment>(F); - assert(AF.getFillLen() && "Invalid virtual align in concrete fragment!"); + OS << StringRef(F.getContents().data(), F.getContents().size()); + assert(F.getAlignFillLen() && + "Invalid virtual align in concrete fragment!"); - uint64_t Count = FragmentSize / AF.getFillLen(); - assert(FragmentSize % AF.getFillLen() == 0 && + uint64_t Count = (FragmentSize - F.getFixedSize()) / F.getAlignFillLen(); + assert((FragmentSize - F.getFixedSize()) % F.getAlignFillLen() == 0 && "computeFragmentSize computed size is incorrect"); - // See if we are aligning with nops, and if so do that first to try to fill - // the Count bytes. Then if that did not fill any bytes or there are any - // bytes left to fill use the Value and ValueSize to fill the rest. - // If we are aligning with nops, ask that target to emit the right data. - if (AF.hasEmitNops()) { - if (!Asm.getBackend().writeNopData(OS, Count, AF.getSubtargetInfo())) - report_fatal_error("unable to write nop sequence of " + - Twine(Count) + " bytes"); - break; - } - - // Otherwise, write out in multiples of the value size. - for (uint64_t i = 0; i != Count; ++i) { - switch (AF.getFillLen()) { - default: llvm_unreachable("Invalid size!"); - case 1: - OS << char(AF.getFill()); - break; - case 2: - support::endian::write<uint16_t>(OS, AF.getFill(), Endian); - break; - case 4: - support::endian::write<uint32_t>(OS, AF.getFill(), Endian); - break; - case 8: - support::endian::write<uint64_t>(OS, AF.getFill(), Endian); - break; + // In the nops mode, call the backend hook to write `Count` nops. + if (F.hasAlignEmitNops()) { + if (!Asm.getBackend().writeNopData(OS, Count, F.getSubtargetInfo())) + reportFatalInternalError("unable to write nop sequence of " + + Twine(Count) + " bytes"); + } else { + // Otherwise, write out in multiples of the value size. + for (uint64_t i = 0; i != Count; ++i) { + switch (F.getAlignFillLen()) { + default: + llvm_unreachable("Invalid size!"); + case 1: + OS << char(F.getAlignFill()); + break; + case 2: + support::endian::write<uint16_t>(OS, F.getAlignFill(), Endian); + break; + case 4: + support::endian::write<uint32_t>(OS, F.getAlignFill(), Endian); + break; + case 8: + support::endian::write<uint64_t>(OS, F.getAlignFill(), Endian); + break; + } } } - break; - } + } break; case MCFragment::FT_Fill: { ++stats::EmittedFillFragments; @@ -585,42 +558,45 @@ void MCAssembler::writeSectionData(raw_ostream &OS, const MCSection *Sec) const { assert(getBackendPtr() && "Expected assembler backend"); - // Ignore virtual sections. - if (Sec->isVirtualSection()) { + if (Sec->isBssSection()) { assert(getSectionFileSize(*Sec) == 0 && "Invalid size for section!"); - // Check that contents are only things legal inside a virtual section. + // Ensure no fixups or non-zero bytes are written to BSS sections, catching + // errors in both input assembly code and MCStreamer API usage. Location is + // not tracked for efficiency. + auto Fn = [](char c) { return c != 0; }; for (const MCFragment &F : *Sec) { + bool HasNonZero = false; switch (F.getKind()) { - default: llvm_unreachable("Invalid fragment in virtual section!"); - case MCFragment::FT_Data: { - // Check that we aren't trying to write a non-zero contents (or fixups) - // into a virtual section. This is to support clients which use standard - // directives to fill the contents of virtual sections. - if (F.getFixups().size() || F.getVarFixups().size()) - reportError(SMLoc(), Sec->getVirtualSectionKind() + " section '" + - Sec->getName() + "' cannot have fixups"); - for (char C : F.getContents()) - if (C) { - reportError(SMLoc(), Sec->getVirtualSectionKind() + " section '" + - Sec->getName() + - "' cannot have non-zero initializers"); - break; - } + default: + reportFatalInternalError("BSS section '" + Sec->getName() + + "' contains invalid fragment"); + break; + case MCFragment::FT_Data: + case MCFragment::FT_Relaxable: + HasNonZero = + any_of(F.getContents(), Fn) || any_of(F.getVarContents(), Fn); break; - } case MCFragment::FT_Align: - // Check that we aren't trying to write a non-zero value into a virtual - // section. - assert((cast<MCAlignFragment>(F).getFillLen() == 0 || - cast<MCAlignFragment>(F).getFill() == 0) && - "Invalid align in virtual section!"); + // Disallowed for API usage. AsmParser changes non-zero fill values to + // 0. + assert(F.getAlignFill() == 0 && "Invalid align in virtual section!"); break; case MCFragment::FT_Fill: - assert((cast<MCFillFragment>(F).getValue() == 0) && - "Invalid fill in virtual section!"); + HasNonZero = cast<MCFillFragment>(F).getValue() != 0; break; case MCFragment::FT_Org: + HasNonZero = cast<MCOrgFragment>(F).getValue() != 0; + break; + } + if (HasNonZero) { + reportError(SMLoc(), "BSS section '" + Sec->getName() + + "' cannot have non-zero bytes"); + break; + } + if (F.getFixups().size() || F.getVarFixups().size()) { + reportError(SMLoc(), + "BSS section '" + Sec->getName() + "' cannot have fixups"); break; } } @@ -724,34 +700,25 @@ void MCAssembler::layout() { for (MCSection &Sec : *this) { for (MCFragment &F : Sec) { // Process fragments with fixups here. - if (F.isEncoded()) { - auto Contents = F.getContents(); - for (MCFixup &Fixup : F.getFixups()) { + auto Contents = F.getContents(); + for (MCFixup &Fixup : F.getFixups()) { + uint64_t FixedValue; + MCValue Target; + evaluateFixup(F, Fixup, Target, FixedValue, + /*RecordReloc=*/true, Contents); + } + if (F.getVarFixups().size()) { + // In the variable part, fixup offsets are relative to the fixed part's + // start. Extend the variable contents to the left to account for the + // fixed part size. + Contents = MutableArrayRef(F.getParent()->ContentStorage) + .slice(F.VarContentStart - Contents.size(), F.getSize()); + for (MCFixup &Fixup : F.getVarFixups()) { uint64_t FixedValue; MCValue Target; evaluateFixup(F, Fixup, Target, FixedValue, /*RecordReloc=*/true, Contents); } - // In the variable part, fixup offsets are relative to the fixed part's - // start. Extend the variable contents to the left to account for the - // fixed part size. - auto VarFixups = F.getVarFixups(); - if (VarFixups.size()) { - Contents = - MutableArrayRef(F.getParent()->ContentStorage) - .slice(F.VarContentStart - Contents.size(), F.getSize()); - for (MCFixup &Fixup : VarFixups) { - uint64_t FixedValue; - MCValue Target; - evaluateFixup(F, Fixup, Target, FixedValue, - /*RecordReloc=*/true, Contents); - } - } - } else if (auto *AF = dyn_cast<MCAlignFragment>(&F)) { - // For RISC-V linker relaxation, an alignment relocation might be - // needed. - if (AF->hasEmitNops()) - getBackend().shouldInsertFixupForCodeAlign(*this, *AF); } } } @@ -955,15 +922,15 @@ bool MCAssembler::relaxDwarfCallFrameFragment(MCFragment &F) { } bool MCAssembler::relaxCVInlineLineTable(MCCVInlineLineTableFragment &F) { - unsigned OldSize = F.getContents().size(); + unsigned OldSize = F.getVarContents().size(); getContext().getCVContext().encodeInlineLineTable(*this, F); - return OldSize != F.getContents().size(); + return OldSize != F.getVarContents().size(); } bool MCAssembler::relaxCVDefRange(MCCVDefRangeFragment &F) { - unsigned OldSize = F.getContents().size(); + unsigned OldSize = F.getVarContents().size(); getContext().getCVContext().encodeDefRange(*this, F); - return OldSize != F.getContents().size(); + return OldSize != F.getVarContents().size(); } bool MCAssembler::relaxFill(MCFillFragment &F) { @@ -974,22 +941,6 @@ bool MCAssembler::relaxFill(MCFillFragment &F) { return true; } -bool MCAssembler::relaxPseudoProbeAddr(MCPseudoProbeAddrFragment &PF) { - uint64_t OldSize = PF.getContents().size(); - int64_t AddrDelta; - bool Abs = PF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, *this); - assert(Abs && "We created a pseudo probe with an invalid expression"); - (void)Abs; - SmallVector<char, 8> Data; - raw_svector_ostream OSE(Data); - - // AddrDelta is a signed integer - encodeSLEB128(AddrDelta, OSE, OldSize); - PF.setContents(Data); - PF.clearFixups(); - return OldSize != Data.size(); -} - bool MCAssembler::relaxFragment(MCFragment &F) { switch(F.getKind()) { default: @@ -1011,8 +962,6 @@ bool MCAssembler::relaxFragment(MCFragment &F) { return relaxCVDefRange(cast<MCCVDefRangeFragment>(F)); case MCFragment::FT_Fill: return relaxFill(cast<MCFillFragment>(F)); - case MCFragment::FT_PseudoProbe: - return relaxPseudoProbeAddr(cast<MCPseudoProbeAddrFragment>(F)); } } @@ -1020,7 +969,32 @@ void MCAssembler::layoutSection(MCSection &Sec) { uint64_t Offset = 0; for (MCFragment &F : Sec) { F.Offset = Offset; - Offset += computeFragmentSize(F); + if (F.getKind() == MCFragment::FT_Align) { + Offset += F.getFixedSize(); + unsigned Size = offsetToAlignment(Offset, F.getAlignment()); + // In the nops mode, RISC-V style linker relaxation might adjust the size + // and add a fixup, even if `Size` is originally 0. + bool AlignFixup = false; + if (F.hasAlignEmitNops()) { + AlignFixup = getBackend().relaxAlign(F, Size); + // If the backend does not handle the fragment specially, pad with nops, + // but ensure that the padding is larger than the minimum nop size. + if (!AlignFixup) + while (Size % getBackend().getMinimumNopSize()) + Size += F.getAlignment().value(); + } + if (!AlignFixup && Size > F.getAlignMaxBytesToEmit()) + Size = 0; + // Update the variable tail size, offset by FixedSize to prevent ubsan + // pointer-overflow in evaluateFixup. The content is ignored. + F.VarContentStart = F.getFixedSize(); + F.VarContentEnd = F.VarContentStart + Size; + if (F.VarContentEnd > F.getParent()->ContentStorage.size()) + F.getParent()->ContentStorage.resize(F.VarContentEnd); + Offset += Size; + } else { + Offset += computeFragmentSize(F); + } } } |