aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Driver/ToolChains/UEFI.cpp
blob: 2b4117354347731dc4fa72b2c8b493feb973954b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//===--- UEFI.cpp - UEFI ToolChain Implementations -----------------------===//
//
// 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 "UEFI.h"
#include "clang/Config/config.h"
#include "clang/Driver/CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/TargetParser/Host.h"

using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

UEFI::UEFI(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
    : ToolChain(D, Triple, Args) {}

Tool *UEFI::buildLinker() const { return new tools::uefi::Linker(*this); }

void UEFI::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                     ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
    SmallString<128> Dir(getDriver().ResourceDir);
    llvm::sys::path::append(Dir, "include");
    addSystemInclude(DriverArgs, CC1Args, Dir.str());
  }

  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
    return;

  if (std::optional<std::string> Path = getStdlibIncludePath())
    addSystemInclude(DriverArgs, CC1Args, *Path);
}

void tools::uefi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
                                       const InputInfo &Output,
                                       const InputInfoList &Inputs,
                                       const ArgList &Args,
                                       const char *LinkingOutput) const {
  ArgStringList CmdArgs;
  auto &TC = static_cast<const toolchains::UEFI &>(getToolChain());

  assert((Output.isFilename() || Output.isNothing()) && "invalid output");
  if (Output.isFilename())
    CmdArgs.push_back(
        Args.MakeArgString(std::string("-out:") + Output.getFilename()));

  CmdArgs.push_back("-nologo");

  // TODO: Other UEFI binary subsystems that are currently unsupported:
  // efi_boot_service_driver, efi_rom, efi_runtime_driver.
  CmdArgs.push_back("-subsystem:efi_application");

  // Default entry function name according to the TianoCore reference
  // implementation is EfiMain.
  // TODO: Provide a flag to override the entry function name.
  CmdArgs.push_back("-entry:EfiMain");

  // "Terminal Service Aware" flag is not needed for UEFI applications.
  CmdArgs.push_back("-tsaware:no");

  if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
    CmdArgs.push_back("-debug");

  Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);

  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);

  // This should ideally be handled by ToolChain::GetLinkerPath but we need
  // to special case some linker paths. In the case of lld, we need to
  // translate 'lld' into 'lld-link'.
  StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ,
                                          TC.getDriver().getPreferredLinker());
  if (Linker.empty() || Linker == "lld")
    Linker = "lld-link";

  auto LinkerPath = TC.GetProgramPath(Linker.str().c_str());
  auto LinkCmd = std::make_unique<Command>(
      JA, *this, ResponseFileSupport::AtFileUTF16(),
      Args.MakeArgString(LinkerPath), CmdArgs, Inputs, Output);
  C.addCommand(std::move(LinkCmd));
}