2013-08-07 06:31:59 +08:00
|
|
|
//===- lib/ReaderWriter/MachO/MachOLinkingContext.cpp ---------------------===//
|
2013-01-22 10:15:30 +08:00
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
#include "lld/ReaderWriter/MachOLinkingContext.h"
|
2013-01-24 04:03:10 +08:00
|
|
|
#include "GOTPass.hpp"
|
|
|
|
#include "StubsPass.hpp"
|
2013-04-05 02:59:24 +08:00
|
|
|
#include "ReferenceKinds.h"
|
2013-01-22 10:15:30 +08:00
|
|
|
|
2013-01-24 04:03:10 +08:00
|
|
|
#include "lld/Core/PassManager.h"
|
2013-04-05 02:59:24 +08:00
|
|
|
#include "lld/ReaderWriter/Reader.h"
|
|
|
|
#include "lld/ReaderWriter/Writer.h"
|
2013-02-08 04:16:12 +08:00
|
|
|
#include "lld/Passes/LayoutPass.h"
|
2013-10-29 13:12:14 +08:00
|
|
|
#include "lld/Passes/RoundTripYAMLPass.h"
|
2013-01-22 10:15:30 +08:00
|
|
|
|
2013-04-05 02:59:24 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2013-01-22 10:15:30 +08:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2013-11-07 05:36:55 +08:00
|
|
|
#include "llvm/Support/Host.h"
|
2013-09-28 06:50:00 +08:00
|
|
|
#include "llvm/Support/MachO.h"
|
2013-04-05 02:59:24 +08:00
|
|
|
|
|
|
|
using lld::mach_o::KindHandler;
|
2013-11-07 05:36:55 +08:00
|
|
|
using namespace llvm::MachO;
|
2013-04-05 02:59:24 +08:00
|
|
|
|
2013-01-22 10:15:30 +08:00
|
|
|
namespace lld {
|
2013-04-05 02:59:24 +08:00
|
|
|
|
2013-09-11 07:46:57 +08:00
|
|
|
bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {
|
|
|
|
result = 0;
|
2013-04-05 02:59:24 +08:00
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
if (str.empty())
|
2013-04-05 02:59:24 +08:00
|
|
|
return false;
|
2013-08-07 06:31:59 +08:00
|
|
|
|
2013-04-05 02:59:24 +08:00
|
|
|
SmallVector<StringRef, 3> parts;
|
|
|
|
llvm::SplitString(str, parts, ".");
|
2013-08-07 06:31:59 +08:00
|
|
|
|
2013-04-05 02:59:24 +08:00
|
|
|
unsigned long long num;
|
|
|
|
if (llvm::getAsUnsignedInteger(parts[0], 10, num))
|
|
|
|
return true;
|
|
|
|
if (num > 65535)
|
|
|
|
return true;
|
2013-09-11 07:46:57 +08:00
|
|
|
result = num << 16;
|
2013-08-07 06:31:59 +08:00
|
|
|
|
2013-04-05 02:59:24 +08:00
|
|
|
if (parts.size() > 1) {
|
|
|
|
if (llvm::getAsUnsignedInteger(parts[1], 10, num))
|
|
|
|
return true;
|
|
|
|
if (num > 255)
|
|
|
|
return true;
|
2013-09-11 07:46:57 +08:00
|
|
|
result |= (num << 8);
|
2013-04-05 02:59:24 +08:00
|
|
|
}
|
2013-08-07 06:31:59 +08:00
|
|
|
|
2013-04-05 02:59:24 +08:00
|
|
|
if (parts.size() > 2) {
|
|
|
|
if (llvm::getAsUnsignedInteger(parts[2], 10, num))
|
|
|
|
return true;
|
|
|
|
if (num > 255)
|
|
|
|
return true;
|
2013-09-11 07:46:57 +08:00
|
|
|
result |= num;
|
2013-04-05 02:59:24 +08:00
|
|
|
}
|
2013-08-07 06:31:59 +08:00
|
|
|
|
2013-04-05 02:59:24 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-07-20 10:08:23 +08:00
|
|
|
|
2013-11-07 05:36:55 +08:00
|
|
|
MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
|
|
|
|
{ "x86_64", arch_x86_64, true, CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL },
|
|
|
|
{ "i386", arch_x86, true, CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL },
|
|
|
|
{ "ppc", arch_ppc, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL },
|
|
|
|
{ "armv6", arch_armv6, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 },
|
|
|
|
{ "armv7", arch_armv7, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 },
|
|
|
|
{ "armv7s", arch_armv7s, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S },
|
|
|
|
{ "", arch_unknown,false, 0, 0 }
|
2013-07-20 10:08:23 +08:00
|
|
|
};
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
MachOLinkingContext::Arch
|
|
|
|
MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {
|
2013-11-07 05:36:55 +08:00
|
|
|
for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
|
|
|
|
if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype))
|
2013-07-20 10:08:23 +08:00
|
|
|
return info->arch;
|
|
|
|
}
|
|
|
|
return arch_unknown;
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
MachOLinkingContext::Arch
|
|
|
|
MachOLinkingContext::archFromName(StringRef archName) {
|
2013-11-07 05:36:55 +08:00
|
|
|
for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
|
|
|
|
if (info->archName.equals(archName))
|
2013-07-20 10:08:23 +08:00
|
|
|
return info->arch;
|
|
|
|
}
|
|
|
|
return arch_unknown;
|
|
|
|
}
|
|
|
|
|
[lld] Introduce registry and Reference kind tuple
The main changes are in:
include/lld/Core/Reference.h
include/lld/ReaderWriter/Reader.h
Everything else is details to support the main change.
1) Registration based Readers
Previously, lld had a tangled interdependency with all the Readers. It would
have been impossible to make a streamlined linker (say for a JIT) which
just supported one file format and one architecture (no yaml, no archives, etc).
The old model also required a LinkingContext to read an object file, which
would have made .o inspection tools awkward.
The new model is that there is a global Registry object. You programmatically
register the Readers you want with the registry object. Whenever you need to
read/parse a file, you ask the registry to do it, and the registry tries each
registered reader.
For ease of use with the existing lld code base, there is one Registry
object inside the LinkingContext object.
2) Changing kind value to be a tuple
Beside Readers, the registry also keeps track of the mapping for Reference
Kind values to and from strings. Along with that, this patch also fixes
an ambiguity with the previous Reference::Kind values. The problem was that
we wanted to reuse existing relocation type values as Reference::Kind values.
But then how can the YAML write know how to convert a value to a string? The
fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace
(e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and
a 16-bit value. This tuple system allows conversion to and from strings with
no ambiguities.
llvm-svn: 197727
2013-12-20 05:58:00 +08:00
|
|
|
StringRef MachOLinkingContext::nameFromArch(Arch arch) {
|
|
|
|
for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
|
|
|
|
if (info->arch == arch)
|
|
|
|
return info->archName;
|
|
|
|
}
|
|
|
|
return "<unknown>";
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {
|
2013-07-20 10:08:23 +08:00
|
|
|
assert(arch != arch_unknown);
|
2013-11-07 05:36:55 +08:00
|
|
|
for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
|
|
|
|
if (info->arch == arch)
|
2013-07-20 10:08:23 +08:00
|
|
|
return info->cputype;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unknown arch type");
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
|
2013-07-20 10:08:23 +08:00
|
|
|
assert(arch != arch_unknown);
|
2013-11-07 05:36:55 +08:00
|
|
|
for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
|
|
|
|
if (info->arch == arch)
|
2013-07-20 10:08:23 +08:00
|
|
|
return info->cpusubtype;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unknown arch type");
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
MachOLinkingContext::MachOLinkingContext()
|
2013-11-07 05:36:55 +08:00
|
|
|
: _outputFileType(MH_EXECUTE), _outputFileTypeStatic(false),
|
2013-09-11 07:46:57 +08:00
|
|
|
_doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
|
2013-11-07 05:36:55 +08:00
|
|
|
_pageZeroSize(unspecifiedPageZeroSize),
|
2013-11-09 07:00:26 +08:00
|
|
|
_pageSize(4096),
|
2013-11-07 05:36:55 +08:00
|
|
|
_compatibilityVersion(0), _currentVersion(0),
|
2013-09-11 07:55:14 +08:00
|
|
|
_deadStrippableDylib(false), _kindHandler(nullptr) {}
|
2013-04-05 02:59:24 +08:00
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
MachOLinkingContext::~MachOLinkingContext() {}
|
2013-04-05 02:59:24 +08:00
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
uint32_t MachOLinkingContext::getCPUType() const {
|
2013-07-20 10:08:23 +08:00
|
|
|
return cpuTypeFromArch(_arch);
|
2013-01-22 10:15:30 +08:00
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
uint32_t MachOLinkingContext::getCPUSubType() const {
|
2013-07-20 10:08:23 +08:00
|
|
|
return cpuSubtypeFromArch(_arch);
|
2013-01-22 10:15:30 +08:00
|
|
|
}
|
|
|
|
|
2013-11-07 05:36:55 +08:00
|
|
|
bool MachOLinkingContext::is64Bit(Arch arch) {
|
|
|
|
for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
|
|
|
|
if (info->arch == arch) {
|
|
|
|
return (info->cputype & CPU_ARCH_ABI64);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// unknown archs are not 64-bit.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MachOLinkingContext::isHostEndian(Arch arch) {
|
|
|
|
assert(arch != arch_unknown);
|
|
|
|
for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
|
|
|
|
if (info->arch == arch) {
|
|
|
|
return (info->littleEndian == llvm::sys::IsLittleEndianHost);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unknown arch type");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MachOLinkingContext::isBigEndian(Arch arch) {
|
|
|
|
assert(arch != arch_unknown);
|
|
|
|
for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
|
|
|
|
if (info->arch == arch) {
|
|
|
|
return ! info->littleEndian;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unknown arch type");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool MachOLinkingContext::is64Bit() const {
|
|
|
|
return is64Bit(_arch);
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
bool MachOLinkingContext::outputTypeHasEntry() const {
|
2013-04-05 02:59:24 +08:00
|
|
|
switch (_outputFileType) {
|
2013-11-07 05:36:55 +08:00
|
|
|
case MH_EXECUTE:
|
|
|
|
case MH_DYLINKER:
|
|
|
|
case MH_PRELOAD:
|
2013-01-23 09:18:43 +08:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
|
2013-10-08 08:43:34 +08:00
|
|
|
uint32_t parsedVersion;
|
2013-04-05 02:59:24 +08:00
|
|
|
switch (_os) {
|
2013-10-08 08:43:34 +08:00
|
|
|
case OS::macOSX:
|
2013-09-11 07:46:57 +08:00
|
|
|
if (parsePackedVersion(mac, parsedVersion))
|
|
|
|
return false;
|
|
|
|
return _osMinVersion >= parsedVersion;
|
2013-04-05 02:59:24 +08:00
|
|
|
case OS::iOS:
|
2013-10-08 08:43:34 +08:00
|
|
|
case OS::iOS_simulator:
|
2013-09-11 07:46:57 +08:00
|
|
|
if (parsePackedVersion(iOS, parsedVersion))
|
|
|
|
return false;
|
|
|
|
return _osMinVersion >= parsedVersion;
|
2013-10-08 08:43:34 +08:00
|
|
|
case OS::unknown:
|
|
|
|
break;
|
2013-04-05 02:59:24 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("target not configured for iOS or MacOSX");
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
bool MachOLinkingContext::addEntryPointLoadCommand() const {
|
2013-11-07 05:36:55 +08:00
|
|
|
if ((_outputFileType == MH_EXECUTE) && !_outputFileTypeStatic) {
|
2013-04-05 02:59:24 +08:00
|
|
|
return minOS("10.8", "6.0");
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
bool MachOLinkingContext::addUnixThreadLoadCommand() const {
|
2013-04-05 02:59:24 +08:00
|
|
|
switch (_outputFileType) {
|
2013-11-07 05:36:55 +08:00
|
|
|
case MH_EXECUTE:
|
2013-04-05 02:59:24 +08:00
|
|
|
if (_outputFileTypeStatic)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return !minOS("10.8", "6.0");
|
|
|
|
break;
|
2013-11-07 05:36:55 +08:00
|
|
|
case MH_DYLINKER:
|
|
|
|
case MH_PRELOAD:
|
2013-01-23 09:18:43 +08:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
|
2013-11-07 05:36:55 +08:00
|
|
|
if ((_outputFileType == MH_EXECUTE) && _entrySymbolName.empty()){
|
2013-04-05 02:59:24 +08:00
|
|
|
if (_outputFileTypeStatic) {
|
|
|
|
_entrySymbolName = "start";
|
2013-11-13 01:46:55 +08:00
|
|
|
} else if (addUnixThreadLoadCommand()) {
|
2013-04-05 02:59:24 +08:00
|
|
|
// If targeting older OS, use start (in crt1.o)
|
2013-11-13 01:46:55 +08:00
|
|
|
_entrySymbolName = "start";
|
|
|
|
} else if (addEntryPointLoadCommand()) {
|
|
|
|
// If targeting newer OS, use _main
|
|
|
|
_entrySymbolName = "_main";
|
2013-04-05 02:59:24 +08:00
|
|
|
}
|
2013-01-22 10:15:30 +08:00
|
|
|
}
|
2013-01-24 04:03:10 +08:00
|
|
|
|
2013-11-07 05:36:55 +08:00
|
|
|
// TODO: if -arch not specified, look at arch of first .o file.
|
|
|
|
|
|
|
|
// Set default __PAGEZERO for main executables
|
|
|
|
if ((_outputFileType == MH_EXECUTE) && !_outputFileTypeStatic
|
|
|
|
&& (_pageZeroSize == unspecifiedPageZeroSize)) {
|
|
|
|
if (is64Bit(_arch))
|
|
|
|
_pageZeroSize = 0x100000000;
|
|
|
|
else
|
|
|
|
_pageZeroSize = 0x00010000;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_currentVersion && _outputFileType != MH_DYLIB) {
|
2013-09-11 07:55:14 +08:00
|
|
|
diagnostics << "error: -current_version can only be used with dylibs\n";
|
2013-09-25 07:26:34 +08:00
|
|
|
return false;
|
2013-09-11 07:55:14 +08:00
|
|
|
}
|
|
|
|
|
2013-11-07 05:36:55 +08:00
|
|
|
if (_compatibilityVersion && _outputFileType != MH_DYLIB) {
|
2013-09-11 07:55:14 +08:00
|
|
|
diagnostics
|
|
|
|
<< "error: -compatibility_version can only be used with dylibs\n";
|
2013-09-25 07:26:34 +08:00
|
|
|
return false;
|
2013-09-11 07:55:14 +08:00
|
|
|
}
|
|
|
|
|
2013-11-07 05:36:55 +08:00
|
|
|
if (_deadStrippableDylib && _outputFileType != MH_DYLIB) {
|
2013-09-11 07:55:14 +08:00
|
|
|
diagnostics
|
|
|
|
<< "error: -mark_dead_strippable_dylib can only be used with dylibs.\n";
|
2013-09-25 07:26:34 +08:00
|
|
|
return false;
|
2013-09-11 07:55:14 +08:00
|
|
|
}
|
|
|
|
|
2013-11-07 05:36:55 +08:00
|
|
|
if (!_bundleLoader.empty() && outputFileType() != MH_BUNDLE) {
|
2013-09-11 07:55:14 +08:00
|
|
|
diagnostics
|
|
|
|
<< "error: -bundle_loader can only be used with Mach-O bundles\n";
|
2013-09-25 07:26:34 +08:00
|
|
|
return false;
|
2013-09-11 07:55:14 +08:00
|
|
|
}
|
|
|
|
|
2013-09-25 07:26:34 +08:00
|
|
|
return true;
|
2013-04-05 02:59:24 +08:00
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
bool MachOLinkingContext::setOS(OS os, StringRef minOSVersion) {
|
2013-04-05 02:59:24 +08:00
|
|
|
_os = os;
|
2013-09-11 07:46:57 +08:00
|
|
|
return parsePackedVersion(minOSVersion, _osMinVersion);
|
2013-04-05 02:59:24 +08:00
|
|
|
}
|
|
|
|
|
2013-10-29 13:12:14 +08:00
|
|
|
void MachOLinkingContext::addPasses(PassManager &pm) {
|
2013-11-07 05:36:55 +08:00
|
|
|
if (outputFileType() != MH_OBJECT) {
|
|
|
|
pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass));
|
|
|
|
pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this)));
|
|
|
|
}
|
2013-04-05 02:59:24 +08:00
|
|
|
pm.add(std::unique_ptr<Pass>(new LayoutPass()));
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
Writer &MachOLinkingContext::writer() const {
|
2013-04-05 02:59:24 +08:00
|
|
|
if (!_writer) {
|
|
|
|
_writer = createWriterMachO(*this);
|
2013-01-24 04:03:10 +08:00
|
|
|
}
|
2013-04-05 02:59:24 +08:00
|
|
|
return *_writer;
|
|
|
|
}
|
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
KindHandler &MachOLinkingContext::kindHandler() const {
|
2013-04-05 02:59:24 +08:00
|
|
|
if (!_kindHandler)
|
|
|
|
_kindHandler = KindHandler::create(_arch);
|
|
|
|
return *_kindHandler;
|
|
|
|
}
|
2013-01-22 10:15:30 +08:00
|
|
|
|
2013-04-05 02:59:24 +08:00
|
|
|
|
2013-01-22 10:15:30 +08:00
|
|
|
} // end namespace lld
|