blob: 098277c96ba1d046be14af1d4ce3da2e7c3bdd24 [file] [edit]
//===---- Serenity.cpp - SerenityOS ToolChain Implementation ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Serenity.h"
#include "clang/Config/config.h"
#include "clang/Driver/CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/SanitizerArgs.h"
#include "clang/Options/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <string>
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
void tools::serenity::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
const auto &TC = static_cast<Generic_ELF const &>(getToolChain());
const auto &D = TC.getDriver();
const bool IsShared = Args.hasArg(options::OPT_shared);
const bool IsStatic =
Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_static_pie);
const bool IsStaticPIE = Args.hasArg(options::OPT_static_pie);
ArgStringList CmdArgs;
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
if (IsShared)
CmdArgs.push_back("-shared");
if (IsStaticPIE) {
CmdArgs.push_back("-static");
CmdArgs.push_back("-pie");
CmdArgs.push_back("--no-dynamic-linker");
CmdArgs.push_back("-z");
CmdArgs.push_back("text");
} else if (IsStatic) {
CmdArgs.push_back("-static");
} else if (!Args.hasArg(options::OPT_r)) {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
if (!IsShared) {
Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie);
bool IsPIE =
A ? A->getOption().matches(options::OPT_pie) : TC.isPIEDefault(Args);
if (IsPIE)
CmdArgs.push_back("-pie");
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back(Args.MakeArgString(TC.getDynamicLinker(Args)));
}
}
CmdArgs.push_back("--eh-frame-hdr");
assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
}
CmdArgs.push_back("-z");
CmdArgs.push_back("pack-relative-relocs");
bool HasNoStdLib = Args.hasArg(options::OPT_nostdlib, options::OPT_r);
bool HasNoStdLibXX = Args.hasArg(options::OPT_nostdlibxx);
bool HasNoLibC = Args.hasArg(options::OPT_nolibc);
bool HasNoStartFiles = Args.hasArg(options::OPT_nostartfiles);
bool HasNoDefaultLibs = Args.hasArg(options::OPT_nodefaultlibs);
bool ShouldLinkStartFiles = !HasNoStartFiles && !HasNoStdLib;
bool ShouldLinkCompilerRuntime = !HasNoDefaultLibs && !HasNoStdLib;
bool ShouldLinkLibC = !HasNoLibC && !HasNoStdLib && !HasNoDefaultLibs;
bool ShouldLinkLibCXX =
D.CCCIsCXX() && !HasNoStdLibXX && !HasNoStdLib && !HasNoDefaultLibs;
if (ShouldLinkStartFiles) {
if (!IsShared)
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt0.o")));
std::string crtbegin_path;
if (TC.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
std::string crtbegin =
TC.getCompilerRT(Args, "crtbegin", ToolChain::FT_Object);
if (TC.getVFS().exists(crtbegin))
crtbegin_path = crtbegin;
}
if (crtbegin_path.empty())
crtbegin_path = TC.GetFilePath("crtbeginS.o");
CmdArgs.push_back(Args.MakeArgString(crtbegin_path));
}
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
TC.AddFilePathLibArgs(Args, CmdArgs);
if (auto LTO = TC.getLTOMode(Args); LTO != LTOK_None)
addLTOOptions(TC, Args, CmdArgs, Output, Inputs, LTO == LTOK_Thin);
Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
options::OPT_t, options::OPT_r});
addLinkerCompressDebugSectionsOption(TC, Args, CmdArgs);
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
if (ShouldLinkCompilerRuntime) {
AddRunTimeLibs(TC, D, CmdArgs, Args);
// We supply our own sanitizer runtimes that output errors to the
// Kernel debug log as well as stderr.
// FIXME: Properly port clang/gcc sanitizers and use those instead.
const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args);
if (Sanitize.needsUbsanRt())
CmdArgs.push_back("-lubsan");
}
if (ShouldLinkLibCXX) {
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
!Args.hasArg(options::OPT_static);
CmdArgs.push_back("--push-state");
CmdArgs.push_back("--as-needed");
if (OnlyLibstdcxxStatic)
CmdArgs.push_back("-Bstatic");
TC.AddCXXStdlibLibArgs(Args, CmdArgs);
if (OnlyLibstdcxxStatic)
CmdArgs.push_back("-Bdynamic");
CmdArgs.push_back("--pop-state");
}
// Silence warnings when linking C code with a C++ '-stdlib' argument.
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
if (ShouldLinkLibC)
CmdArgs.push_back("-lc");
if (ShouldLinkStartFiles) {
std::string crtend_path;
if (TC.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
std::string crtend =
TC.getCompilerRT(Args, "crtend", ToolChain::FT_Object);
if (TC.getVFS().exists(crtend))
crtend_path = crtend;
}
if (crtend_path.empty())
crtend_path = TC.GetFilePath("crtendS.o");
CmdArgs.push_back(Args.MakeArgString(crtend_path));
}
const char *Exec = Args.MakeArgString(TC.GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
}
SanitizerMask
Serenity::getSupportedSanitizers(BoundArch BA,
Action::OffloadKind DeviceOffloadKind) const {
return ToolChain::getSupportedSanitizers(BA, DeviceOffloadKind) |
SanitizerKind::KernelAddress;
}
Serenity::Serenity(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib"));
}
Tool *Serenity::buildLinker() const {
return new tools::serenity::Linker(*this);
}
void Serenity::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
const Driver &D = getDriver();
if (DriverArgs.hasArg(options::OPT_nostdinc))
return;
if (!DriverArgs.hasArg(options::OPT_nobuiltininc))
addSystemInclude(DriverArgs, CC1Args, concat(D.ResourceDir, "/include"));
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, "/usr/include"));
}