diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -14,6 +14,7 @@ #ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H #define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/BinaryFormat/XCOFF.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -32,6 +33,7 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { bool UseInitArray = false; mutable unsigned NextUniqueID = 1; // ID 0 is reserved for execute-only sections + SmallPtrSet Used; protected: MCSymbolRefExpr::VariantKind PLTRelativeVariantKind = @@ -43,6 +45,8 @@ void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + void getModuleMetadata(Module &M) override; + /// Emit Obj-C garbage collection and linker options. void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -293,6 +293,14 @@ } } +void TargetLoweringObjectFileELF::getModuleMetadata(Module &M) { + SmallVector Vec; + collectUsedGlobalVariables(M, Vec, false); + for (GlobalValue *GV : Vec) + if (auto *GO = dyn_cast(GV)) + Used.insert(GO); +} + void TargetLoweringObjectFileELF::emitModuleMetadata(MCStreamer &Streamer, Module &M) const { auto &C = getContext(); @@ -687,9 +695,15 @@ // MD_associated in a unique section. unsigned UniqueID = MCContext::GenericSectionID; const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM); - if (GO->getMetadata(LLVMContext::MD_associated)) { + const bool Associated = GO->getMetadata(LLVMContext::MD_associated); + const bool Retain = Used.count(GO); + if (Associated || Retain) { UniqueID = NextUniqueID++; - Flags |= ELF::SHF_LINK_ORDER; + if (Associated) + Flags |= ELF::SHF_LINK_ORDER; + if (Retain && (getContext().getAsmInfo()->useIntegratedAssembler() || + getContext().getAsmInfo()->binutilsIsAtLeast(2, 36))) + Flags |= ELF::SHF_GNU_RETAIN; } else { if (getContext().getAsmInfo()->useIntegratedAssembler() || getContext().getAsmInfo()->binutilsIsAtLeast(2, 35)) { @@ -802,13 +816,18 @@ static MCSection *selectELFSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, - const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags, - unsigned *NextUniqueID) { + const TargetMachine &TM, bool Retain, bool EmitUniqueSection, + unsigned Flags, unsigned *NextUniqueID) { const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM); if (LinkedToSym) { EmitUniqueSection = true; Flags |= ELF::SHF_LINK_ORDER; } + if (Retain && (Ctx.getAsmInfo()->useIntegratedAssembler() || + Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36))) { + EmitUniqueSection = true; + Flags |= ELF::SHF_GNU_RETAIN; + } MCSectionELF *Section = selectELFSectionForGlobal( Ctx, GO, Kind, Mang, TM, EmitUniqueSection, Flags, @@ -832,16 +851,17 @@ } EmitUniqueSection |= GO->hasComdat(); return selectELFSectionForGlobal(getContext(), GO, Kind, getMangler(), TM, - EmitUniqueSection, Flags, &NextUniqueID); + Used.count(GO), EmitUniqueSection, Flags, + &NextUniqueID); } MCSection *TargetLoweringObjectFileELF::getUniqueSectionForFunction( const Function &F, const TargetMachine &TM) const { SectionKind Kind = SectionKind::getText(); unsigned Flags = getELFSectionFlags(Kind); - return selectELFSectionForGlobal(getContext(), &F, Kind, getMangler(), TM, - /* EmitUniqueSection = */ true, Flags, - &NextUniqueID); + return selectELFSectionForGlobal( + getContext(), &F, Kind, getMangler(), TM, Used.count(&F), + /*EmitUniqueSection=*/true, Flags, &NextUniqueID); } MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable( diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp --- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp @@ -84,6 +84,7 @@ } void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) { + TargetLoweringObjectFileELF::getModuleMetadata(M); SmallVector ModuleFlags; M.getModuleFlagsMetadata(ModuleFlags); diff --git a/llvm/test/CodeGen/PowerPC/func-addr-consts.ll b/llvm/test/CodeGen/PowerPC/func-addr-consts.ll --- a/llvm/test/CodeGen/PowerPC/func-addr-consts.ll +++ b/llvm/test/CodeGen/PowerPC/func-addr-consts.ll @@ -12,5 +12,5 @@ ret void } -; CHECK: .section gsection,"aw",@progbits -; CHECK: .section hsection,"aw",@progbits +; CHECK: .section gsection,"awR",@progbits +; CHECK: .section hsection,"awR",@progbits diff --git a/llvm/test/CodeGen/PowerPC/no-dead-strip.ll b/llvm/test/CodeGen/PowerPC/no-dead-strip.ll --- a/llvm/test/CodeGen/PowerPC/no-dead-strip.ll +++ b/llvm/test/CodeGen/PowerPC/no-dead-strip.ll @@ -1,6 +1,6 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-linux-gnu < %s | FileCheck %s -; CHECK: .section .bss,"aw",@nobits +; CHECK: .section .bss.X,"awR",@nobits ; CHECK: .weak X ; CHECK-LABEL: X: ; CHECK: .long 0 diff --git a/llvm/test/CodeGen/X86/elf-retain.ll b/llvm/test/CodeGen/X86/elf-retain.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/elf-retain.ll @@ -0,0 +1,74 @@ +;; Place a global object in the llvm.used list in a unique section with the SHF_GNU_RETAIN flag. +; RUN: llc -mtriple=x86_64 < %s | FileCheck %s +; RUN: llc -mtriple=x86_64 -data-sections=1 < %s | FileCheck %s +; RUN: llc -mtriple=x86_64 -no-integrated-as -binutils-version=2.36 < %s | FileCheck %s +; RUN: llc -mtriple=x86_64 -no-integrated-as -binutils-version=2.35 < %s | FileCheck %s --check-prefix=OLDGAS + +; RUN: llc -mtriple=x86_64 -data-sections=1 -unique-section-names=0 < %s | FileCheck %s --check-prefix=NOUNIQUE + +@llvm.used = appending global [10 x i8*] [ + i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @fb to i8*), i8* bitcast (void ()* @fc to i8*), + i8* bitcast (i32* @ga to i8*), i8* bitcast (i32* @gb to i8*), i8* bitcast (i32* @gc to i8*), i8* bitcast (i32* @gd to i8*), i8* bitcast (i32* @ge to i8*), + i8* bitcast (i32* @aa to i8*), i8* bitcast (i32* @ab to i8*) ], section "llvm.metadata" + +; CHECK: .section .text.fa,"axR",@progbits{{$}} +; OLDGAS-NOT: .section .text +; NOUNIQUE: .section .text,"axR",@progbits,unique,1 +define dso_local void @fa() { +entry: + ret void +} + +; CHECK: .section .text.fb,"axR",@progbits{{$}} +; NOUNIQUE: .section .text,"axR",@progbits,unique,2 +define internal void @fb() { +entry: + ret void +} + +;; Explicit section. +; CHECK: .section ccc,"axR",@progbits,unique,1 +; OLDGAS: .section ccc,"ax",@progbits,unique,1 +; NOUNIQUE: .section ccc,"axR",@progbits,unique,3 +define dso_local void @fc() section "ccc" { +entry: + ret void +} + +; CHECK: .section .bss.ga,"awR",@nobits{{$}} +; OLDGAS: .bss{{$}} +; NOUNIQUE: .section .bss,"awR",@nobits,unique,4 +@ga = global i32 0 + +; CHECK: .section .data.gb,"awR",@progbits{{$}} +; OLDGAS: .data{{$}} +; NOUNIQUE: .section .data,"awR",@progbits,unique,5 +@gb = internal global i32 2 + +; CHECK: .section .rodata.gc,"aR",@progbits{{$}} +; OLDGAS: .section .rodata,"a",@progbits{{$}} +; NOUNIQUE: .section .rodata,"aR",@progbits,unique,6 +@gc = constant i32 3 + +;; Explicit section. +; CHECK: .section ddd,"awR",@progbits,unique,2 +; OLDGAS: .section ddd,"aw",@progbits,unique,2 +; NOUNIQUE: .section ddd,"awR",@progbits,unique,7 +@gd = global i32 1, section "ddd" + +;; Used together with !associated. +; CHECK: .section .data.ge,"awoR",@progbits,gc +; OLDGAS: .section .data.ge,"awo",@progbits,gc +; NOUNIQUE: .section .data,"awoR",@progbits,gc,unique,8 +@ge = global i32 1, !associated !0 + +;; Aliases in llvm.used are ignored. +; CHECK: .section fff,"aw",@progbits{{$}} +; OLDGAS: .section fff,"aw",@progbits{{$}} +; NOUNIQUE: .section fff,"aw",@progbits{{$}} +@gf = global i32 1, section "fff" + +@aa = alias i32, i32* @gf +@ab = internal alias i32, i32* @gf + +!0 = !{i32* @gc}