[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