Index: llvm/docs/Extensions.rst =================================================================== --- llvm/docs/Extensions.rst +++ llvm/docs/Extensions.rst @@ -329,6 +329,36 @@ written at the end of the file. This forces the symbol to show up in the symbol table. +``SHT_LLVM_ADDRSIG`` Section (address-significance table) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This section is used to mark symbols as address-significant, i.e. the address +of the symbol is used in a comparison or leaks outside the translation unit. It +has the same meaning as the absence of the LLVM attributes ``unnamed_addr`` +and ``local_unnamed_addr``. + +Any sections referred to by symbols that are not marked as address-significant +in any object file may be safely merged by a linker without breaking the +address uniqueness guarantee provided by the C and C++ language standards. + +The contents of the section are a sequence of ULEB128-encoded integers +referring to the symbol table indexes of the address-significant symbols. + +There are two associated assembly directives: + +.. code-block:: gas + + .addrsig + +This instructs the assembler to emit an address-significance table. Without +this directive, all symbols are considered address-significant. + +.. code-block:: gas + + .addrsig_sym sym + +This marks ``sym`` as address-significant. + Target Specific Behaviour ========================= Index: llvm/include/llvm/BinaryFormat/ELF.h =================================================================== --- llvm/include/llvm/BinaryFormat/ELF.h +++ llvm/include/llvm/BinaryFormat/ELF.h @@ -804,6 +804,8 @@ SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table. SHT_LLVM_LINKER_OPTIONS = 0x6fff4c01, // LLVM Linker Options. SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c02, // LLVM Call Graph Profile. + SHT_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols + // for safe ICF. SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes. SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table. SHT_GNU_verdef = 0x6ffffffd, // GNU version definitions. Index: llvm/include/llvm/MC/MCObjectStreamer.h =================================================================== --- llvm/include/llvm/MC/MCObjectStreamer.h +++ llvm/include/llvm/MC/MCObjectStreamer.h @@ -166,6 +166,9 @@ SMLoc Loc = SMLoc()) override; void EmitFileDirective(StringRef Filename) override; + void EmitAddrsig() override; + void EmitAddrsigSym(const MCSymbol *Sym) override; + void FinishImpl() override; /// Emit the absolute difference between two symbols if possible. Index: llvm/include/llvm/MC/MCObjectWriter.h =================================================================== --- llvm/include/llvm/MC/MCObjectWriter.h +++ llvm/include/llvm/MC/MCObjectWriter.h @@ -92,6 +92,15 @@ bool InSet, bool IsPCRel) const; + /// Tell the object writer to emit an address-significance table during + /// writeObject(). If this function is not called, all symbols are treated as + /// address-significant. + virtual void emitAddrsigSection() {} + + /// Record the given symbol in the address-significance table to be written + /// diring writeObject(). + virtual void addAddrsigSymbol(const MCSymbol *Sym) {} + /// Write the object file and returns the number of bytes written. /// /// This routine is called by the assembler after layout and relaxation is Index: llvm/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/include/llvm/MC/MCStreamer.h +++ llvm/include/llvm/MC/MCStreamer.h @@ -922,6 +922,9 @@ return true; } + virtual void EmitAddrsig() {} + virtual void EmitAddrsigSym(const MCSymbol *Sym) {} + /// Emit the given \p Instruction into the current section. /// PrintSchedInfo == true then schedul comment should be added to output virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, Index: llvm/lib/MC/ELFObjectWriter.cpp =================================================================== --- llvm/lib/MC/ELFObjectWriter.cpp +++ llvm/lib/MC/ELFObjectWriter.cpp @@ -43,6 +43,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/StringSaver.h" @@ -199,6 +200,8 @@ const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets); + void writeAddrsigSection(); + MCSectionELF *createRelocationSection(MCContext &Ctx, const MCSectionELF &Sec); @@ -232,6 +235,9 @@ DenseMap Renames; + bool EmitAddrsigSection = false; + std::vector AddrsigSyms; + bool hasRelocationAddend() const; bool shouldRelocateWithSymbol(const MCAssembler &Asm, @@ -267,6 +273,11 @@ void executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) override; + void emitAddrsigSection() override { EmitAddrsigSection = true; } + void addAddrsigSymbol(const MCSymbol *Sym) override { + AddrsigSyms.push_back(Sym); + } + friend struct ELFWriter; }; @@ -747,6 +758,11 @@ SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd); } +void ELFWriter::writeAddrsigSection() { + for (const MCSymbol *Sym : OWriter.AddrsigSyms) + encodeULEB128(Sym->getIndex(), W.OS); +} + MCSectionELF *ELFWriter::createRelocationSection(MCContext &Ctx, const MCSectionELF &Sec) { if (OWriter.Relocations[&Sec].empty()) @@ -977,6 +993,7 @@ case ELF::SHT_SYMTAB_SHNDX: case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: + case ELF::SHT_LLVM_ADDRSIG: sh_link = SymbolTableIndex; break; @@ -1123,6 +1140,13 @@ // string tables. StrTabBuilder.finalize(); } else { + MCSectionELF *AddrsigSection; + if (OWriter.EmitAddrsigSection) { + AddrsigSection = Ctx.getELFSection(".llvm_addrsig", ELF::SHT_LLVM_ADDRSIG, + ELF::SHF_EXCLUDE); + addToSectionTable(AddrsigSection); + } + // Compute symbol table information. computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap, SectionOffsets); @@ -1139,6 +1163,13 @@ uint64_t SecEnd = W.OS.tell(); SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd); } + + if (OWriter.EmitAddrsigSection) { + uint64_t SecStart = W.OS.tell(); + writeAddrsigSection(); + uint64_t SecEnd = W.OS.tell(); + SectionOffsets[AddrsigSection] = std::make_pair(SecStart, SecEnd); + } } if (CGProfileSection) { @@ -1238,6 +1269,12 @@ Renames.insert(std::make_pair(&Symbol, Alias)); } + + for (const MCSymbol *&Sym : AddrsigSyms) { + if (const MCSymbol *R = Renames.lookup(cast(Sym))) + Sym = R; + Sym->setUsedInReloc(); + } } // It is always valid to create a relocation with a symbol. It is preferable Index: llvm/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/lib/MC/MCAsmStreamer.cpp +++ llvm/lib/MC/MCAsmStreamer.cpp @@ -317,6 +317,9 @@ bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc) override; + void EmitAddrsig() override; + void EmitAddrsigSym(const MCSymbol *Sym) override; + /// If this file is backed by an assembly streamer, this dumps the specified /// string in the output .s file. This capability is indicated by the /// hasRawTextSupport() predicate. @@ -1825,6 +1828,17 @@ return false; } +void MCAsmStreamer::EmitAddrsig() { + OS << "\t.addrsig"; + EmitEOL(); +} + +void MCAsmStreamer::EmitAddrsigSym(const MCSymbol *Sym) { + OS << "\t.addrsig_sym "; + Sym->print(OS, MAI); + EmitEOL(); +} + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. Index: llvm/lib/MC/MCObjectStreamer.cpp =================================================================== --- llvm/lib/MC/MCObjectStreamer.cpp +++ llvm/lib/MC/MCObjectStreamer.cpp @@ -673,6 +673,15 @@ getAssembler().addFileName(Filename); } +void MCObjectStreamer::EmitAddrsig() { + getAssembler().getWriter().emitAddrsigSection(); +} + +void MCObjectStreamer::EmitAddrsigSym(const MCSymbol *Sym) { + getAssembler().registerSymbol(*Sym); + getAssembler().getWriter().addAddrsigSymbol(Sym); +} + void MCObjectStreamer::FinishImpl() { // If we are generating dwarf for assembly source files dump out the sections. if (getContext().getGenDwarfForAssembly()) Index: llvm/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/AsmParser.cpp +++ llvm/lib/MC/MCParser/AsmParser.cpp @@ -503,6 +503,8 @@ DK_ERROR, DK_WARNING, DK_PRINT, + DK_ADDRSIG, + DK_ADDRSIG_SYM, DK_END }; @@ -651,6 +653,10 @@ // .print bool parseDirectivePrint(SMLoc DirectiveLoc); + // Directives to support address-significance tables. + bool parseDirectiveAddrsig(); + bool parseDirectiveAddrsigSym(); + void initializeDirectiveKindMap(); }; @@ -2121,6 +2127,10 @@ return parseDirectiveDS(IDVal, 12); case DK_PRINT: return parseDirectivePrint(IDLoc); + case DK_ADDRSIG: + return parseDirectiveAddrsig(); + case DK_ADDRSIG_SYM: + return parseDirectiveAddrsigSym(); } return Error(IDLoc, "unknown directive"); @@ -5271,6 +5281,8 @@ DirectiveKindMap[".ds.w"] = DK_DS_W; DirectiveKindMap[".ds.x"] = DK_DS_X; DirectiveKindMap[".print"] = DK_PRINT; + DirectiveKindMap[".addrsig"] = DK_ADDRSIG; + DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { @@ -5510,6 +5522,21 @@ return false; } +bool AsmParser::parseDirectiveAddrsig() { + getStreamer().EmitAddrsig(); + return false; +} + +bool AsmParser::parseDirectiveAddrsigSym() { + StringRef Name; + if (check(parseIdentifier(Name), + "expected identifier in '.addrsig_sym' directive")) + return true; + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + getStreamer().EmitAddrsigSym(Sym); + return false; +} + // We are comparing pointers, but the pointers are relative to a single string. // Thus, this should always be deterministic. static int rewritesSort(const AsmRewrite *AsmRewriteA, Index: llvm/lib/Object/ELF.cpp =================================================================== --- llvm/lib/Object/ELF.cpp +++ llvm/lib/Object/ELF.cpp @@ -207,6 +207,7 @@ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LINKER_OPTIONS); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE); + STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef); Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -442,6 +442,7 @@ ECase(SHT_LLVM_ODRTAB); ECase(SHT_LLVM_LINKER_OPTIONS); ECase(SHT_LLVM_CALL_GRAPH_PROFILE); + ECase(SHT_LLVM_ADDRSIG); ECase(SHT_GNU_ATTRIBUTES); ECase(SHT_GNU_HASH); ECase(SHT_GNU_verdef); Index: llvm/test/MC/ELF/addrsig-error.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/addrsig-error.s @@ -0,0 +1,5 @@ +// RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s +// CHECK: Undefined temporary symbol + +.addrsig +.addrsig_sym .Lundef Index: llvm/test/MC/ELF/addrsig.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/addrsig.s @@ -0,0 +1,86 @@ +// RUN: llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - | FileCheck --check-prefix=ASM %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -s -t -sd -elf-addrsig | FileCheck %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -split-dwarf-file %t.dwo -o - | llvm-readobj -s -t -sd -elf-addrsig | FileCheck %s +// RUN: llvm-readobj -s %t.dwo | FileCheck --check-prefix=DWO %s + +// CHECK: Name: .llvm_addrsig +// CHECK-NEXT: Type: SHT_LLVM_ADDRSIG (0x6FFF4C03) +// CHECK-NEXT: Flags [ (0x80000000) +// CHECK-NEXT: SHF_EXCLUDE (0x80000000) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: 4 +// CHECK-NEXT: Link: 4 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 1 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 03050201 +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 4 +// CHECK-NEXT: Name: .symtab + +// CHECK: Name: .Llocal +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: +// CHECK-NEXT: Binding: +// CHECK-NEXT: Type: +// CHECK-NEXT: Other: +// CHECK-NEXT: Section: +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: local +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: +// CHECK-NEXT: Binding: +// CHECK-NEXT: Type: +// CHECK-NEXT: Other: +// CHECK-NEXT: Section: +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: g1 +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: +// CHECK-NEXT: Binding: +// CHECK-NEXT: Type: +// CHECK-NEXT: Other: +// CHECK-NEXT: Section: +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: g2 +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: +// CHECK-NEXT: Binding: +// CHECK-NEXT: Type: +// CHECK-NEXT: Other: +// CHECK-NEXT: Section: +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: g3 + +// CHECK: Addrsig [ +// CHECK-NEXT: Sym: g1 (3) +// CHECK-NEXT: Sym: g3 (5) +// CHECK-NEXT: Sym: local (2) +// CHECK-NEXT: Sym: .Llocal (1) +// CHECK-NEXT: ] + +// ASM: .addrsig +.addrsig +// ASM: .addrsig_sym g1 +.addrsig_sym g1 +.globl g2 +// ASM: .addrsig_sym g3 +.addrsig_sym g3 +// ASM: .addrsig_sym local +.addrsig_sym local +// ASM: .addrsig_sym .Llocal +.addrsig_sym .Llocal + +local: +.Llocal: + +// DWO-NOT: .llvm_addrsig Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -44,6 +44,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MipsABIFlags.h" #include "llvm/Support/ScopedPrinter.h" @@ -166,6 +167,7 @@ void printHashHistogram() override; void printCGProfile() override; + void printAddrsig() override; void printNotes() override; @@ -214,6 +216,7 @@ const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; const Elf_Shdr *DotCGProfileSec = nullptr; + const Elf_Shdr *DotAddrsigSec = nullptr; StringRef DynSymtabName; ArrayRef ShndxTable; @@ -266,6 +269,7 @@ void printSymbolsHelper(bool IsDynamic) const; const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; } + const Elf_Shdr *getDotAddrsigSec() const { return DotAddrsigSec; } ArrayRef getShndxTable() const { return ShndxTable; } StringRef getDynamicStringTable() const { return DynamicStringTable; } const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; } @@ -326,6 +330,7 @@ virtual void printProgramHeaders(const ELFFile *Obj) = 0; virtual void printHashHistogram(const ELFFile *Obj) = 0; virtual void printCGProfile(const ELFFile *Obj) = 0; + virtual void printAddrsig(const ELFFile *Obj) = 0; virtual void printNotes(const ELFFile *Obj) = 0; virtual void printELFLinkerOptions(const ELFFile *Obj) = 0; virtual void printMipsGOT(const MipsGOTParser &Parser) = 0; @@ -357,6 +362,7 @@ void printProgramHeaders(const ELFO *Obj) override; void printHashHistogram(const ELFFile *Obj) override; void printCGProfile(const ELFFile *Obj) override; + void printAddrsig(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; void printELFLinkerOptions(const ELFFile *Obj) override; void printMipsGOT(const MipsGOTParser &Parser) override; @@ -419,6 +425,7 @@ void printProgramHeaders(const ELFO *Obj) override; void printHashHistogram(const ELFFile *Obj) override; void printCGProfile(const ELFFile *Obj) override; + void printAddrsig(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; void printELFLinkerOptions(const ELFFile *Obj) override; void printMipsGOT(const MipsGOTParser &Parser) override; @@ -1413,6 +1420,12 @@ if (DotCGProfileSec != nullptr) reportError("Multiple .note.llvm.cgprofile"); DotCGProfileSec = &Sec; + break; + case ELF::SHT_LLVM_ADDRSIG: + if (DotAddrsigSec != nullptr) + reportError("Multiple .llvm_addrsig"); + DotAddrsigSec = &Sec; + break; } } @@ -2410,6 +2423,10 @@ ELFDumperStyle->printGroupSections(Obj); } +template void ELFDumper::printAddrsig() { + ELFDumperStyle->printAddrsig(Obj); +} + static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, StringRef Str2) { OS.PadToColumn(2u); @@ -2750,6 +2767,8 @@ return "LLVM_LINKER_OPTIONS"; case SHT_LLVM_CALL_GRAPH_PROFILE: return "LLVM_CALL_GRAPH_PROFILE"; + case SHT_LLVM_ADDRSIG: + return "LLVM_ADDRSIG"; // FIXME: Parse processor specific GNU attributes case SHT_GNU_ATTRIBUTES: return "ATTRIBUTES"; @@ -3408,6 +3427,11 @@ OS << "GNUStyle::printCGProfile not implemented\n"; } +template +void GNUStyle::printAddrsig(const ELFFile *Obj) { + OS << "GNUStyle::printAddrsig not implemented\n"; +} + static std::string getGNUNoteTypeName(const uint32_t NT) { static const struct { uint32_t ID; @@ -4219,6 +4243,27 @@ } } +template +void LLVMStyle::printAddrsig(const ELFFile *Obj) { + ListScope L(W, "Addrsig"); + if (!this->dumper()->getDotAddrsigSec()) + return; + ArrayRef Contents = unwrapOrError( + Obj->getSectionContents(this->dumper()->getDotAddrsigSec())); + const uint8_t *Cur = Contents.begin(); + const uint8_t *End = Contents.end(); + while (Cur != End) { + unsigned Size; + const char *Err; + uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); + if (Err) + reportError(Err); + W.printNumber("Sym", this->dumper()->getStaticSymbolName(SymIndex), + SymIndex); + Cur += Size; + } +} + template void LLVMStyle::printNotes(const ELFFile *Obj) { W.startLine() << "printNotes not implemented!\n"; Index: llvm/tools/llvm-readobj/ObjDumper.h =================================================================== --- llvm/tools/llvm-readobj/ObjDumper.h +++ llvm/tools/llvm-readobj/ObjDumper.h @@ -48,6 +48,7 @@ virtual void printGroupSections() {} virtual void printHashHistogram() {} virtual void printCGProfile() {} + virtual void printAddrsig() {} virtual void printNotes() {} virtual void printELFLinkerOptions() {} Index: llvm/tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- llvm/tools/llvm-readobj/llvm-readobj.cpp +++ llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -286,6 +286,9 @@ cl::opt CGProfile("elf-cg-profile", cl::desc("Display callgraph profile section")); + cl::opt Addrsig("elf-addrsig", + cl::desc("Display address-significance table")); + cl::opt Output("elf-output-style", cl::desc("Specify ELF dump style"), cl::values(clEnumVal(LLVM, "LLVM default style"), @@ -445,6 +448,8 @@ Dumper->printHashHistogram(); if (opts::CGProfile) Dumper->printCGProfile(); + if (opts::Addrsig) + Dumper->printAddrsig(); if (opts::Notes) Dumper->printNotes(); }