Skip to content

Commit d39a9e3

Browse files
committed
[Driver] Support GNU ld on Solaris
This patch supports GNU ld on Solaris in addition to Solaris ld, the default. - Linker selection is dynamic: one can switch between Solaris ld and GNU ld at runtime, with the default selectable with `-DCLANG_DEFAULT_LINKER`. - Testcases have been adjusted to test both variants in case there are differences. - The `compiler-rt/cmake/config-ix.cmake` and `llvm/cmake/modules/AddLLVM.cmake` changes to restrict the tests to Solaris ld are necessary because GNU accepts unknown `-z` options, but warns every time they are used, creating a lot of noise. Since there seems to be no way to check for those warnings in `llvm_check_compiler_linker_flag` or `llvm_check_compiler_linker_flag`, I restrict the cmake tests to Solaris ld in the first place. - The changes to `clang/test/Driver/hip-link-bundle-archive.hip` and `flang/test/Driver/linker-flags.f90` are required when LLVM is built with `-DCLANG_DEFAULT_LINKER=gld` on Solaris: `MSVC.cpp` `visualstudio::Linker::ConstructJob` ultimately calls `GetProgramPath("gld")`, resulting in a search for `gld`, which exists in `/usr/bin/gld` on Solaris. With `-fuse-ld=`, this doesn't happen and the expected `link` is returned. - `compiler-rt/test/asan/TestCases/global-location-nodebug.cpp` needs to enforce the Solaris ld, otherwise the test would `XPASS` with GNU ld which has the `-S` semantics expected by the test. Tested on `amd64-pc-solaris2.11` and `sparcv9-sun-solaris2.11` with both `-DCLANG_DEFAULT_LINKER=gld` and the default, and `x86_64-pc-linux-gnu`. No regressions in either case. Differential Revision: https://reviews.llvm.org/D85309
1 parent f9f2fdc commit d39a9e3

File tree

10 files changed

+191
-69
lines changed

10 files changed

+191
-69
lines changed

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "HIPAMD.h"
2323
#include "Hexagon.h"
2424
#include "MSP430.h"
25+
#include "Solaris.h"
2526
#include "clang/Basic/CharInfo.h"
2627
#include "clang/Basic/LangOptions.h"
2728
#include "clang/Basic/ObjCRuntime.h"
@@ -993,9 +994,11 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
993994
static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args,
994995
ArgStringList &CmdArgs,
995996
StringRef Sanitizer) {
997+
bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args);
998+
996999
// Solaris ld defaults to --export-dynamic behaviour but doesn't support
9971000
// the option, so don't try to pass it.
998-
if (TC.getTriple().getOS() == llvm::Triple::Solaris)
1001+
if (TC.getTriple().getOS() == llvm::Triple::Solaris && !LinkerIsGnuLd)
9991002
return true;
10001003
SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer));
10011004
if (llvm::sys::fs::exists(SanRT + ".syms")) {
@@ -1011,11 +1014,14 @@ void tools::addAsNeededOption(const ToolChain &TC,
10111014
bool as_needed) {
10121015
assert(!TC.getTriple().isOSAIX() &&
10131016
"AIX linker does not support any form of --as-needed option yet.");
1017+
bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args);
10141018

10151019
// While the Solaris 11.2 ld added --as-needed/--no-as-needed as aliases
10161020
// for the native forms -z ignore/-z record, they are missing in Illumos,
10171021
// so always use the native form.
1018-
if (TC.getTriple().isOSSolaris()) {
1022+
// GNU ld doesn't support -z ignore/-z record, so don't use them even on
1023+
// Solaris.
1024+
if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd) {
10191025
CmdArgs.push_back("-z");
10201026
CmdArgs.push_back(as_needed ? "ignore" : "record");
10211027
} else {

clang/lib/Driver/ToolChains/Solaris.cpp

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "clang/Driver/Options.h"
1717
#include "clang/Driver/SanitizerArgs.h"
1818
#include "clang/Driver/ToolChain.h"
19+
#include "llvm/ADT/StringSwitch.h"
1920
#include "llvm/Option/ArgList.h"
2021
#include "llvm/Support/FileSystem.h"
2122
#include "llvm/Support/Path.h"
@@ -47,6 +48,13 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
4748
Exec, CmdArgs, Inputs, Output));
4849
}
4950

51+
bool solaris::isLinkerGnuLd(const ToolChain &TC, const ArgList &Args) {
52+
// Only used if targetting Solaris.
53+
const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ);
54+
StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER;
55+
return UseLinker == "bfd" || UseLinker == "gld";
56+
}
57+
5058
static bool getPIE(const ArgList &Args, const ToolChain &TC) {
5159
if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) ||
5260
Args.hasArg(options::OPT_r))
@@ -59,25 +67,57 @@ static bool getPIE(const ArgList &Args, const ToolChain &TC) {
5967
return A->getOption().matches(options::OPT_pie);
6068
}
6169

70+
// FIXME: Need to handle CLANG_DEFAULT_LINKER here?
71+
std::string solaris::Linker::getLinkerPath(const ArgList &Args) const {
72+
const ToolChain &ToolChain = getToolChain();
73+
if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
74+
StringRef UseLinker = A->getValue();
75+
if (!UseLinker.empty()) {
76+
if (llvm::sys::path::is_absolute(UseLinker) &&
77+
llvm::sys::fs::can_execute(UseLinker))
78+
return std::string(UseLinker);
79+
80+
// Accept 'bfd' and 'gld' as aliases for the GNU linker.
81+
if (UseLinker == "bfd" || UseLinker == "gld")
82+
// FIXME: Could also use /usr/bin/gld here.
83+
return "/usr/gnu/bin/ld";
84+
85+
// Accept 'ld' as alias for the default linker
86+
if (UseLinker != "ld")
87+
ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name)
88+
<< A->getAsString(Args);
89+
}
90+
}
91+
92+
// getDefaultLinker() always returns an absolute path.
93+
return ToolChain.getDefaultLinker();
94+
}
95+
6296
void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
6397
const InputInfo &Output,
6498
const InputInfoList &Inputs,
6599
const ArgList &Args,
66100
const char *LinkingOutput) const {
67101
const bool IsPIE = getPIE(Args, getToolChain());
68102
ArgStringList CmdArgs;
103+
bool LinkerIsGnuLd = isLinkerGnuLd(getToolChain(), Args);
69104

70-
// Demangle C++ names in errors
71-
CmdArgs.push_back("-C");
105+
// Demangle C++ names in errors. GNU ld already defaults to --demangle.
106+
if (!LinkerIsGnuLd)
107+
CmdArgs.push_back("-C");
72108

73109
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
74110
CmdArgs.push_back("-e");
75111
CmdArgs.push_back("_start");
76112
}
77113

78114
if (IsPIE) {
79-
CmdArgs.push_back("-z");
80-
CmdArgs.push_back("type=pie");
115+
if (LinkerIsGnuLd) {
116+
CmdArgs.push_back("-pie");
117+
} else {
118+
CmdArgs.push_back("-z");
119+
CmdArgs.push_back("type=pie");
120+
}
81121
}
82122

83123
if (Args.hasArg(options::OPT_static)) {
@@ -95,6 +135,42 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
95135
Args.ClaimAllArgs(options::OPT_pthreads);
96136
}
97137

138+
if (LinkerIsGnuLd) {
139+
// Set the correct linker emulation for 32- and 64-bit Solaris.
140+
const toolchains::Solaris &ToolChain =
141+
static_cast<const toolchains::Solaris &>(getToolChain());
142+
const llvm::Triple::ArchType Arch = ToolChain.getArch();
143+
144+
switch (Arch) {
145+
case llvm::Triple::x86:
146+
CmdArgs.push_back("-m");
147+
CmdArgs.push_back("elf_i386_sol2");
148+
break;
149+
case llvm::Triple::x86_64:
150+
CmdArgs.push_back("-m");
151+
CmdArgs.push_back("elf_x86_64_sol2");
152+
break;
153+
case llvm::Triple::sparc:
154+
CmdArgs.push_back("-m");
155+
CmdArgs.push_back("elf32_sparc_sol2");
156+
break;
157+
case llvm::Triple::sparcv9:
158+
CmdArgs.push_back("-m");
159+
CmdArgs.push_back("elf64_sparc_sol2");
160+
break;
161+
default:
162+
break;
163+
}
164+
165+
if (Args.hasArg(options::OPT_rdynamic))
166+
CmdArgs.push_back("-export-dynamic");
167+
168+
CmdArgs.push_back("--eh-frame-hdr");
169+
} else {
170+
// -rdynamic is a no-op with Solaris ld. Claim argument to avoid warning.
171+
Args.ClaimAllArgs(options::OPT_rdynamic);
172+
}
173+
98174
if (Output.isFilename()) {
99175
CmdArgs.push_back("-o");
100176
CmdArgs.push_back(Output.getFilename());
@@ -183,7 +259,8 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
183259
// in Illumos.
184260
if (getToolChain().getTriple().getArch() == llvm::Triple::x86_64 &&
185261
(SA.needsAsanRt() || SA.needsStatsRt() ||
186-
(SA.needsUbsanRt() && !SA.requiresMinimalRuntime()))) {
262+
(SA.needsUbsanRt() && !SA.requiresMinimalRuntime())) &&
263+
!LinkerIsGnuLd) {
187264
CmdArgs.push_back("-z");
188265
CmdArgs.push_back("relax=transtls");
189266
}
@@ -210,7 +287,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
210287

211288
getToolChain().addProfileRTLibs(Args, CmdArgs);
212289

213-
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
290+
const char *Exec = Args.MakeArgString(getLinkerPath(Args));
214291
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
215292
Exec, CmdArgs, Inputs, Output));
216293
}
@@ -271,6 +348,13 @@ SanitizerMask Solaris::getSupportedSanitizers() const {
271348
return Res;
272349
}
273350

351+
const char *Solaris::getDefaultLinker() const {
352+
// FIXME: Only handle Solaris ld and GNU ld here.
353+
return llvm::StringSwitch<const char *>(CLANG_DEFAULT_LINKER)
354+
.Cases("bfd", "gld", "/usr/gnu/bin/ld")
355+
.Default("/usr/bin/ld");
356+
}
357+
274358
Tool *Solaris::buildAssembler() const {
275359
return new tools::solaris::Assembler(*this);
276360
}

clang/lib/Driver/ToolChains/Solaris.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,15 @@ class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
3232
const char *LinkingOutput) const override;
3333
};
3434

35+
bool isLinkerGnuLd(const ToolChain &TC, const llvm::opt::ArgList &Args);
36+
3537
class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
3638
public:
3739
Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {}
3840

3941
bool hasIntegratedCPP() const override { return false; }
4042
bool isLinkJob() const override { return true; }
43+
std::string getLinkerPath(const llvm::opt::ArgList &Args) const;
4144

4245
void ConstructJob(Compilation &C, const JobAction &JA,
4346
const InputInfo &Output, const InputInfoList &Inputs,
@@ -64,10 +67,7 @@ class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_ELF {
6467

6568
SanitizerMask getSupportedSanitizers() const override;
6669

67-
const char *getDefaultLinker() const override {
68-
// clang currently uses Solaris ld-only options.
69-
return "/usr/bin/ld";
70-
}
70+
const char *getDefaultLinker() const override;
7171

7272
protected:
7373
Tool *buildAssembler() const override;

clang/test/Driver/hip-link-bundle-archive.hip

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,17 @@
5656

5757
// RUN: llvm-ar cr %t/hipBundled2.lib %t/dummy.bc
5858
// RUN: %clang -### --offload-arch=gfx906 --offload-arch=gfx1030 \
59-
// RUN: --target=x86_64-pc-windows-msvc \
59+
// RUN: --target=x86_64-pc-windows-msvc -fuse-ld= \
6060
// RUN: -nogpuinc -nogpulib %s -fgpu-rdc -L%t -lhipBundled2 \
6161
// RUN: 2>&1 | FileCheck -check-prefix=MSVC %s
6262

6363
// RUN: %clang -### --offload-arch=gfx906 --offload-arch=gfx1030 \
64-
// RUN: --target=x86_64-pc-windows-msvc \
64+
// RUN: --target=x86_64-pc-windows-msvc -fuse-ld= \
6565
// RUN: -nogpuinc -nogpulib %s -fgpu-rdc -L%t -l:hipBundled2.lib \
6666
// RUN: 2>&1 | FileCheck -check-prefix=MSVC %s
6767

6868
// RUN: %clang -### --offload-arch=gfx906 --offload-arch=gfx1030 \
69-
// RUN: --target=x86_64-pc-windows-msvc \
69+
// RUN: --target=x86_64-pc-windows-msvc -fuse-ld= \
7070
// RUN: -nogpuinc -nogpulib %s -fgpu-rdc %t/hipBundled2.lib \
7171
// RUN: 2>&1 | FileCheck -check-prefix=MSVC %s
7272

clang/test/Driver/solaris-ld-sanitizer.c

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,55 @@
33
/// independent of the host system.
44

55
/// Check sparc-sun-solaris2.11, 32bit
6-
// RUN: %clang --target=sparc-sun-solaris2.11 %s -### 2>&1 \
7-
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_sparc_tree \
8-
// RUN: | FileCheck --check-prefix=CHECK-LD-SPARC32 %s
9-
// CHECK-LD-SPARC32-NOT: "-z" "relax=transtls"
6+
// RUN: %clang --target=sparc-sun-solaris2.11 %s -### -fuse-ld= \
7+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_sparc_tree 2>&1 \
8+
// RUN: | FileCheck --check-prefix=CHECK-LD %s
109

1110
/// Check sparc-sun-solaris2.11, 32bit
12-
// RUN: %clang -fsanitize=undefined --target=sparc-sun-solaris2.11 %s -### 2>&1 \
13-
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_sparc_tree \
14-
// RUN: | FileCheck --check-prefix=CHECK-LD-SPARC32 %s
15-
// CHECK-LD-SPARC32-NOT: "-z" "relax=transtls"
11+
// RUN: %clang -fsanitize=undefined --target=sparc-sun-solaris2.11 %s -### -fuse-ld= \
12+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_sparc_tree 2>&1 \
13+
// RUN: | FileCheck --check-prefix=CHECK-LD %s
1614

1715
/// Check sparc-sun-solaris2.11, 64bit
18-
// RUN: %clang -m64 --target=sparc-sun-solaris2.11 %s -### 2>&1 \
19-
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_sparc_tree \
20-
// RUN: | FileCheck --check-prefix=CHECK-LD-SPARC64 %s
21-
// CHECK-LD-SPARC64-NOT: "-z" "relax=transtls"
16+
// RUN: %clang -m64 --target=sparc-sun-solaris2.11 %s -### -fuse-ld= \
17+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_sparc_tree 2>&1 \
18+
// RUN: | FileCheck --check-prefix=CHECK-LD %s
2219

2320
/// Check sparc-sun-solaris2.11, 64bit
24-
// RUN: %clang -m64 -fsanitize=undefined --target=sparc-sun-solaris2.11 %s -### 2>&1 \
25-
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_sparc_tree \
26-
// RUN: | FileCheck --check-prefix=CHECK-LD-SPARC64 %s
27-
// CHECK-LD-SPARC64-NOT: "-z" "relax=transtls"
21+
// RUN: %clang -m64 -fsanitize=undefined --target=sparc-sun-solaris2.11 %s -### -fuse-ld= \
22+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_sparc_tree 2>&1 \
23+
// RUN: | FileCheck --check-prefix=CHECK-LD %s
2824

2925
/// Check i386-pc-solaris2.11, 32bit
30-
// RUN: %clang --target=i386-pc-solaris2.11 %s -### 2>&1 \
31-
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree \
32-
// RUN: | FileCheck --check-prefix=CHECK-LD-X32 %s
33-
// CHECK-LD-X32-NOT: "-z" "relax=transtls"
26+
// RUN: %clang --target=i386-pc-solaris2.11 %s -### -fuse-ld= \
27+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree 2>&1 \
28+
// RUN: | FileCheck --check-prefix=CHECK-LD %s
3429

3530
/// Check i386-pc-solaris2.11, 32bit
36-
// RUN: %clang -fsanitize=undefined --target=i386-pc-solaris2.11 %s -### 2>&1 \
37-
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree \
38-
// RUN: | FileCheck --check-prefix=CHECK-LD-X32 %s
39-
// CHECK-LD-X32-NOT: "-z" "relax=transtls"
31+
// RUN: %clang -fsanitize=undefined --target=i386-pc-solaris2.11 %s -### -fuse-ld= \
32+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree 2>&1 \
33+
// RUN: | FileCheck --check-prefix=CHECK-LD %s
4034

4135
/// Check i386-pc-solaris2.11, 64bit
42-
// RUN: %clang -m64 --target=i386-pc-solaris2.11 %s -### 2>&1 \
43-
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree \
44-
// RUN: | FileCheck --check-prefix=CHECK-LD-X64 %s
45-
// CHECK-LD-X64-NOT: "-z" "relax=transtls"
36+
// RUN: %clang -m64 --target=i386-pc-solaris2.11 %s -### -fuse-ld= \
37+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree 2>&1 \
38+
// RUN: | FileCheck --check-prefix=CHECK-LD %s
39+
40+
// CHECK-LD-NOT: "-z" "relax=transtls"
4641

4742
/// Check i386-pc-solaris2.11, 64bit
48-
// RUN: %clang -m64 -fsanitize=undefined --target=i386-pc-solaris2.11 %s -### 2>&1 \
49-
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree \
43+
// RUN: %clang -m64 -fsanitize=undefined --target=i386-pc-solaris2.11 %s -### -fuse-ld= \
44+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree 2>&1 \
5045
// RUN: | FileCheck --check-prefix=CHECK-LD-X64-UBSAN %s
46+
// RUN: %clang -m64 -fsanitize=undefined --target=i386-pc-solaris2.11 %s -### -fuse-ld=gld \
47+
// RUN: --gcc-toolchain="" --sysroot=%S/Inputs/solaris_x86_tree 2>&1 \
48+
// RUN: | FileCheck --check-prefix=CHECK-GLD-X64-UBSAN %s
49+
5150
// CHECK-LD-X64-UBSAN: "-z" "relax=transtls"
51+
// CHECK-GLD-X64-UBSAN-NOT: "-z" "relax=transtls"
5252

5353
/// General tests that the ld -z now workaround is only applied on
54-
/// Solaris/i386 with shared libclang_rt.asan.. Note that we use sysroot to
54+
/// Solaris/i386 with shared libclang_rt.asan. Note that we use sysroot to
5555
/// make these tests independent of the host system.
5656

5757
/// Check i386-pc-solaris2.11, 32bit, shared libclang_rt.asan

0 commit comments

Comments
 (0)