[mach-o] binary reader and writer
This patch adds support for converting normalized mach-o to and from binary
mach-o. It also changes WriterMachO (which previously directly wrote a
mach-o binary given a set of Atoms) to instead do it in two steps. The first
step uses normalizedFromAtoms() to convert Atoms to normalized mach-o, and the
second step uses writeBinary() which to generate the mach-o binary file.
llvm-svn: 194167
diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 655f3d7..005c8f7 100644
--- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -21,9 +21,11 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/MachO.h"
using lld::mach_o::KindHandler;
+using namespace llvm::MachO;
namespace lld {
@@ -62,71 +64,58 @@
return false;
}
-struct ArchInfo {
- StringRef archName;
- MachOLinkingContext::Arch arch;
- uint32_t cputype;
- uint32_t cpusubtype;
-};
-static ArchInfo archInfos[] = {
- { "x86_64", MachOLinkingContext::arch_x86_64, llvm::MachO::CPU_TYPE_X86_64,
- llvm::MachO::CPU_SUBTYPE_X86_64_ALL },
- { "i386", MachOLinkingContext::arch_x86, llvm::MachO::CPU_TYPE_I386,
- llvm::MachO::CPU_SUBTYPE_X86_ALL },
- { "armv6", MachOLinkingContext::arch_armv6, llvm::MachO::CPU_TYPE_ARM,
- llvm::MachO::CPU_SUBTYPE_ARM_V6 },
- { "armv7", MachOLinkingContext::arch_armv7, llvm::MachO::CPU_TYPE_ARM,
- llvm::MachO::CPU_SUBTYPE_ARM_V7 },
- { "armv7s", MachOLinkingContext::arch_armv7s, llvm::MachO::CPU_TYPE_ARM,
- llvm::MachO::CPU_SUBTYPE_ARM_V7S },
- { StringRef(), MachOLinkingContext::arch_unknown, 0, 0 }
+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 }
};
MachOLinkingContext::Arch
MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {
- for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
- if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype)) {
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype))
return info->arch;
- }
}
return arch_unknown;
}
MachOLinkingContext::Arch
MachOLinkingContext::archFromName(StringRef archName) {
- for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
- if (info->archName.equals(archName)) {
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->archName.equals(archName))
return info->arch;
- }
}
return arch_unknown;
}
uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {
assert(arch != arch_unknown);
- for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
- if (info->arch == arch) {
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->arch == arch)
return info->cputype;
- }
}
llvm_unreachable("Unknown arch type");
}
uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
assert(arch != arch_unknown);
- for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
- if (info->arch == arch) {
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->arch == arch)
return info->cpusubtype;
- }
}
llvm_unreachable("Unknown arch type");
}
MachOLinkingContext::MachOLinkingContext()
- : _outputFileType(llvm::MachO::MH_EXECUTE), _outputFileTypeStatic(false),
+ : _outputFileType(MH_EXECUTE), _outputFileTypeStatic(false),
_doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
- _pageZeroSize(0x1000), _compatibilityVersion(0), _currentVersion(0),
+ _pageZeroSize(unspecifiedPageZeroSize),
+ _compatibilityVersion(0), _currentVersion(0),
_deadStrippableDylib(false), _kindHandler(nullptr) {}
MachOLinkingContext::~MachOLinkingContext() {}
@@ -139,11 +128,47 @@
return cpuSubtypeFromArch(_arch);
}
+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);
+}
+
bool MachOLinkingContext::outputTypeHasEntry() const {
switch (_outputFileType) {
- case llvm::MachO::MH_EXECUTE:
- case llvm::MachO::MH_DYLINKER:
- case llvm::MachO::MH_PRELOAD:
+ case MH_EXECUTE:
+ case MH_DYLINKER:
+ case MH_PRELOAD:
return true;
default:
return false;
@@ -169,7 +194,7 @@
}
bool MachOLinkingContext::addEntryPointLoadCommand() const {
- if ((_outputFileType == llvm::MachO::MH_EXECUTE) && !_outputFileTypeStatic) {
+ if ((_outputFileType == MH_EXECUTE) && !_outputFileTypeStatic) {
return minOS("10.8", "6.0");
}
return false;
@@ -177,14 +202,14 @@
bool MachOLinkingContext::addUnixThreadLoadCommand() const {
switch (_outputFileType) {
- case llvm::MachO::MH_EXECUTE:
+ case MH_EXECUTE:
if (_outputFileTypeStatic)
return true;
else
return !minOS("10.8", "6.0");
break;
- case llvm::MachO::MH_DYLINKER:
- case llvm::MachO::MH_PRELOAD:
+ case MH_DYLINKER:
+ case MH_PRELOAD:
return true;
default:
return false;
@@ -192,7 +217,7 @@
}
bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
- if ((_outputFileType == llvm::MachO::MH_EXECUTE) && _entrySymbolName.empty()){
+ if ((_outputFileType == MH_EXECUTE) && _entrySymbolName.empty()){
if (_outputFileTypeStatic) {
_entrySymbolName = "start";
} else {
@@ -206,24 +231,35 @@
}
}
- if (_currentVersion && _outputFileType != llvm::MachO::MH_DYLIB) {
+ // 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) {
diagnostics << "error: -current_version can only be used with dylibs\n";
return false;
}
- if (_compatibilityVersion && _outputFileType != llvm::MachO::MH_DYLIB) {
+ if (_compatibilityVersion && _outputFileType != MH_DYLIB) {
diagnostics
<< "error: -compatibility_version can only be used with dylibs\n";
return false;
}
- if (_deadStrippableDylib && _outputFileType != llvm::MachO::MH_DYLIB) {
+ if (_deadStrippableDylib && _outputFileType != MH_DYLIB) {
diagnostics
<< "error: -mark_dead_strippable_dylib can only be used with dylibs.\n";
return false;
}
- if (!_bundleLoader.empty() && outputFileType() != llvm::MachO::MH_BUNDLE) {
+ if (!_bundleLoader.empty() && outputFileType() != MH_BUNDLE) {
diagnostics
<< "error: -bundle_loader can only be used with Mach-O bundles\n";
return false;
@@ -238,8 +274,10 @@
}
void MachOLinkingContext::addPasses(PassManager &pm) {
- pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass));
- pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this)));
+ 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)));
+ }
pm.add(std::unique_ptr<Pass>(new LayoutPass()));
}