forked from swiftlang/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[lld] Initial commit for new Mach-O backend
Summary: This is the first commit for the new Mach-O backend, designed to roughly follow the architecture of the existing ELF and COFF backends, and building off work that @RuiU and @pcc did in a branch a while back. Note that this is a very stripped-down commit with the bare minimum of functionality for ease of review. We'll be following up with more diffs soon. Currently, we're able to generate a simple "Hello World!" executable that runs on OS X Catalina (and possibly on earlier OS X versions; I haven't tested them). (This executable can be obtained by compiling `test/MachO/relocations.s`.) We're mocking out a few load commands to achieve this -- for example, we can't load dynamic libraries, but Catalina requires binaries to be linked against `dyld`, so we hardcode the emission of a `LC_LOAD_DYLIB` command. Other mocked out load commands include LC_SYMTAB and LC_DYSYMTAB. Differential Revision: https://reviews.llvm.org/D75382
- Loading branch information
Showing
36 changed files
with
1,669 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
//===- X86_64.cpp ---------------------------------------------------------===// | ||
// | ||
// 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 "Target.h" | ||
#include "lld/Common/ErrorHandler.h" | ||
#include "llvm/BinaryFormat/MachO.h" | ||
#include "llvm/Support/Endian.h" | ||
|
||
using namespace llvm::MachO; | ||
using namespace llvm::support::endian; | ||
using namespace lld; | ||
using namespace lld::macho; | ||
|
||
namespace { | ||
|
||
struct X86_64 : TargetInfo { | ||
X86_64(); | ||
uint64_t getImplicitAddend(const uint8_t *loc, uint8_t type) const override; | ||
void relocateOne(uint8_t *loc, uint8_t type, uint64_t val) const override; | ||
}; | ||
|
||
X86_64::X86_64() { | ||
cpuType = CPU_TYPE_X86_64; | ||
cpuSubtype = CPU_SUBTYPE_X86_64_ALL; | ||
} | ||
|
||
uint64_t X86_64::getImplicitAddend(const uint8_t *loc, uint8_t type) const { | ||
switch (type) { | ||
case X86_64_RELOC_SIGNED: | ||
return read32le(loc); | ||
default: | ||
error("TODO: Unhandled relocation type " + std::to_string(type)); | ||
return 0; | ||
} | ||
} | ||
|
||
void X86_64::relocateOne(uint8_t *loc, uint8_t type, uint64_t val) const { | ||
switch (type) { | ||
case X86_64_RELOC_SIGNED: | ||
// This type is only used for pc-relative relocations, so offset by 4 since | ||
// the RIP has advanced by 4 at this point. | ||
write32le(loc, val - 4); | ||
break; | ||
default: | ||
llvm_unreachable( | ||
"getImplicitAddend should have flagged all unhandled relocation types"); | ||
} | ||
} | ||
|
||
} // namespace | ||
|
||
TargetInfo *macho::createX86_64TargetInfo() { | ||
static X86_64 t; | ||
return &t; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
set(LLVM_TARGET_DEFINITIONS Options.td) | ||
tablegen(LLVM Options.inc -gen-opt-parser-defs) | ||
add_public_tablegen_target(MachOOptionsTableGen) | ||
|
||
add_lld_library(lldMachO2 | ||
Arch/X86_64.cpp | ||
Driver.cpp | ||
InputFiles.cpp | ||
InputSection.cpp | ||
OutputSegment.cpp | ||
SymbolTable.cpp | ||
Symbols.cpp | ||
Target.cpp | ||
Writer.cpp | ||
|
||
LINK_COMPONENTS | ||
${LLVM_TARGETS_TO_BUILD} | ||
BinaryFormat | ||
Core | ||
DebugInfoDWARF | ||
LTO | ||
MC | ||
Object | ||
Option | ||
Support | ||
|
||
LINK_LIBS | ||
lldCommon | ||
${LLVM_PTHREAD_LIB} | ||
|
||
DEPENDS | ||
MachOOptionsTableGen | ||
${tablegen_deps} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
//===- Config.h -------------------------------------------------*- 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLD_MACHO_CONFIG_H | ||
#define LLD_MACHO_CONFIG_H | ||
|
||
#include "llvm/ADT/StringRef.h" | ||
|
||
namespace lld { | ||
namespace macho { | ||
|
||
class Symbol; | ||
|
||
struct Configuration { | ||
llvm::StringRef outputFile; | ||
Symbol *entry; | ||
}; | ||
|
||
extern Configuration *config; | ||
|
||
} // namespace macho | ||
} // namespace lld | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
//===- Driver.cpp ---------------------------------------------------------===// | ||
// | ||
// 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 "Driver.h" | ||
#include "Config.h" | ||
#include "InputFiles.h" | ||
#include "OutputSegment.h" | ||
#include "SymbolTable.h" | ||
#include "Symbols.h" | ||
#include "Target.h" | ||
#include "Writer.h" | ||
|
||
#include "lld/Common/Args.h" | ||
#include "lld/Common/Driver.h" | ||
#include "lld/Common/ErrorHandler.h" | ||
#include "lld/Common/LLVM.h" | ||
#include "lld/Common/Memory.h" | ||
#include "lld/Common/Version.h" | ||
#include "llvm/ADT/StringRef.h" | ||
#include "llvm/BinaryFormat/MachO.h" | ||
#include "llvm/BinaryFormat/Magic.h" | ||
#include "llvm/Option/ArgList.h" | ||
#include "llvm/Option/Option.h" | ||
#include "llvm/Support/MemoryBuffer.h" | ||
|
||
using namespace llvm; | ||
using namespace llvm::MachO; | ||
using namespace llvm::sys; | ||
using namespace lld; | ||
using namespace lld::macho; | ||
|
||
Configuration *lld::macho::config; | ||
|
||
// Create prefix string literals used in Options.td | ||
#define PREFIX(NAME, VALUE) const char *NAME[] = VALUE; | ||
#include "Options.inc" | ||
#undef PREFIX | ||
|
||
// Create table mapping all options defined in Options.td | ||
static const opt::OptTable::Info optInfo[] = { | ||
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ | ||
{X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ | ||
X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, | ||
#include "Options.inc" | ||
#undef OPTION | ||
}; | ||
|
||
MachOOptTable::MachOOptTable() : OptTable(optInfo) {} | ||
|
||
opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) { | ||
// Make InputArgList from string vectors. | ||
unsigned missingIndex; | ||
unsigned missingCount; | ||
SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); | ||
|
||
opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount); | ||
|
||
if (missingCount) | ||
error(Twine(args.getArgString(missingIndex)) + ": missing argument"); | ||
|
||
for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) | ||
error("unknown argument: " + arg->getSpelling()); | ||
return args; | ||
} | ||
|
||
static TargetInfo *createTargetInfo(opt::InputArgList &args) { | ||
StringRef s = args.getLastArgValue(OPT_arch, "x86_64"); | ||
if (s != "x86_64") | ||
error("missing or unsupported -arch " + s); | ||
return createX86_64TargetInfo(); | ||
} | ||
|
||
static void addFile(StringRef path) { | ||
Optional<MemoryBufferRef> buffer = readFile(path); | ||
if (!buffer) | ||
return; | ||
MemoryBufferRef mbref = *buffer; | ||
|
||
switch (identify_magic(mbref.getBuffer())) { | ||
case file_magic::macho_object: | ||
inputFiles.push_back(make<ObjFile>(mbref)); | ||
break; | ||
default: | ||
error(path + ": unhandled file type"); | ||
} | ||
} | ||
|
||
bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly, | ||
raw_ostream &stdoutOS, raw_ostream &stderrOS) { | ||
lld::stdoutOS = &stdoutOS; | ||
lld::stderrOS = &stderrOS; | ||
|
||
MachOOptTable parser; | ||
opt::InputArgList args = parser.parse(argsArr.slice(1)); | ||
|
||
if (args.hasArg(OPT_v)) { | ||
message(getLLDVersion()); | ||
freeArena(); | ||
return !errorCount(); | ||
} | ||
|
||
config = make<Configuration>(); | ||
symtab = make<SymbolTable>(); | ||
target = createTargetInfo(args); | ||
|
||
config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main")); | ||
config->outputFile = args.getLastArgValue(OPT_o, "a.out"); | ||
|
||
getOrCreateOutputSegment("__TEXT", VM_PROT_READ | VM_PROT_EXECUTE); | ||
getOrCreateOutputSegment("__DATA", VM_PROT_READ | VM_PROT_WRITE); | ||
|
||
for (opt::Arg *arg : args) { | ||
switch (arg->getOption().getID()) { | ||
case OPT_INPUT: | ||
addFile(arg->getValue()); | ||
break; | ||
} | ||
} | ||
|
||
if (!isa<Defined>(config->entry)) { | ||
error("undefined symbol: " + config->entry->getName()); | ||
return false; | ||
} | ||
|
||
// Initialize InputSections. | ||
for (InputFile *file : inputFiles) | ||
for (InputSection *sec : file->sections) | ||
inputSections.push_back(sec); | ||
|
||
// Add input sections to output segments. | ||
for (InputSection *isec : inputSections) { | ||
OutputSegment *os = | ||
getOrCreateOutputSegment(isec->segname, VM_PROT_READ | VM_PROT_WRITE); | ||
os->sections[isec->name].push_back(isec); | ||
} | ||
|
||
// Write to an output file. | ||
writeResult(); | ||
|
||
if (canExitEarly) | ||
exitLld(errorCount() ? 1 : 0); | ||
|
||
freeArena(); | ||
return !errorCount(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
//===- Driver.h -------------------------------------------------*- 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLD_MACHO_DRIVER_H | ||
#define LLD_MACHO_DRIVER_H | ||
|
||
#include "lld/Common/LLVM.h" | ||
#include "llvm/Option/OptTable.h" | ||
|
||
namespace lld { | ||
namespace macho { | ||
|
||
class MachOOptTable : public llvm::opt::OptTable { | ||
public: | ||
MachOOptTable(); | ||
llvm::opt::InputArgList parse(ArrayRef<const char *> argv); | ||
}; | ||
|
||
// Create enum with OPT_xxx values for each option in Options.td | ||
enum { | ||
OPT_INVALID = 0, | ||
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, | ||
#include "Options.inc" | ||
#undef OPTION | ||
}; | ||
|
||
} // namespace macho | ||
} // namespace lld | ||
|
||
#endif |
Oops, something went wrong.