Skip to content

Commit 178a185

Browse files
committed
[UEFI] X86_64 UEFI Clang Driver
Introduce changes necessary for UEFI X86_64 target Clang driver. Reviewed By: phosek Differential Revision: https://reviews.llvm.org/D159541
1 parent c414612 commit 178a185

File tree

8 files changed

+247
-0
lines changed

8 files changed

+247
-0
lines changed

clang/lib/Basic/Targets.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,9 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
625625
case llvm::Triple::Solaris:
626626
return std::make_unique<SolarisTargetInfo<X86_64TargetInfo>>(Triple,
627627
Opts);
628+
case llvm::Triple::UEFI:
629+
return std::make_unique<UEFIX86_64TargetInfo>(Triple, Opts);
630+
628631
case llvm::Triple::Win32: {
629632
switch (Triple.getEnvironment()) {
630633
case llvm::Triple::Cygnus:

clang/lib/Basic/Targets/OSTargets.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,21 @@ class LLVM_LIBRARY_VISIBILITY ZOSTargetInfo : public OSTargetInfo<Target> {
774774
}
775775
};
776776

777+
// UEFI target
778+
template <typename Target>
779+
class LLVM_LIBRARY_VISIBILITY UEFITargetInfo : public OSTargetInfo<Target> {
780+
protected:
781+
void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
782+
MacroBuilder &Builder) const override {}
783+
784+
public:
785+
UEFITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
786+
: OSTargetInfo<Target>(Triple, Opts) {
787+
this->WCharType = TargetInfo::UnsignedShort;
788+
this->WIntType = TargetInfo::UnsignedShort;
789+
}
790+
};
791+
777792
void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts,
778793
MacroBuilder &Builder);
779794

clang/lib/Basic/Targets/X86.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,43 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
819819
}
820820
};
821821

822+
// x86-64 UEFI target
823+
class LLVM_LIBRARY_VISIBILITY UEFIX86_64TargetInfo
824+
: public UEFITargetInfo<X86_64TargetInfo> {
825+
public:
826+
UEFIX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
827+
: UEFITargetInfo<X86_64TargetInfo>(Triple, Opts) {
828+
this->TheCXXABI.set(TargetCXXABI::Microsoft);
829+
this->MaxTLSAlign = 8192u * this->getCharWidth();
830+
this->resetDataLayout("e-m:w-p270:32:32-p271:32:32-p272:64:64-"
831+
"i64:64-i128:128-f80:128-n8:16:32:64-S128");
832+
}
833+
834+
void getTargetDefines(const LangOptions &Opts,
835+
MacroBuilder &Builder) const override {
836+
getOSDefines(Opts, X86TargetInfo::getTriple(), Builder);
837+
}
838+
839+
BuiltinVaListKind getBuiltinVaListKind() const override {
840+
return TargetInfo::CharPtrBuiltinVaList;
841+
}
842+
843+
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
844+
switch (CC) {
845+
case CC_C:
846+
case CC_Win64:
847+
return CCCR_OK;
848+
default:
849+
return CCCR_Warning;
850+
}
851+
}
852+
853+
TargetInfo::CallingConvKind
854+
getCallingConvKind(bool ClangABICompat4) const override {
855+
return CCK_MicrosoftWin64;
856+
}
857+
};
858+
822859
// x86-64 Windows target
823860
class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
824861
: public WindowsTargetInfo<X86_64TargetInfo> {

clang/lib/Driver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ add_clang_library(clangDriver
7878
ToolChains/Solaris.cpp
7979
ToolChains/SPIRV.cpp
8080
ToolChains/TCE.cpp
81+
ToolChains/UEFI.cpp
8182
ToolChains/VEToolchain.cpp
8283
ToolChains/WebAssembly.cpp
8384
ToolChains/XCore.cpp

clang/lib/Driver/Driver.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "ToolChains/SPIRV.h"
4646
#include "ToolChains/Solaris.h"
4747
#include "ToolChains/TCE.h"
48+
#include "ToolChains/UEFI.h"
4849
#include "ToolChains/VEToolchain.h"
4950
#include "ToolChains/WebAssembly.h"
5051
#include "ToolChains/XCore.h"
@@ -6259,6 +6260,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
62596260
case llvm::Triple::Mesa3D:
62606261
TC = std::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args);
62616262
break;
6263+
case llvm::Triple::UEFI:
6264+
TC = std::make_unique<toolchains::UEFI>(*this, Target, Args);
6265+
break;
62626266
case llvm::Triple::Win32:
62636267
switch (Target.getEnvironment()) {
62646268
default:

clang/lib/Driver/ToolChains/UEFI.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//===--- UEFI.h - UEFI ToolChain Implementations ----------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "UEFI.h"
10+
#include "CommonArgs.h"
11+
#include "Darwin.h"
12+
#include "clang/Basic/CharInfo.h"
13+
#include "clang/Basic/Version.h"
14+
#include "clang/Config/config.h"
15+
#include "clang/Driver/Compilation.h"
16+
#include "clang/Driver/Driver.h"
17+
#include "clang/Driver/Options.h"
18+
#include "clang/Driver/SanitizerArgs.h"
19+
#include "llvm/ADT/StringExtras.h"
20+
#include "llvm/ADT/StringSwitch.h"
21+
#include "llvm/Option/Arg.h"
22+
#include "llvm/Option/ArgList.h"
23+
#include "llvm/Support/FileSystem.h"
24+
#include "llvm/Support/MemoryBuffer.h"
25+
#include "llvm/Support/VirtualFileSystem.h"
26+
#include "llvm/TargetParser/Host.h"
27+
28+
using namespace clang::driver;
29+
using namespace clang::driver::toolchains;
30+
using namespace clang;
31+
using namespace llvm::opt;
32+
33+
UEFI::UEFI(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
34+
: ToolChain(D, Triple, Args) {
35+
getProgramPaths().push_back(getDriver().getInstalledDir());
36+
if (getDriver().getInstalledDir() != getDriver().Dir)
37+
getProgramPaths().push_back(getDriver().Dir);
38+
}
39+
40+
Tool *UEFI::buildLinker() const { return new tools::uefi::Linker(*this); }
41+
42+
void tools::uefi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
43+
const InputInfo &Output,
44+
const InputInfoList &Inputs,
45+
const ArgList &Args,
46+
const char *LinkingOutput) const {
47+
ArgStringList CmdArgs;
48+
49+
auto &TC = static_cast<const toolchains::UEFI &>(getToolChain());
50+
51+
assert((Output.isFilename() || Output.isNothing()) && "invalid output");
52+
if (Output.isFilename())
53+
CmdArgs.push_back(
54+
Args.MakeArgString(std::string("-out:") + Output.getFilename()));
55+
56+
CmdArgs.push_back("-nologo");
57+
58+
// TODO: Other UEFI binary subsystems that are currently unsupported:
59+
// efi_boot_service_driver, efi_rom, efi_runtime_driver.
60+
CmdArgs.push_back("-subsystem:efi_application");
61+
62+
// Default entry function name according to the TianoCore reference
63+
// implementation is EfiMain.
64+
// TODO: Provide a flag to override the entry function name.
65+
CmdArgs.push_back("-entry:EfiMain");
66+
67+
// "Terminal Service Aware" flag is not needed for UEFI applications.
68+
CmdArgs.push_back("-tsaware:no");
69+
70+
// EFI_APPLICATION to be linked as DLL by default.
71+
CmdArgs.push_back("-dll");
72+
73+
if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
74+
CmdArgs.push_back("-debug");
75+
76+
Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
77+
78+
// Add filenames, libraries, and other linker inputs.
79+
for (const auto &Input : Inputs) {
80+
if (Input.isFilename()) {
81+
CmdArgs.push_back(Input.getFilename());
82+
continue;
83+
}
84+
85+
const Arg &A = Input.getInputArg();
86+
if (A.getOption().matches(options::OPT_l)) {
87+
StringRef Lib = A.getValue();
88+
const char *LinkLibArg;
89+
if (Lib.ends_with(".lib"))
90+
LinkLibArg = Args.MakeArgString(Lib);
91+
else
92+
LinkLibArg = Args.MakeArgString(Lib + ".lib");
93+
CmdArgs.push_back(LinkLibArg);
94+
continue;
95+
}
96+
97+
// Otherwise, this is some other kind of linker input option like -Wl, -z,
98+
// or -L.
99+
A.renderAsInput(Args, CmdArgs);
100+
}
101+
102+
// This should ideally be handled by ToolChain::GetLinkerPath but we need
103+
// to special case some linker paths. In the case of lld, we need to
104+
// translate 'lld' into 'lld-link'.
105+
StringRef Linker =
106+
Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
107+
if (Linker.empty() || Linker.equals_insensitive("lld"))
108+
Linker = "lld-link";
109+
110+
auto LinkerPath = TC.GetProgramPath(Linker.str().c_str());
111+
auto LinkCmd = std::make_unique<Command>(
112+
JA, *this, ResponseFileSupport::AtFileUTF16(),
113+
Args.MakeArgString(LinkerPath), CmdArgs, Inputs, Output);
114+
C.addCommand(std::move(LinkCmd));
115+
}

clang/lib/Driver/ToolChains/UEFI.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===--- UEFI.h - UEFI ToolChain Implementations ----------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H
10+
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H
11+
12+
#include "clang/Driver/Tool.h"
13+
#include "clang/Driver/ToolChain.h"
14+
15+
namespace clang {
16+
namespace driver {
17+
namespace tools {
18+
namespace uefi {
19+
class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
20+
public:
21+
Linker(const ToolChain &TC) : Tool("uefi::Linker", "lld-link", TC) {}
22+
23+
bool hasIntegratedCPP() const override { return false; }
24+
bool isLinkJob() const override { return true; }
25+
26+
void ConstructJob(Compilation &C, const JobAction &JA,
27+
const InputInfo &Output, const InputInfoList &Inputs,
28+
const llvm::opt::ArgList &TCArgs,
29+
const char *LinkingOutput) const override;
30+
};
31+
} // end namespace uefi
32+
} // end namespace tools
33+
34+
namespace toolchains {
35+
36+
class LLVM_LIBRARY_VISIBILITY UEFI : public ToolChain {
37+
public:
38+
UEFI(const Driver &D, const llvm::Triple &Triple,
39+
const llvm::opt::ArgList &Args);
40+
41+
protected:
42+
Tool *buildLinker() const override;
43+
44+
public:
45+
bool HasNativeLLVMSupport() const override { return true; }
46+
UnwindTableLevel
47+
getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override {
48+
return UnwindTableLevel::Asynchronous;
49+
}
50+
bool isPICDefault() const override { return true; }
51+
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
52+
return false;
53+
}
54+
bool isPICDefaultForced() const override { return true; }
55+
};
56+
57+
} // namespace toolchains
58+
} // namespace driver
59+
} // namespace clang
60+
61+
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_UEFI_H

clang/test/Driver/uefi.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %clang -### %s --target=x86_64-unknown-uefi \
2+
// RUN: --sysroot=%S/platform -fuse-ld=lld 2>&1 \
3+
// RUN: | FileCheck -check-prefixes=CHECK %s
4+
// CHECK: "-cc1"
5+
// CHECK-SAME: "-triple" "x86_64-unknown-uefi"
6+
// CHECK-SAME: "-mrelocation-model" "pic" "-pic-level" "2"
7+
// CHECK-SAME: "-mframe-pointer=all"
8+
// CHECK-NEXT: "-subsystem:efi_application"
9+
// CHECK-SAME: "-entry:EfiMain"
10+
// CHECK-SAME: "-tsaware:no"
11+
// CHECK-SAME: "-dll"

0 commit comments

Comments
 (0)