Skip to content

Commit 47c5576

Browse files
committed
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
1 parent 8afdacb commit 47c5576

File tree

6 files changed

+110
-11
lines changed

6 files changed

+110
-11
lines changed

llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H
1515
#define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H
1616

17+
#include "llvm/ADT/SmallPtrSet.h"
1718
#include "llvm/BinaryFormat/XCOFF.h"
1819
#include "llvm/Target/TargetLoweringObjectFile.h"
1920

@@ -32,6 +33,7 @@ class TargetMachine;
3233
class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
3334
bool UseInitArray = false;
3435
mutable unsigned NextUniqueID = 1; // ID 0 is reserved for execute-only sections
36+
SmallPtrSet<GlobalObject *, 2> Used;
3537

3638
protected:
3739
MCSymbolRefExpr::VariantKind PLTRelativeVariantKind =
@@ -43,6 +45,8 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
4345

4446
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
4547

48+
void getModuleMetadata(Module &M) override;
49+
4650
/// Emit Obj-C garbage collection and linker options.
4751
void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override;
4852

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,14 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx,
293293
}
294294
}
295295

296+
void TargetLoweringObjectFileELF::getModuleMetadata(Module &M) {
297+
SmallVector<GlobalValue *, 4> Vec;
298+
collectUsedGlobalVariables(M, Vec, false);
299+
for (GlobalValue *GV : Vec)
300+
if (auto *GO = dyn_cast<GlobalObject>(GV))
301+
Used.insert(GO);
302+
}
303+
296304
void TargetLoweringObjectFileELF::emitModuleMetadata(MCStreamer &Streamer,
297305
Module &M) const {
298306
auto &C = getContext();
@@ -687,9 +695,15 @@ MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
687695
// MD_associated in a unique section.
688696
unsigned UniqueID = MCContext::GenericSectionID;
689697
const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM);
690-
if (GO->getMetadata(LLVMContext::MD_associated)) {
698+
const bool Associated = GO->getMetadata(LLVMContext::MD_associated);
699+
const bool Retain = Used.count(GO);
700+
if (Associated || Retain) {
691701
UniqueID = NextUniqueID++;
692-
Flags |= ELF::SHF_LINK_ORDER;
702+
if (Associated)
703+
Flags |= ELF::SHF_LINK_ORDER;
704+
if (Retain && (getContext().getAsmInfo()->useIntegratedAssembler() ||
705+
getContext().getAsmInfo()->binutilsIsAtLeast(2, 36)))
706+
Flags |= ELF::SHF_GNU_RETAIN;
693707
} else {
694708
if (getContext().getAsmInfo()->useIntegratedAssembler() ||
695709
getContext().getAsmInfo()->binutilsIsAtLeast(2, 35)) {
@@ -802,13 +816,18 @@ static MCSectionELF *selectELFSectionForGlobal(
802816

803817
static MCSection *selectELFSectionForGlobal(
804818
MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang,
805-
const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags,
806-
unsigned *NextUniqueID) {
819+
const TargetMachine &TM, bool Retain, bool EmitUniqueSection,
820+
unsigned Flags, unsigned *NextUniqueID) {
807821
const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM);
808822
if (LinkedToSym) {
809823
EmitUniqueSection = true;
810824
Flags |= ELF::SHF_LINK_ORDER;
811825
}
826+
if (Retain && (Ctx.getAsmInfo()->useIntegratedAssembler() ||
827+
Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36))) {
828+
EmitUniqueSection = true;
829+
Flags |= ELF::SHF_GNU_RETAIN;
830+
}
812831

813832
MCSectionELF *Section = selectELFSectionForGlobal(
814833
Ctx, GO, Kind, Mang, TM, EmitUniqueSection, Flags,
@@ -832,16 +851,17 @@ MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
832851
}
833852
EmitUniqueSection |= GO->hasComdat();
834853
return selectELFSectionForGlobal(getContext(), GO, Kind, getMangler(), TM,
835-
EmitUniqueSection, Flags, &NextUniqueID);
854+
Used.count(GO), EmitUniqueSection, Flags,
855+
&NextUniqueID);
836856
}
837857

838858
MCSection *TargetLoweringObjectFileELF::getUniqueSectionForFunction(
839859
const Function &F, const TargetMachine &TM) const {
840860
SectionKind Kind = SectionKind::getText();
841861
unsigned Flags = getELFSectionFlags(Kind);
842-
return selectELFSectionForGlobal(getContext(), &F, Kind, getMangler(), TM,
843-
/* EmitUniqueSection = */ true, Flags,
844-
&NextUniqueID);
862+
return selectELFSectionForGlobal(
863+
getContext(), &F, Kind, getMangler(), TM, Used.count(&F),
864+
/*EmitUniqueSection=*/true, Flags, &NextUniqueID);
845865
}
846866

847867
MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable(

llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal(
8484
}
8585

8686
void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) {
87+
TargetLoweringObjectFileELF::getModuleMetadata(M);
8788
SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags;
8889
M.getModuleFlagsMetadata(ModuleFlags);
8990

llvm/test/CodeGen/PowerPC/func-addr-consts.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ entry:
1212
ret void
1313
}
1414

15-
; CHECK: .section gsection,"aw",@progbits
16-
; CHECK: .section hsection,"aw",@progbits
15+
; CHECK: .section gsection,"awR",@progbits
16+
; CHECK: .section hsection,"awR",@progbits

llvm/test/CodeGen/PowerPC/no-dead-strip.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-linux-gnu < %s | FileCheck %s
22

3-
; CHECK: .section .bss,"aw",@nobits
3+
; CHECK: .section .bss.X,"awR",@nobits
44
; CHECK: .weak X
55
; CHECK-LABEL: X:
66
; CHECK: .long 0

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
;; Place a global object in the llvm.used list in a unique section with the SHF_GNU_RETAIN flag.
2+
; RUN: llc -mtriple=x86_64 < %s | FileCheck %s
3+
; RUN: llc -mtriple=x86_64 -data-sections=1 < %s | FileCheck %s
4+
; RUN: llc -mtriple=x86_64 -no-integrated-as -binutils-version=2.36 < %s | FileCheck %s
5+
; RUN: llc -mtriple=x86_64 -no-integrated-as -binutils-version=2.35 < %s | FileCheck %s --check-prefix=OLDGAS
6+
7+
; RUN: llc -mtriple=x86_64 -data-sections=1 -unique-section-names=0 < %s | FileCheck %s --check-prefix=NOUNIQUE
8+
9+
@llvm.used = appending global [10 x i8*] [
10+
i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @fb to i8*), i8* bitcast (void ()* @fc to i8*),
11+
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*),
12+
i8* bitcast (i32* @aa to i8*), i8* bitcast (i32* @ab to i8*) ], section "llvm.metadata"
13+
14+
; CHECK: .section .text.fa,"axR",@progbits{{$}}
15+
; OLDGAS-NOT: .section .text
16+
; NOUNIQUE: .section .text,"axR",@progbits,unique,1
17+
define dso_local void @fa() {
18+
entry:
19+
ret void
20+
}
21+
22+
; CHECK: .section .text.fb,"axR",@progbits{{$}}
23+
; NOUNIQUE: .section .text,"axR",@progbits,unique,2
24+
define internal void @fb() {
25+
entry:
26+
ret void
27+
}
28+
29+
;; Explicit section.
30+
; CHECK: .section ccc,"axR",@progbits,unique,1
31+
; OLDGAS: .section ccc,"ax",@progbits,unique,1
32+
; NOUNIQUE: .section ccc,"axR",@progbits,unique,3
33+
define dso_local void @fc() section "ccc" {
34+
entry:
35+
ret void
36+
}
37+
38+
; CHECK: .section .bss.ga,"awR",@nobits{{$}}
39+
; OLDGAS: .bss{{$}}
40+
; NOUNIQUE: .section .bss,"awR",@nobits,unique,4
41+
@ga = global i32 0
42+
43+
; CHECK: .section .data.gb,"awR",@progbits{{$}}
44+
; OLDGAS: .data{{$}}
45+
; NOUNIQUE: .section .data,"awR",@progbits,unique,5
46+
@gb = internal global i32 2
47+
48+
; CHECK: .section .rodata.gc,"aR",@progbits{{$}}
49+
; OLDGAS: .section .rodata,"a",@progbits{{$}}
50+
; NOUNIQUE: .section .rodata,"aR",@progbits,unique,6
51+
@gc = constant i32 3
52+
53+
;; Explicit section.
54+
; CHECK: .section ddd,"awR",@progbits,unique,2
55+
; OLDGAS: .section ddd,"aw",@progbits,unique,2
56+
; NOUNIQUE: .section ddd,"awR",@progbits,unique,7
57+
@gd = global i32 1, section "ddd"
58+
59+
;; Used together with !associated.
60+
; CHECK: .section .data.ge,"awoR",@progbits,gc
61+
; OLDGAS: .section .data.ge,"awo",@progbits,gc
62+
; NOUNIQUE: .section .data,"awoR",@progbits,gc,unique,8
63+
@ge = global i32 1, !associated !0
64+
65+
;; Aliases in llvm.used are ignored.
66+
; CHECK: .section fff,"aw",@progbits{{$}}
67+
; OLDGAS: .section fff,"aw",@progbits{{$}}
68+
; NOUNIQUE: .section fff,"aw",@progbits{{$}}
69+
@gf = global i32 1, section "fff"
70+
71+
@aa = alias i32, i32* @gf
72+
@ab = internal alias i32, i32* @gf
73+
74+
!0 = !{i32* @gc}

0 commit comments

Comments
 (0)