[llvm] 47c5576 - ELF: Create unique SHF_GNU_RETAIN sections for llvm.used global objects

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 26 16:38:52 PST 2021


Author: Fangrui Song
Date: 2021-02-26T16:38:44-08:00
New Revision: 47c5576d7d586624c38f76bd3168e05f6ef1f838

URL: https://github.com/llvm/llvm-project/commit/47c5576d7d586624c38f76bd3168e05f6ef1f838
DIFF: https://github.com/llvm/llvm-project/commit/47c5576d7d586624c38f76bd3168e05f6ef1f838.diff

LOG: ELF: Create unique SHF_GNU_RETAIN sections for llvm.used global objects

If a global object is listed in `@llvm.used`, place it in a unique section with
the `SHF_GNU_RETAIN` flag. The section is a GC root under `ld --gc-sections`
with LLD>=13 or GNU ld>=2.36.

For front ends which do not expect to see multiple sections of the same name,
consider emitting `@llvm.compiler.used` instead of `@llvm.used`.

SHF_GNU_RETAIN is restricted to ELFOSABI_GNU and ELFOSABI_FREEBSD in
binutils. We don't do the restriction - see the rationale in D95749.

The integrated assembler has supported SHF_GNU_RETAIN since D95730.
GNU as>=2.36 supports section flag 'R'.
We don't need to worry about GNU ld support because older GNU ld just ignores
the unknown SHF_GNU_RETAIN.

With this change, `__attribute__((retain))` functions/variables emitted
by clang will get the SHF_GNU_RETAIN flag.

Differential Revision: https://reviews.llvm.org/D97448

Added: 
    llvm/test/CodeGen/X86/elf-retain.ll

Modified: 
    llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
    llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
    llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
    llvm/test/CodeGen/PowerPC/func-addr-consts.ll
    llvm/test/CodeGen/PowerPC/no-dead-strip.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index 73df97a81e70..52c8527f47ce 100644
--- 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 TargetMachine;
 class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
   bool UseInitArray = false;
   mutable unsigned NextUniqueID = 1;  // ID 0 is reserved for execute-only sections
+  SmallPtrSet<GlobalObject *, 2> Used;
 
 protected:
   MCSymbolRefExpr::VariantKind PLTRelativeVariantKind =
@@ -43,6 +45,8 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
 
   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
index 8f74866187c2..f1729d1280bb 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -293,6 +293,14 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx,
   }
 }
 
+void TargetLoweringObjectFileELF::getModuleMetadata(Module &M) {
+  SmallVector<GlobalValue *, 4> Vec;
+  collectUsedGlobalVariables(M, Vec, false);
+  for (GlobalValue *GV : Vec)
+    if (auto *GO = dyn_cast<GlobalObject>(GV))
+      Used.insert(GO);
+}
+
 void TargetLoweringObjectFileELF::emitModuleMetadata(MCStreamer &Streamer,
                                                      Module &M) const {
   auto &C = getContext();
@@ -687,9 +695,15 @@ MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
   // 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 MCSectionELF *selectELFSectionForGlobal(
 
 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 @@ MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
   }
   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
index fba86b463764..52083714931a 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
@@ -84,6 +84,7 @@ MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal(
 }
 
 void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) {
+  TargetLoweringObjectFileELF::getModuleMetadata(M);
   SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags;
   M.getModuleFlagsMetadata(ModuleFlags);
 

diff  --git a/llvm/test/CodeGen/PowerPC/func-addr-consts.ll b/llvm/test/CodeGen/PowerPC/func-addr-consts.ll
index fe2bd7f009d5..ff2d6bea9512 100644
--- a/llvm/test/CodeGen/PowerPC/func-addr-consts.ll
+++ b/llvm/test/CodeGen/PowerPC/func-addr-consts.ll
@@ -12,5 +12,5 @@ entry:
   ret void
 }
 
-; CHECK: .section	gsection,"aw", at progbits
-; CHECK: .section	hsection,"aw", at progbits
+; CHECK: .section	gsection,"awR", at progbits
+; CHECK: .section	hsection,"awR", at progbits

diff  --git a/llvm/test/CodeGen/PowerPC/no-dead-strip.ll b/llvm/test/CodeGen/PowerPC/no-dead-strip.ll
index ddd955e7db53..86e9be540efe 100644
--- 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", at nobits
+; CHECK: .section  .bss.X,"awR", at 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
index 000000000000..95d0414f36ed
--- /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
+
+ at 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", at progbits{{$}}
+; OLDGAS-NOT: .section .text
+; NOUNIQUE: .section .text,"axR", at progbits,unique,1
+define dso_local void @fa() {
+entry:
+  ret void
+}
+
+; CHECK:    .section .text.fb,"axR", at progbits{{$}}
+; NOUNIQUE: .section .text,"axR", at progbits,unique,2
+define internal void @fb() {
+entry:
+  ret void
+}
+
+;; Explicit section.
+; CHECK:    .section ccc,"axR", at progbits,unique,1
+; OLDGAS:   .section ccc,"ax", at progbits,unique,1
+; NOUNIQUE: .section ccc,"axR", at progbits,unique,3
+define dso_local void @fc() section "ccc" {
+entry:
+  ret void
+}
+
+; CHECK:    .section .bss.ga,"awR", at nobits{{$}}
+; OLDGAS:   .bss{{$}}
+; NOUNIQUE: .section .bss,"awR", at nobits,unique,4
+ at ga = global i32 0
+
+; CHECK:    .section .data.gb,"awR", at progbits{{$}}
+; OLDGAS:   .data{{$}}
+; NOUNIQUE: .section .data,"awR", at progbits,unique,5
+ at gb = internal global i32 2
+
+; CHECK:    .section .rodata.gc,"aR", at progbits{{$}}
+; OLDGAS:   .section .rodata,"a", at progbits{{$}}
+; NOUNIQUE: .section .rodata,"aR", at progbits,unique,6
+ at gc = constant i32 3
+
+;; Explicit section.
+; CHECK:    .section ddd,"awR", at progbits,unique,2
+; OLDGAS:   .section ddd,"aw", at progbits,unique,2
+; NOUNIQUE: .section ddd,"awR", at progbits,unique,7
+ at gd = global i32 1, section "ddd"
+
+;; Used together with !associated.
+; CHECK:    .section .data.ge,"awoR", at progbits,gc
+; OLDGAS:   .section .data.ge,"awo", at progbits,gc
+; NOUNIQUE: .section .data,"awoR", at progbits,gc,unique,8
+ at ge = global i32 1, !associated !0
+
+;; Aliases in llvm.used are ignored.
+; CHECK:    .section fff,"aw", at progbits{{$}}
+; OLDGAS:   .section fff,"aw", at progbits{{$}}
+; NOUNIQUE: .section fff,"aw", at progbits{{$}}
+ at gf = global i32 1, section "fff"
+
+ at aa = alias i32, i32* @gf
+ at ab = internal alias i32, i32* @gf
+
+!0 = !{i32* @gc}


        


More information about the llvm-commits mailing list