Skip to content

Commit a26bd95

Browse files
committed
[LinkerWrapper] Fix static library symbol resolution
The linker wrapper performs its own very basic symbol resolution for the purpose of supporting standard static library semantics. We do this here because the Nvidia `nvlink` wrapper does not support static linking and we have some offloading specific extensions. Currently, we always place symbols in the "table" even if they aren't extracted. This caused the logic to fail when many files were used that referenced the same undefined variable. This patch changes the pass to only add the symbols to the global "table" if the file is actually extracted. Reviewed By: tra Differential Revision: https://reviews.llvm.org/D151839
1 parent 8e58fdd commit a26bd95

File tree

2 files changed

+44
-19
lines changed

2 files changed

+44
-19
lines changed

clang/test/Driver/linker-wrapper-libs.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ int __attribute__((visibility("protected"))) global;
1212
int __attribute__((visibility("hidden"))) weak;
1313
#elif defined(HIDDEN)
1414
int __attribute__((visibility("hidden"))) hidden;
15+
#elif defined(UNDEFINED)
16+
extern int sym;
17+
int baz() { return sym; }
1518
#else
1619
extern int sym;
1720

@@ -26,7 +29,11 @@ int bar() { return weak; }
2629
//
2730
// RUN: %clang -cc1 %s -triple nvptx64-nvidia-cuda -emit-llvm-bc -DRESOLVES -o %t.nvptx.resolves.bc
2831
// RUN: %clang -cc1 %s -triple amdgcn-amd-amdhsa -emit-llvm-bc -DRESOLVES -o %t.amdgpu.resolves.bc
32+
// RUN: %clang -cc1 %s -triple nvptx64-nvidia-cuda -emit-llvm-bc -DUNDEFINED -o %t.nvptx.undefined.bc
33+
// RUN: %clang -cc1 %s -triple amdgcn-amd-amdhsa -emit-llvm-bc -DUNDEFINED -o %t.amdgpu.undefined.bc
2934
// RUN: clang-offload-packager -o %t-lib.out \
35+
// RUN: --image=file=%t.nvptx.undefined.bc,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 \
36+
// RUN: --image=file=%t.amdgpu.undefined.bc,kind=openmp,triple=amdgcn-amd-amdhsa,arch=gfx1030 \
3037
// RUN: --image=file=%t.nvptx.resolves.bc,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70 \
3138
// RUN: --image=file=%t.amdgpu.resolves.bc,kind=openmp,triple=amdgcn-amd-amdhsa,arch=gfx1030
3239
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t-lib.out

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,20 +1163,21 @@ enum Symbol : uint32_t {
11631163
/// Scan the symbols from a BitcodeFile \p Buffer and record if we need to
11641164
/// extract any symbols from it.
11651165
Expected<bool> getSymbolsFromBitcode(MemoryBufferRef Buffer, OffloadKind Kind,
1166-
StringSaver &Saver,
1166+
bool IsArchive, StringSaver &Saver,
11671167
DenseMap<StringRef, Symbol> &Syms) {
11681168
Expected<IRSymtabFile> IRSymtabOrErr = readIRSymtab(Buffer);
11691169
if (!IRSymtabOrErr)
11701170
return IRSymtabOrErr.takeError();
11711171

1172-
bool ShouldExtract = false;
1172+
bool ShouldExtract = !IsArchive;
1173+
DenseMap<StringRef, Symbol> TmpSyms;
11731174
for (unsigned I = 0; I != IRSymtabOrErr->Mods.size(); ++I) {
11741175
for (const auto &Sym : IRSymtabOrErr->TheReader.module_symbols(I)) {
11751176
if (Sym.isFormatSpecific() || !Sym.isGlobal())
11761177
continue;
11771178

11781179
bool NewSymbol = Syms.count(Sym.getName()) == 0;
1179-
auto &OldSym = Syms[Saver.save(Sym.getName())];
1180+
auto OldSym = NewSymbol ? Sym_None : Syms[Sym.getName()];
11801181

11811182
// We will extract if it defines a currenlty undefined non-weak symbol.
11821183
bool ResolvesStrongReference =
@@ -1192,23 +1193,31 @@ Expected<bool> getSymbolsFromBitcode(MemoryBufferRef Buffer, OffloadKind Kind,
11921193

11931194
// Update this symbol in the "table" with the new information.
11941195
if (OldSym & Sym_Undefined && !Sym.isUndefined())
1195-
OldSym = static_cast<Symbol>(OldSym & ~Sym_Undefined);
1196+
TmpSyms[Saver.save(Sym.getName())] =
1197+
static_cast<Symbol>(OldSym & ~Sym_Undefined);
11961198
if (Sym.isUndefined() && NewSymbol)
1197-
OldSym = static_cast<Symbol>(OldSym | Sym_Undefined);
1199+
TmpSyms[Saver.save(Sym.getName())] =
1200+
static_cast<Symbol>(OldSym | Sym_Undefined);
11981201
if (Sym.isWeak())
1199-
OldSym = static_cast<Symbol>(OldSym | Sym_Weak);
1202+
TmpSyms[Saver.save(Sym.getName())] =
1203+
static_cast<Symbol>(OldSym | Sym_Weak);
12001204
}
12011205
}
12021206

1207+
// If the file gets extracted we update the table with the new symbols.
1208+
if (ShouldExtract)
1209+
Syms.insert(std::begin(TmpSyms), std::end(TmpSyms));
1210+
12031211
return ShouldExtract;
12041212
}
12051213

12061214
/// Scan the symbols from an ObjectFile \p Obj and record if we need to extract
12071215
/// any symbols from it.
12081216
Expected<bool> getSymbolsFromObject(const ObjectFile &Obj, OffloadKind Kind,
1209-
StringSaver &Saver,
1217+
bool IsArchive, StringSaver &Saver,
12101218
DenseMap<StringRef, Symbol> &Syms) {
1211-
bool ShouldExtract = false;
1219+
bool ShouldExtract = !IsArchive;
1220+
DenseMap<StringRef, Symbol> TmpSyms;
12121221
for (SymbolRef Sym : Obj.symbols()) {
12131222
auto FlagsOrErr = Sym.getFlags();
12141223
if (!FlagsOrErr)
@@ -1223,7 +1232,7 @@ Expected<bool> getSymbolsFromObject(const ObjectFile &Obj, OffloadKind Kind,
12231232
return NameOrErr.takeError();
12241233

12251234
bool NewSymbol = Syms.count(*NameOrErr) == 0;
1226-
auto &OldSym = Syms[Saver.save(*NameOrErr)];
1235+
auto OldSym = NewSymbol ? Sym_None : Syms[*NameOrErr];
12271236

12281237
// We will extract if it defines a currenlty undefined non-weak symbol.
12291238
bool ResolvesStrongReference = (OldSym & Sym_Undefined) &&
@@ -1240,12 +1249,19 @@ Expected<bool> getSymbolsFromObject(const ObjectFile &Obj, OffloadKind Kind,
12401249

12411250
// Update this symbol in the "table" with the new information.
12421251
if (OldSym & Sym_Undefined && !(*FlagsOrErr & SymbolRef::SF_Undefined))
1243-
OldSym = static_cast<Symbol>(OldSym & ~Sym_Undefined);
1252+
TmpSyms[Saver.save(*NameOrErr)] =
1253+
static_cast<Symbol>(OldSym & ~Sym_Undefined);
12441254
if (*FlagsOrErr & SymbolRef::SF_Undefined && NewSymbol)
1245-
OldSym = static_cast<Symbol>(OldSym | Sym_Undefined);
1255+
TmpSyms[Saver.save(*NameOrErr)] =
1256+
static_cast<Symbol>(OldSym | Sym_Undefined);
12461257
if (*FlagsOrErr & SymbolRef::SF_Weak)
1247-
OldSym = static_cast<Symbol>(OldSym | Sym_Weak);
1258+
TmpSyms[Saver.save(*NameOrErr)] = static_cast<Symbol>(OldSym | Sym_Weak);
12481259
}
1260+
1261+
// If the file gets extracted we update the table with the new symbols.
1262+
if (ShouldExtract)
1263+
Syms.insert(std::begin(TmpSyms), std::end(TmpSyms));
1264+
12491265
return ShouldExtract;
12501266
}
12511267

@@ -1255,18 +1271,19 @@ Expected<bool> getSymbolsFromObject(const ObjectFile &Obj, OffloadKind Kind,
12551271
/// 1) It defines an undefined symbol in a regular object filie.
12561272
/// 2) It defines a global symbol without hidden visibility that has not
12571273
/// yet been defined.
1258-
Expected<bool> getSymbols(StringRef Image, OffloadKind Kind, StringSaver &Saver,
1274+
Expected<bool> getSymbols(StringRef Image, OffloadKind Kind, bool IsArchive,
1275+
StringSaver &Saver,
12591276
DenseMap<StringRef, Symbol> &Syms) {
12601277
MemoryBufferRef Buffer = MemoryBufferRef(Image, "");
12611278
switch (identify_magic(Image)) {
12621279
case file_magic::bitcode:
1263-
return getSymbolsFromBitcode(Buffer, Kind, Saver, Syms);
1280+
return getSymbolsFromBitcode(Buffer, Kind, IsArchive, Saver, Syms);
12641281
case file_magic::elf_relocatable: {
12651282
Expected<std::unique_ptr<ObjectFile>> ObjFile =
12661283
ObjectFile::createObjectFile(Buffer);
12671284
if (!ObjFile)
12681285
return ObjFile.takeError();
1269-
return getSymbolsFromObject(**ObjFile, Kind, Saver, Syms);
1286+
return getSymbolsFromObject(**ObjFile, Kind, IsArchive, Saver, Syms);
12701287
}
12711288
default:
12721289
return false;
@@ -1341,13 +1358,14 @@ Expected<SmallVector<OffloadFile>> getDeviceInput(const ArgList &Args) {
13411358
if (IsArchive && !WholeArchive && !Syms.count(Binary))
13421359
continue;
13431360

1344-
Expected<bool> ExtractOrErr = getSymbols(
1345-
Binary.getBinary()->getImage(),
1346-
Binary.getBinary()->getOffloadKind(), Saver, Syms[Binary]);
1361+
Expected<bool> ExtractOrErr =
1362+
getSymbols(Binary.getBinary()->getImage(),
1363+
Binary.getBinary()->getOffloadKind(), IsArchive, Saver,
1364+
Syms[Binary]);
13471365
if (!ExtractOrErr)
13481366
return ExtractOrErr.takeError();
13491367

1350-
Extracted = IsArchive && !WholeArchive && *ExtractOrErr;
1368+
Extracted = !WholeArchive && *ExtractOrErr;
13511369

13521370
if (!IsArchive || WholeArchive || Extracted)
13531371
InputFiles.emplace_back(std::move(Binary));

0 commit comments

Comments
 (0)