mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-11-05 20:30:18 +00:00
lld relies on a memset that GCC 16 is allowed to optimize away, leaving some symbol fields uninitialized. With lld 21, this makes `ld -r` emit broken section symbols, which breaks LTO kernel module builds (see ClangBuiltLinux/linux#2162). 18 through 20 should have the same bug, but I haven't seen it break there myself. This backports llvm/llvm-project@4d5dffb594 and llvm/llvm-project@070e505ce2, which landed in 22.1.8.
102 lines
3.9 KiB
Diff
102 lines
3.9 KiB
Diff
From 4d5dffb59420df29cc3b419a7fc90834aed7f7a9 Mon Sep 17 00:00:00 2001
|
|
From: Fangrui Song <i@maskray.me>
|
|
Date: Sat, 16 May 2026 21:38:18 +0000
|
|
Subject: [PATCH] [ELF] Initialize Symbol fields in the constructor instead of
|
|
via memset (#198129)
|
|
|
|
`initSectionsAndLocalSyms` and `makeDefined` memset the storage to zero
|
|
and then placement-new a Symbol-derived object into it. Placement new
|
|
begins a new object's lifetime. The standard does not seem to guarantee
|
|
the memset bytes carry into members the constructor leaves
|
|
uninitialized.
|
|
|
|
lld built by GCC 16 can make Valgrind report reads of Symbol::flags
|
|
(via getSymSectionIndex during finalizeSections) as uses of
|
|
uninitialized values (ClangBuiltLinux/linux#2162).
|
|
|
|
This patch reinstates the per-field initialization that commit
|
|
778742760534 ("[ELF] Avoid redundant assignment to Symbol fields. NFC")
|
|
had replaced with a bulk memset.
|
|
|
|
(cherry picked from commit 905a88b923433eb8cd83677ea55bee82eb9ba498)
|
|
|
|
Squashed with 070e505ce21d ("[LLD][ELF] Add missing initialization of
|
|
Symbol `used` member.") and rebased onto 20.1.8.
|
|
---
|
|
--- a/ELF/InputFiles.cpp
|
|
+++ b/ELF/InputFiles.cpp
|
|
@@ -1175,7 +1175,6 @@
|
|
if (!firstGlobal)
|
|
return;
|
|
SymbolUnion *locals = makeThreadLocalN<SymbolUnion>(firstGlobal);
|
|
- memset(locals, 0, sizeof(SymbolUnion) * firstGlobal);
|
|
|
|
ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>();
|
|
for (size_t i = 0, end = firstGlobal; i != end; ++i) {
|
|
@@ -1211,7 +1210,6 @@
|
|
else
|
|
new (symbols[i]) Defined(ctx, this, name, STB_LOCAL, eSym.st_other, type,
|
|
eSym.st_value, eSym.st_size, sec);
|
|
- symbols[i]->partition = 1;
|
|
symbols[i]->isUsedInRegularObj = true;
|
|
}
|
|
}
|
|
--- a/ELF/Symbols.h
|
|
+++ b/ELF/Symbols.h
|
|
@@ -102,7 +102,7 @@
|
|
uint8_t symbolKind;
|
|
|
|
// The partition whose dynamic symbol table contains this symbol's definition.
|
|
- uint8_t partition;
|
|
+ uint8_t partition = 1;
|
|
|
|
// True if this symbol is preemptible at load time.
|
|
//
|
|
@@ -242,8 +242,13 @@
|
|
Symbol(Kind k, InputFile *file, StringRef name, uint8_t binding,
|
|
uint8_t stOther, uint8_t type)
|
|
: file(file), nameData(name.data()), nameSize(name.size()), type(type),
|
|
- binding(binding), stOther(stOther), symbolKind(k), ltoCanOmit(false),
|
|
- archSpecificBit(false) {}
|
|
+ binding(binding), stOther(stOther), symbolKind(k), isPreemptible(false),
|
|
+ isUsedInRegularObj(false), used(false), isExported(false),
|
|
+ ltoCanOmit(false), traced(false), hasVersionSuffix(false),
|
|
+ isInIplt(false), gotInIgot(false), folded(false),
|
|
+ archSpecificBit(false), scriptDefined(false), dsoDefined(false),
|
|
+ dsoProtected(false), versionScriptAssigned(false), thunkAccessed(false),
|
|
+ inDynamicList(false), referenced(false), referencedAfterWrap(false) {}
|
|
|
|
void overwrite(Symbol &sym, Kind k) const {
|
|
if (sym.traced)
|
|
@@ -302,18 +307,18 @@
|
|
|
|
// Temporary flags used to communicate which symbol entries need PLT and GOT
|
|
// entries during postScanRelocations();
|
|
- std::atomic<uint16_t> flags;
|
|
+ std::atomic<uint16_t> flags = 0;
|
|
|
|
// A ctx.symAux index used to access GOT/PLT entry indexes. This is allocated
|
|
// in postScanRelocations().
|
|
- uint32_t auxIdx;
|
|
- uint32_t dynsymIndex;
|
|
+ uint32_t auxIdx = 0;
|
|
+ uint32_t dynsymIndex = 0;
|
|
|
|
// If `file` is SharedFile (for SharedSymbol or copy-relocated Defined), this
|
|
// represents the Verdef index within the input DSO, which will be converted
|
|
// to a Verneed index in the output. Otherwise, this represents the Verdef
|
|
// index (VER_NDX_LOCAL, VER_NDX_GLOBAL, or a named version).
|
|
- uint16_t versionId;
|
|
+ uint16_t versionId = 0;
|
|
LLVM_PREFERRED_TYPE(bool)
|
|
uint8_t versionScriptAssigned : 1;
|
|
|
|
@@ -524,7 +529,6 @@
|
|
|
|
template <typename... T> Defined *makeDefined(T &&...args) {
|
|
auto *sym = getSpecificAllocSingleton<SymbolUnion>().Allocate();
|
|
- memset(sym, 0, sizeof(Symbol));
|
|
auto &s = *new (reinterpret_cast<Defined *>(sym)) Defined(std::forward<T>(args)...);
|
|
return &s;
|
|
}
|