Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -153,6 +153,7 @@ CODEGENOPT(FatalWarnings , 1, 0) ///< Set when -Wa,--fatal-warnings is ///< enabled. CODEGENOPT(NoWarn , 1, 0) ///< Set when -Wa,--no-warn is enabled. +CODEGENOPT(GenerateMissingBuildNotes, 1, 0) ///< Set when -Wa,--generate-missing-build-notes=yes is passed CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled. CODEGENOPT(NoInlineLineTables, 1, 0) ///< Whether debug info should contain ///< inline line tables. Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -3674,6 +3674,8 @@ HelpText<"Mark the file as not needing an executable stack">; def massembler_no_warn : Flag<["-"], "massembler-no-warn">, HelpText<"Make assembler not emit warnings">; +def massembler_generate_missing_build_notes : Flag<["-"], "massembler-generate-missing-build-notes">, + HelpText<"Make assembler emit missing GNU build notes">; def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">, HelpText<"Make assembler warnings fatal">; def mrelax_relocations : Flag<["--"], "mrelax-relocations">, Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -529,6 +529,8 @@ CodeGenOpts.IncrementalLinkerCompatible; Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings; Options.MCOptions.MCNoWarn = CodeGenOpts.NoWarn; + Options.MCOptions.MCGenerateMissingBuildNotes = + CodeGenOpts.GenerateMissingBuildNotes; Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose; Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments; Options.MCOptions.ABIName = TargetOpts.ABI; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2276,6 +2276,7 @@ bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations(); bool UseNoExecStack = C.getDefaultToolChain().isNoExecStackDefault(); + bool UseGenerateMissingBuildNotes = false; const char *MipsTargetFeature = nullptr; for (const Arg *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { @@ -2358,6 +2359,10 @@ CmdArgs.push_back("-massembler-fatal-warnings"); } else if (Value == "--no-warn" || Value == "-W") { CmdArgs.push_back("-massembler-no-warn"); + } else if (Value == "--generate-missing-build-notes=yes") { + UseGenerateMissingBuildNotes = true; + } else if (Value == "--generate-missing-build-notes=no") { + UseGenerateMissingBuildNotes = false; } else if (Value == "--noexecstack") { UseNoExecStack = true; } else if (Value.startswith("-compress-debug-sections") || @@ -2430,6 +2435,8 @@ CmdArgs.push_back("--mrelax-relocations"); if (UseNoExecStack) CmdArgs.push_back("-mnoexecstack"); + if (UseGenerateMissingBuildNotes) + CmdArgs.push_back("-massembler-generate-missing-build-notes"); if (MipsTargetFeature != nullptr) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back(MipsTargetFeature); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -948,6 +948,8 @@ getLastArgIntValue(Args, OPT_msmall_data_limit, 0, Diags); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn); + Opts.GenerateMissingBuildNotes = + Args.hasArg(OPT_massembler_generate_missing_build_notes); Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks); Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.IncrementalLinkerCompatible = Index: clang/test/Misc/generate-missing-build-notes.c =================================================================== --- /dev/null +++ clang/test/Misc/generate-missing-build-notes.c @@ -0,0 +1,13 @@ +// RUN: %clang -c -Wa,--generate-missing-build-notes=yes %s -o - | llvm-readobj -r --section-relocations - | FileCheck %s + +int main(int argc, char **argv) { + return 0; +} + +// CHECK: Section {{.*}} .rela.gnu.build.attributes { +// CHECK-NEXT: 0x14 R_X86_64_64 .text 0x0 +// CHECK-NEXT: 0x1C R_X86_64_64 .text 0x16 +// CHECK-NEXT: } + +// Run this one as well, just to check that =no is accepted. +// RUN: %clang -c -Wa,--generate-missing-build-notes=no %s -o - Index: clang/tools/driver/cc1as_main.cpp =================================================================== --- clang/tools/driver/cc1as_main.cpp +++ clang/tools/driver/cc1as_main.cpp @@ -133,6 +133,7 @@ unsigned NoExecStack : 1; unsigned FatalWarnings : 1; unsigned NoWarn : 1; + unsigned GenerateMissingBuildNotes : 1; unsigned IncrementalLinkerCompatible : 1; unsigned EmbedBitcode : 1; @@ -159,6 +160,7 @@ NoExecStack = 0; FatalWarnings = 0; NoWarn = 0; + GenerateMissingBuildNotes = 0; IncrementalLinkerCompatible = 0; DwarfVersion = 0; EmbedBitcode = 0; @@ -295,6 +297,8 @@ Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn); + Opts.GenerateMissingBuildNotes = + Args.hasArg(OPT_massembler_generate_missing_build_notes); Opts.RelocationModel = std::string(Args.getLastArgValue(OPT_mrelocation_model, "pic")); Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi)); @@ -426,6 +430,8 @@ if (Opts.GenDwarfForAssembly) Ctx.setGenDwarfRootFile(Opts.InputFile, SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer()); + if (Opts.GenerateMissingBuildNotes) + Ctx.setGenerateMissingBuildNotes(true); // Build up the feature string from the target feature list. std::string FS = llvm::join(Opts.Features, ","); @@ -441,6 +447,7 @@ MCOptions.MCNoWarn = Opts.NoWarn; MCOptions.MCFatalWarnings = Opts.FatalWarnings; + MCOptions.MCGenerateMissingBuildNotes = Opts.GenerateMissingBuildNotes; MCOptions.ABIName = Opts.TargetABI; // FIXME: There is a bit of code duplication with addPassesToEmitFile. Index: llvm/include/llvm/MC/MCContext.h =================================================================== --- llvm/include/llvm/MC/MCContext.h +++ llvm/include/llvm/MC/MCContext.h @@ -195,6 +195,7 @@ /// Darwin). bool AllowTemporaryLabels = true; bool UseNamesOnTempLabels = false; + bool GenerateMissingBuildNotes = false; /// The Compile Unit ID that we are currently processing. unsigned DwarfCompileUnitID = 0; @@ -371,6 +372,12 @@ void setAllowTemporaryLabels(bool Value) { AllowTemporaryLabels = Value; } void setUseNamesOnTempLabels(bool Value) { UseNamesOnTempLabels = Value; } + void setGenerateMissingBuildNotes(bool Value) { + GenerateMissingBuildNotes = Value; + } + bool getGenerateMissingBuildNotes() const { + return GenerateMissingBuildNotes; + } /// \name Module Lifetime Management /// @{ @@ -472,6 +479,9 @@ BeginSymName); } + bool hasELFSection(const Twine &Section, const MCSymbolELF *GroupSym, + unsigned UniqueID, const MCSymbolELF *LinkedToSym); + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags) { return getELFSection(Section, Type, Flags, 0, ""); Index: llvm/include/llvm/MC/MCTargetOptions.h =================================================================== --- llvm/include/llvm/MC/MCTargetOptions.h +++ llvm/include/llvm/MC/MCTargetOptions.h @@ -47,6 +47,7 @@ bool MCSaveTempLabels : 1; bool MCUseDwarfDirectory : 1; bool MCIncrementalLinkerCompatible : 1; + bool MCGenerateMissingBuildNotes : 1; bool ShowMCEncoding : 1; bool ShowMCInst : 1; bool AsmVerbose : 1; Index: llvm/lib/CodeGen/LLVMTargetMachine.cpp =================================================================== --- llvm/lib/CodeGen/LLVMTargetMachine.cpp +++ llvm/lib/CodeGen/LLVMTargetMachine.cpp @@ -121,6 +121,9 @@ if (Options.MCOptions.MCSaveTempLabels) Context.setAllowTemporaryLabels(false); + if (Options.MCOptions.MCGenerateMissingBuildNotes) + Context.setGenerateMissingBuildNotes(true); + const MCSubtargetInfo &STI = *getMCSubtargetInfo(); const MCAsmInfo &MAI = *getMCAsmInfo(); const MCRegisterInfo &MRI = *getMCRegisterInfo(); @@ -227,6 +230,9 @@ if (Options.MCOptions.MCSaveTempLabels) Ctx->setAllowTemporaryLabels(false); + if (Options.MCOptions.MCGenerateMissingBuildNotes) + Ctx->setGenerateMissingBuildNotes(true); + // Create the code emitter for the target if it exists. If not, .o file // emission fails. const MCSubtargetInfo &STI = *getMCSubtargetInfo(); Index: llvm/lib/MC/ELFObjectWriter.cpp =================================================================== --- llvm/lib/MC/ELFObjectWriter.cpp +++ llvm/lib/MC/ELFObjectWriter.cpp @@ -222,6 +222,10 @@ void writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec); + void writeBuildNote(MCContext &Ctx, const MCSectionELF *Section, + const MCSectionELF *BuildAttributes, + uint64_t BuildAttributesStart, + SectionOffsetsTy &SectionOffsets); uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout); void writeSection(const SectionIndexMapTy &SectionIndexMap, uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, @@ -1070,6 +1074,68 @@ } } +void ELFWriter::writeBuildNote(MCContext &Ctx, const MCSectionELF *Section, + const MCSectionELF *BuildAttributes, + uint64_t BuildAttributesStart, + SectionOffsetsTy &SectionOffsets) { + const MCSymbolELF *SectionSymbol = + static_cast(Section->getBeginSymbol()); + const uint64_t BuildNoteSize = is64Bit() ? 36 : 28; + const uint64_t RelEndOffset = is64Bit() ? 28 : 24; + const uint64_t SectionOffset = W.OS.tell() - BuildAttributesStart; + const uint64_t SectionSize = + SectionOffsets[Section].second - SectionOffsets[Section].first; + const uint64_t BuildNoteStart = W.OS.tell(); + + W.write(8); // strlen(name) + 1 + W.write(is64Bit() ? 16 : 8); // Two N-byte offsets + W.write(ELF::NT_GNU_BUILD_ATTRIBUTE_OPEN); + + // The a2 version number indicates that this note was + // generated by the LLVM assembler and not the annobin plugin. + W.write('G'); + W.write('A'); + W.write('$'); + W.write(''); + W.write('3'); + W.write('a'); + W.write('2'); + W.write('\0'); + + // 20 bytes so far + assert(W.OS.tell() - BuildNoteStart == 20); + + if (!hasRelocationAddend()) { + if (is64Bit()) { + W.write(SectionSize); + } else { + W.OS.write_zeros(4); + W.write(SectionSize); + } + } + + W.OS.write_zeros(BuildNoteSize - + (W.OS.tell() - BuildNoteStart)); // Fill up with zeroes + + MCFixup Fixup = MCFixup::create(SectionOffset, nullptr, + is64Bit() ? MCFixupKind::FK_Data_8 + : MCFixupKind::FK_Data_4); + MCValue Value = MCValue::get(nullptr, nullptr, 0, 0); + auto RelocType = + OWriter.TargetObjectWriter->getRelocType(Ctx, Value, Fixup, false); + + SectionSymbol->setUsedInReloc(); + // Create a relocation to install the start address of the note + ELFRelocationEntry RelStart(SectionOffset + 20, SectionSymbol, RelocType, 0, + nullptr, 0); + OWriter.Relocations[BuildAttributes].push_back(RelStart); + + // ... and one to install the end address + ELFRelocationEntry RelEnd(SectionOffset + RelEndOffset, SectionSymbol, + RelocType, SectionSize, nullptr, 0); + OWriter.Relocations[BuildAttributes].push_back(RelEnd); +} + uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { uint64_t StartOffset = W.OS.tell(); @@ -1135,6 +1201,47 @@ OWriter.TargetObjectWriter->addTargetSectionFlags(Ctx, Section); } + // .gnu.build.attributes section + if (Ctx.getGenerateMissingBuildNotes() && + !Ctx.hasELFSection(".gnu.build.attributes", nullptr, + MCSection::NonUniqueID, nullptr)) { + MCSectionELF *BuildAttributes = + Ctx.getELFSection(".gnu.build.attributes", ELF::SHT_NOTE, 0); + BuildAttributes->setAlignment(Align(2)); + SectionIndexMap[BuildAttributes] = addToSectionTable(BuildAttributes); + + // Create a build note for each code section + const uint64_t BuildAttributesStart = W.OS.tell(); + for (const MCSection &Section : Asm) { + const MCSectionELF *SectionELF = + static_cast(&Section); + + if (Section.getKind().isMetadata()) + continue; + + if (!Section.hasInstructions() && !Section.getKind().isText()) + continue; + + // TODO: Are linkonce sections marked in any other way? + if (Section.getName().startswith(".gnu.linkonce")) + continue; + + writeBuildNote(Ctx, SectionELF, BuildAttributes, BuildAttributesStart, + SectionOffsets); + } + const uint64_t BuildAttributesEnd = W.OS.tell(); + + if (BuildAttributesEnd != BuildAttributesStart) { + SectionOffsets[BuildAttributes] = + std::make_pair(BuildAttributesStart, BuildAttributesEnd); + + auto RelocSection = createRelocationSection(Ctx, *BuildAttributes); + assert(RelocSection); + SectionIndexMap[RelocSection] = addToSectionTable(RelocSection); + Relocations.push_back(RelocSection); + } + } + MCSectionELF *CGProfileSection = nullptr; if (!Asm.CGProfile.empty()) { CGProfileSection = Ctx.getELFSection(".llvm.call-graph-profile", Index: llvm/lib/MC/MCContext.cpp =================================================================== --- llvm/lib/MC/MCContext.cpp +++ llvm/lib/MC/MCContext.cpp @@ -476,6 +476,21 @@ LinkedToSym); } +bool MCContext::hasELFSection(const Twine &Section, const MCSymbolELF *GroupSym, + unsigned UniqueID, + const MCSymbolELF *LinkedToSym) { + StringRef Group = ""; + if (GroupSym) + Group = GroupSym->getName(); + assert(!(LinkedToSym && LinkedToSym->getName().empty())); + + auto key = ELFUniquingMap.find( + ELFSectionKey{Section.str(), Group, + LinkedToSym ? LinkedToSym->getName() : "", UniqueID}); + + return key != ELFUniquingMap.end(); +} + MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *GroupSym, Index: llvm/lib/MC/MCTargetOptions.cpp =================================================================== --- llvm/lib/MC/MCTargetOptions.cpp +++ llvm/lib/MC/MCTargetOptions.cpp @@ -15,8 +15,9 @@ : MCRelaxAll(false), MCNoExecStack(false), MCFatalWarnings(false), MCNoWarn(false), MCNoDeprecatedWarn(false), MCSaveTempLabels(false), MCUseDwarfDirectory(false), MCIncrementalLinkerCompatible(false), - ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false), - PreserveAsmComments(true), Dwarf64(false) {} + MCGenerateMissingBuildNotes(false), ShowMCEncoding(false), + ShowMCInst(false), AsmVerbose(false), PreserveAsmComments(true), + Dwarf64(false) {} StringRef MCTargetOptions::getABIName() const { return ABIName; Index: llvm/test/MC/ELF/build-notes.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/build-notes.s @@ -0,0 +1,55 @@ +// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s +// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple i386-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s --check-prefix=i386 +// RUN: llvm-mc --generate-missing-build-notes -filetype=obj -triple armeb-pc-linux-gnu %s -o - | llvm-readobj -r --section-relocations --hex-dump=.gnu.build.attributes - | FileCheck %s --check-prefix=armbe32 + + .text + .dc.l 1 + + .section .text.unused,"ax" + .space 1025 + + .section .gnu.linkonce,"ax" + .dc.l 3 + +// CHECK: Relocations [ +// CHECK-NEXT: Section {{.*}} .rela.gnu.build.attributes { +// CHECK-NEXT: 0x14 R_X86_64_64 .text 0x0 +// CHECK-NEXT: 0x1C R_X86_64_64 .text 0x4 +// CHECK-NEXT: 0x38 R_X86_64_64 .text.unused 0x0 +// CHECK-NEXT: 0x40 R_X86_64_64 .text.unused 0x401 +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK: Hex dump of section '.gnu.build.attributes': +// CHECK-NEXT: 0x00000000 08000000 10000000 00010000 47412401 ............GA$. +// CHECK-NEXT: 0x00000010 33613200 00000000 00000000 00000000 3a2............. +// CHECK-NEXT: 0x00000020 00000000 08000000 10000000 00010000 ................ +// CHECK-NEXT: 0x00000030 47412401 33613200 00000000 00000000 GA$.3a2......... +// CHECK-NEXT: 0x00000040 00000000 00000000 ........ + +// i386: Relocations [ +// i386-NEXT: Section {{.*}} .rel.gnu.build.attributes { +// i386-NEXT: 0x14 R_386_32 .text 0x0 +// i386-NEXT: 0x18 R_386_32 .text 0x0 +// i386-NEXT: 0x30 R_386_32 .text.unused 0x0 +// i386-NEXT: 0x34 R_386_32 .text.unused 0x0 +// i386-NEXT: } +// i386-NEXT: ] +// i386: Hex dump of section '.gnu.build.attributes': +// i386-NEXT: 0x00000000 08000000 08000000 00010000 47412401 ............GA$. +// i386-NEXT: 0x00000010 33613200 00000000 04000000 08000000 3a2............. +// i386-NEXT: 0x00000020 08000000 00010000 47412401 33613200 ........GA$.3a2. +// i386-NEXT: 0x00000030 00000000 01040000 ........ + +// armbe32: Relocations [ +// armbe32-NEXT: Section {{.*}} .rel.gnu.build.attributes { +// armbe32-NEXT: 0x14 R_ARM_ABS32 .text 0x0 +// armbe32-NEXT: 0x18 R_ARM_ABS32 .text 0x0 +// armbe32-NEXT: 0x30 R_ARM_ABS32 .text.unused 0x0 +// armbe32-NEXT: 0x34 R_ARM_ABS32 .text.unused 0x0 +// armbe32-NEXT: } +// armbe32-NEXT: ] +// armbe32: Hex dump of section '.gnu.build.attributes': +// armbe32-NEXT: 0x00000000 00000008 00000008 00000100 47412401 ............GA$. +// armbe32-NEXT: 0x00000010 33613200 00000000 00000004 00000008 3a2............. +// armbe32-NEXT: 0x00000020 00000008 00000100 47412401 33613200 ........GA$.3a2. +// armbe32-NEXT: 0x00000030 00000000 00000401 ........ Index: llvm/tools/llvm-mc/llvm-mc.cpp =================================================================== --- llvm/tools/llvm-mc/llvm-mc.cpp +++ llvm/tools/llvm-mc/llvm-mc.cpp @@ -172,6 +172,10 @@ static cl::opt NoExecStack("no-exec-stack", cl::desc("File doesn't need an exec stack")); +static cl::opt + GenerateMissingBuildNotes("generate-missing-build-notes", + cl::desc("Generate missing GNU build notes")); + enum ActionType { AC_AsLex, AC_Assemble, @@ -378,6 +382,9 @@ if (SaveTempLabels) Ctx.setAllowTemporaryLabels(false); + if (GenerateMissingBuildNotes) + Ctx.setGenerateMissingBuildNotes(true); + Ctx.setGenDwarfForAssembly(GenDwarfForAssembly); // Default to 4 for dwarf version. unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4;