diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -47,6 +47,7 @@ #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/raw_ostream.h" @@ -169,8 +170,13 @@ void writeHeader(const MCAssembler &Asm); - void writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, - ELFSymbolData &MSD, const MCAsmLayout &Layout); + + void writeSymbol(MCAssembler &Asm, SymbolTableWriter &Writer, + uint32_t StringIndex, ELFSymbolData &MSD, + const MCAsmLayout &Layout); + + void reportInvalidSize(MCAssembler &Asm, const MCAsmLayout &Layout, + const MCExpr *SizeExpr); // Start and end offset of each section using SectionOffsetsTy = @@ -519,8 +525,9 @@ return true; } -void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex, - ELFSymbolData &MSD, const MCAsmLayout &Layout) { +void ELFWriter::writeSymbol(MCAssembler &Asm, SymbolTableWriter &Writer, + uint32_t StringIndex, ELFSymbolData &MSD, + const MCAsmLayout &Layout) { const auto &Symbol = cast(*MSD.Symbol); const MCSymbolELF *Base = cast_or_null(Layout.getBaseSymbol(Symbol)); @@ -553,8 +560,10 @@ if (ESize) { int64_t Res; - if (!ESize->evaluateKnownAbsolute(Res, Layout)) - report_fatal_error("Size expression must be absolute."); + if (!ESize->evaluateKnownAbsolute(Res, Layout)) { + reportInvalidSize(Asm, Layout, ESize); + return; + } Size = Res; } @@ -563,6 +572,55 @@ IsReserved); } +void ELFWriter::reportInvalidSize(MCAssembler &Asm, const MCAsmLayout &Layout, + const MCExpr *SizeExpr) { + MCContext &Ctx = Asm.getContext(); + SMLoc SizeLoc = SizeExpr->getLoc(); + Ctx.reportError(SizeLoc, "size expression is not absolute"); + const SourceMgr *SM = Ctx.getSourceManager(); + + if (!SM) + return; + + auto NoteNotInSect = [&SM, &SizeLoc](MCSymbol const &SymRef) { + SM->PrintMessage(SizeLoc, SourceMgr::DK_Note, + Twine("symbol '") + SymRef.getName() + + "' is not defined in this section"); + }; + auto NoteUndef = [&SM, &Asm](MCSymbol const &SymRef, SMLoc Loc) { + SM->PrintMessage(Loc, SourceMgr::DK_Note, "symbol not defined"); + + const unsigned MaxEditDist = 2; + for (const MCSymbol &Sym : Asm.symbols()) { + StringRef Name = Sym.getName(); + if (Name.edit_distance(SymRef.getName()) < MaxEditDist) + SM->PrintMessage(Loc, SourceMgr::DK_Note, + Twine("did you mean to refer to '") + Name + + Twine("'?")); + } + }; + auto NoteSym = [=](MCSymbol const &Sym, SMLoc Loc) { + if (Sym.isUndefined()) + NoteUndef(Sym, Loc); + else if (Sym.isInSection() && !Sym.getName().empty()) + NoteNotInSect(Sym); + }; + + if (const MCSymbolRefExpr *Ref = dyn_cast(SizeExpr)) { + NoteSym(Ref->getSymbol(), Ref->getLoc()); + } else if (SizeExpr->getKind() == MCExpr::Binary) { + const MCBinaryExpr *BE = static_cast(SizeExpr); + MCValue V; + + if (BE->evaluateAsRelocatable(V, &Layout, nullptr)) { + if (V.getSymA()) + NoteSym(V.getSymA()->getSymbol(), V.getSymA()->getLoc()); + if (V.getSymB()) + NoteSym(V.getSymB()->getSymbol(), V.getSymB()->getLoc()); + } + } +} + bool ELFWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol, bool Used, bool Renamed) { if (Symbol.isVariable()) { @@ -736,7 +794,7 @@ ? 0 : StrTabBuilder.getOffset(MSD.Name); MSD.Symbol->setIndex(Index++); - writeSymbol(Writer, StringIndex, MSD, Layout); + writeSymbol(Asm, Writer, StringIndex, MSD, Layout); } for (; FileNameIt != FileNames.end(); ++FileNameIt) { Writer.writeSymbol(StrTabBuilder.getOffset(FileNameIt->first), @@ -751,7 +809,7 @@ for (ELFSymbolData &MSD : ExternalSymbolData) { unsigned StringIndex = StrTabBuilder.getOffset(MSD.Name); MSD.Symbol->setIndex(Index++); - writeSymbol(Writer, StringIndex, MSD, Layout); + writeSymbol(Asm, Writer, StringIndex, MSD, Layout); assert(MSD.Symbol->getBinding() != ELF::STB_LOCAL); } diff --git a/llvm/test/MC/ELF/size-error.s b/llvm/test/MC/ELF/size-error.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ELF/size-error.s @@ -0,0 +1,35 @@ +// RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux < %s 2>&1 \ +// RUN: | FileCheck --implicit-check-not=error %s + +.section some + +Bar: +nop + +.section other + +foo: + .size foo, fo +// CHECK: error: size expression is not absolute +// CHECK: note: symbol not defined +// CHECK: note: did you mean to refer to 'foo'? + +ethers: + nop + .size ethers, Bar + 42 +// CHECK: error: size expression is not absolute +// CHECK: note: symbol 'Bar' is not defined in this section + +a: + .size a, . - others +// CHECK: error: size expression is not absolute +// CHECK: note: symbol not defined +// CHECK: note: did you mean to refer to 'other'? +// CHECK: note: did you mean to refer to 'ethers'? + +bar: + .size bar, 31 - baz + +// CHECK: error: size expression is not absolute +// CHECK: note: symbol not defined +// CHECK: note: did you mean to refer to 'bar'?