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
This commit is contained in:
Fangrui Song
2021-02-26 16:38:44 -08:00
parent 17d644a711
commit a2b91c0b40
6 changed files with 110 additions and 11 deletions
+28 -8
View File
@@ -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(