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.
+
CodeView-Dependent
------------------
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.
// Android's experimental support for SHT_RELR sections.
// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.
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.
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
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,
#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"
const RevGroupMapTy &RevGroupMap,
SectionOffsetsTy &SectionOffsets);
+ void writeAddrsigSection();
+
MCSectionELF *createRelocationSection(MCContext &Ctx,
const MCSectionELF &Sec);
DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames;
+ bool EmitAddrsigSection = false;
+ std::vector<const MCSymbol *> AddrsigSyms;
+
bool hasRelocationAddend() const;
bool shouldRelocateWithSymbol(const MCAssembler &Asm,
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;
};
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())
case ELF::SHT_SYMTAB_SHNDX:
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
+ case ELF::SHT_LLVM_ADDRSIG:
sh_link = SymbolTableIndex;
break;
// 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);
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) {
Renames.insert(std::make_pair(&Symbol, Alias));
}
+
+ for (const MCSymbol *&Sym : AddrsigSyms) {
+ if (const MCSymbol *R = Renames.lookup(cast<MCSymbolELF>(Sym)))
+ Sym = R;
+ Sym->setUsedInReloc();
+ }
}
// It is always valid to create a relocation with a symbol. It is preferable
const MCExpr *Expr, SMLoc Loc,
const MCSubtargetInfo &STI) 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.
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.
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() {
getContext().RemapDebugPaths();
DK_ERROR,
DK_WARNING,
DK_PRINT,
+ DK_ADDRSIG,
+ DK_ADDRSIG_SYM,
DK_END
};
// .print <double-quotes-string>
bool parseDirectivePrint(SMLoc DirectiveLoc);
+ // Directives to support address-significance tables.
+ bool parseDirectiveAddrsig();
+ bool parseDirectiveAddrsigSym();
+
void initializeDirectiveKindMap();
};
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");
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) {
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,
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);
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);
--- /dev/null
+// 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
--- /dev/null
+// 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
#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"
void printHashHistogram() override;
void printCGProfile() override;
+ void printAddrsig() override;
void printNotes() override;
const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
const Elf_Shdr *DotCGProfileSec = nullptr;
+ const Elf_Shdr *DotAddrsigSec = nullptr;
StringRef DynSymtabName;
ArrayRef<Elf_Word> ShndxTable;
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<Elf_Word> getShndxTable() const { return ShndxTable; }
StringRef getDynamicStringTable() const { return DynamicStringTable; }
const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; }
StringRef SectionName) = 0;
virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
virtual void printCGProfile(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0;
virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0;
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
void printSectionAsString(const ELFO *Obj, StringRef SectionName) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
+ void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
void printSectionAsString(const ELFO *Obj, StringRef SectionName) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
+ void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override;
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
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;
}
}
ELFDumperStyle->printGroupSections(Obj);
}
+template <class ELFT> void ELFDumper<ELFT>::printAddrsig() {
+ ELFDumperStyle->printAddrsig(Obj);
+}
+
static inline void printFields(formatted_raw_ostream &OS, StringRef Str1,
StringRef Str2) {
OS.PadToColumn(2u);
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";
OS << "GNUStyle::printCGProfile not implemented\n";
}
+template <class ELFT>
+void GNUStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) {
+ OS << "GNUStyle::printAddrsig not implemented\n";
+}
+
static std::string getGNUNoteTypeName(const uint32_t NT) {
static const struct {
uint32_t ID;
}
template <class ELFT>
+void LLVMStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) {
+ ListScope L(W, "Addrsig");
+ if (!this->dumper()->getDotAddrsigSec())
+ return;
+ ArrayRef<uint8_t> 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 <class ELFT>
void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
W.startLine() << "printNotes not implemented!\n";
}
virtual void printGroupSections() {}
virtual void printHashHistogram() {}
virtual void printCGProfile() {}
+ virtual void printAddrsig() {}
virtual void printNotes() {}
virtual void printELFLinkerOptions() {}
cl::opt<bool> CGProfile("elf-cg-profile", cl::desc("Display callgraph profile section"));
+ cl::opt<bool> Addrsig("elf-addrsig",
+ cl::desc("Display address-significance table"));
+
cl::opt<OutputStyleTy>
Output("elf-output-style", cl::desc("Specify ELF dump style"),
cl::values(clEnumVal(LLVM, "LLVM default style"),
Dumper->printHashHistogram();
if (opts::CGProfile)
Dumper->printCGProfile();
+ if (opts::Addrsig)
+ Dumper->printAddrsig();
if (opts::Notes)
Dumper->printNotes();
}