summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/include/lld/ReaderWriter/MachOLinkingContext.h1
-rw-r--r--lld/lib/Driver/DarwinLdDriver.cpp14
-rw-r--r--lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp5
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFile.h2
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp73
-rw-r--r--lld/test/mach-o/infer-arch.yaml29
-rw-r--r--lld/unittests/DriverTests/DarwinLdDriverTest.cpp70
7 files changed, 145 insertions, 49 deletions
diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h
index 8cff3ea5ed8..58fd886424d 100644
--- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h
+++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -222,6 +222,7 @@ public:
/// Creates a copy (owned by this MachOLinkingContext) of a string.
StringRef copy(StringRef str) { return str.copy(_allocator); }
+ static bool isThinObjectFile(StringRef path, Arch &arch);
static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
static Arch archFromName(StringRef archName);
static StringRef nameFromArch(Arch arch);
diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp
index 259cf758c79..79cf242cbaa 100644
--- a/lld/lib/Driver/DarwinLdDriver.cpp
+++ b/lld/lib/Driver/DarwinLdDriver.cpp
@@ -243,6 +243,20 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
return false;
}
}
+ // If no -arch specified, scan input files to find first non-fat .o file.
+ if ((arch == MachOLinkingContext::arch_unknown)
+ && !parsedArgs->getLastArg(OPT_test_file_usage)) {
+ for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) {
+ // This is expensive because it opens and maps the file. But that is
+ // ok because no -arch is rare.
+ if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch))
+ break;
+ }
+ if (arch == MachOLinkingContext::arch_unknown) {
+ diagnostics << "error: -arch not specified and could not be inferred\n";
+ return false;
+ }
+ }
// Handle -macosx_version_min or -ios_version_min
MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX;
diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 4ef1b625c4c..4d2304a73d8 100644
--- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -11,6 +11,7 @@
#include "ArchHandler.h"
#include "File.h"
+#include "MachONormalizedFile.h"
#include "MachOPasses.h"
#include "lld/Core/PassManager.h"
@@ -125,6 +126,10 @@ uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
llvm_unreachable("Unknown arch type");
}
+bool MachOLinkingContext::isThinObjectFile(StringRef path, Arch &arch) {
+ return mach_o::normalized::isThinObjectFile(path, arch);
+}
+
MachOLinkingContext::MachOLinkingContext()
: _outputMachOType(MH_EXECUTE), _outputMachOTypeStatic(false),
_doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
index c6e2a3a9b75..441bf45299a 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
@@ -252,6 +252,8 @@ struct NormalizedFile {
BumpPtrAllocator ownedAllocations;
};
+/// Tests if a file is a non-fat mach-o object file.
+bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch);
/// Reads a mach-o file and produces an in-memory normalized view.
ErrorOr<std::unique_ptr<NormalizedFile>>
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
index 6fcee3bf059..9997ca0245c 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -117,6 +117,59 @@ template <typename T> static T readBigEndian(T t) {
return t;
}
+
+static bool isMachOHeader(const mach_header *mh, bool &is64, bool &swap) {
+ switch (mh->magic) {
+ case llvm::MachO::MH_MAGIC:
+ is64 = false;
+ swap = false;
+ return true;
+ case llvm::MachO::MH_MAGIC_64:
+ is64 = true;
+ swap = false;
+ return true;
+ case llvm::MachO::MH_CIGAM:
+ is64 = false;
+ swap = true;
+ return true;
+ case llvm::MachO::MH_CIGAM_64:
+ is64 = true;
+ swap = true;
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) {
+ // Try opening and mapping file at path.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> b = MemoryBuffer::getFileOrSTDIN(path);
+ if (b.getError())
+ return false;
+
+ // If file length < 32 it is too small to be mach-o object file.
+ StringRef fileBuffer = b->get()->getBuffer();
+ if (fileBuffer.size() < 32)
+ return false;
+
+ // If file buffer does not start with MH_MAGIC (and variants), not obj file.
+ const mach_header *mh = reinterpret_cast<const mach_header *>(
+ fileBuffer.begin());
+ bool is64, swap;
+ if (!isMachOHeader(mh, is64, swap))
+ return false;
+
+ // If not MH_OBJECT, not object file.
+ if (read32(swap, mh->filetype) != MH_OBJECT)
+ return false;
+
+ // Lookup up arch from cpu/subtype pair.
+ arch = MachOLinkingContext::archFromCpuType(read32(swap, mh->cputype),
+ read32(swap, mh->cpusubtype));
+ return true;
+}
+
/// Reads a mach-o file and produces an in-memory normalized view.
ErrorOr<std::unique_ptr<NormalizedFile>>
readBinary(std::unique_ptr<MemoryBuffer> &mb,
@@ -162,26 +215,8 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
}
bool is64, swap;
- switch (mh->magic) {
- case llvm::MachO::MH_MAGIC:
- is64 = false;
- swap = false;
- break;
- case llvm::MachO::MH_MAGIC_64:
- is64 = true;
- swap = false;
- break;
- case llvm::MachO::MH_CIGAM:
- is64 = false;
- swap = true;
- break;
- case llvm::MachO::MH_CIGAM_64:
- is64 = true;
- swap = true;
- break;
- default:
+ if (!isMachOHeader(mh, is64, swap))
return make_error_code(llvm::errc::executable_format_error);
- }
// Endian swap header, if needed.
mach_header headerCopy;
diff --git a/lld/test/mach-o/infer-arch.yaml b/lld/test/mach-o/infer-arch.yaml
new file mode 100644
index 00000000000..94f8543bd72
--- /dev/null
+++ b/lld/test/mach-o/infer-arch.yaml
@@ -0,0 +1,29 @@
+# RUN: lld -flavor darwin -arch i386 -macosx_version_min 10.8 %s -r -o %t \
+# RUN: && lld -flavor darwin -r %t -o %t2 -print_atoms | FileCheck %s
+#
+# Test linker can detect architecture without -arch option.
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3 ]
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+...
+
+
+# CHECK: defined-atoms:
+# CHECK: - name: _foo
diff --git a/lld/unittests/DriverTests/DarwinLdDriverTest.cpp b/lld/unittests/DriverTests/DarwinLdDriverTest.cpp
index cf0da9dd099..c159fd8fd4a 100644
--- a/lld/unittests/DriverTests/DarwinLdDriverTest.cpp
+++ b/lld/unittests/DriverTests/DarwinLdDriverTest.cpp
@@ -30,7 +30,7 @@ protected:
}
TEST_F(DarwinLdParserTest, Basic) {
- EXPECT_TRUE(parse("ld", "foo.o", "bar.o", nullptr));
+ EXPECT_TRUE(parse("ld", "foo.o", "bar.o", "-arch", "i386", nullptr));
EXPECT_FALSE(_context.allowRemainingUndefines());
EXPECT_FALSE(_context.deadStrip());
EXPECT_EQ(2, inputFileCount());
@@ -39,45 +39,40 @@ TEST_F(DarwinLdParserTest, Basic) {
}
TEST_F(DarwinLdParserTest, Output) {
- EXPECT_TRUE(parse("ld", "-o", "my.out", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-o", "my.out", "foo.o", "-arch", "i386", nullptr));
EXPECT_EQ("my.out", _context.outputPath());
}
TEST_F(DarwinLdParserTest, Dylib) {
- EXPECT_TRUE(parse("ld", "-dylib", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-dylib", "foo.o", "-arch", "i386", nullptr));
EXPECT_EQ(llvm::MachO::MH_DYLIB, _context.outputMachOType());
}
TEST_F(DarwinLdParserTest, Relocatable) {
- EXPECT_TRUE(parse("ld", "-r", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-r", "foo.o", "-arch", "i386", nullptr));
EXPECT_EQ(llvm::MachO::MH_OBJECT, _context.outputMachOType());
}
TEST_F(DarwinLdParserTest, Bundle) {
- EXPECT_TRUE(parse("ld", "-bundle", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-bundle", "foo.o", "-arch", "i386", nullptr));
EXPECT_EQ(llvm::MachO::MH_BUNDLE, _context.outputMachOType());
}
TEST_F(DarwinLdParserTest, Preload) {
- EXPECT_TRUE(parse("ld", "-preload", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-preload", "foo.o", "-arch", "i386", nullptr));
EXPECT_EQ(llvm::MachO::MH_PRELOAD, _context.outputMachOType());
}
TEST_F(DarwinLdParserTest, Static) {
- EXPECT_TRUE(parse("ld", "-static", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-static", "foo.o", "-arch", "i386", nullptr));
EXPECT_EQ(llvm::MachO::MH_EXECUTE, _context.outputMachOType());
}
TEST_F(DarwinLdParserTest, Entry) {
- EXPECT_TRUE(parse("ld", "-e", "entryFunc", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-e", "entryFunc", "foo.o", "-arch", "i386",nullptr));
EXPECT_EQ("entryFunc", _context.entrySymbolName());
}
-TEST_F(DarwinLdParserTest, OutputPath) {
- EXPECT_TRUE(parse("ld", "-o", "foo", "foo.o", nullptr));
- EXPECT_EQ("foo", _context.outputPath());
-}
-
TEST_F(DarwinLdParserTest, DeadStrip) {
EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-dead_strip", "foo.o", nullptr));
EXPECT_TRUE(_context.deadStrip());
@@ -130,42 +125,48 @@ TEST_F(DarwinLdParserTest, Arch_armv7s) {
}
TEST_F(DarwinLdParserTest, MinMacOSX10_7) {
- EXPECT_TRUE(parse("ld", "-macosx_version_min", "10.7", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-macosx_version_min", "10.7", "foo.o",
+ "-arch", "x86_64", nullptr));
EXPECT_EQ(MachOLinkingContext::OS::macOSX, _context.os());
EXPECT_TRUE(_context.minOS("10.7", ""));
EXPECT_FALSE(_context.minOS("10.8", ""));
}
TEST_F(DarwinLdParserTest, MinMacOSX10_8) {
- EXPECT_TRUE(parse("ld", "-macosx_version_min", "10.8.3", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-macosx_version_min", "10.8.3", "foo.o",
+ "-arch", "x86_64", nullptr));
EXPECT_EQ(MachOLinkingContext::OS::macOSX, _context.os());
EXPECT_TRUE(_context.minOS("10.7", ""));
EXPECT_TRUE(_context.minOS("10.8", ""));
}
TEST_F(DarwinLdParserTest, iOS5) {
- EXPECT_TRUE(parse("ld", "-ios_version_min", "5.0", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-ios_version_min", "5.0", "foo.o",
+ "-arch", "armv7", nullptr));
EXPECT_EQ(MachOLinkingContext::OS::iOS, _context.os());
EXPECT_TRUE(_context.minOS("", "5.0"));
EXPECT_FALSE(_context.minOS("", "6.0"));
}
TEST_F(DarwinLdParserTest, iOS6) {
- EXPECT_TRUE(parse("ld", "-ios_version_min", "6.0", "foo.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-ios_version_min", "6.0", "foo.o", "-arch", "armv7",
+ nullptr));
EXPECT_EQ(MachOLinkingContext::OS::iOS, _context.os());
EXPECT_TRUE(_context.minOS("", "5.0"));
EXPECT_TRUE(_context.minOS("", "6.0"));
}
TEST_F(DarwinLdParserTest, iOS_Simulator5) {
- EXPECT_TRUE(parse("ld", "-ios_simulator_version_min", "5.0", "a.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-ios_simulator_version_min", "5.0", "a.o",
+ "-arch", "i386", nullptr));
EXPECT_EQ(MachOLinkingContext::OS::iOS_simulator, _context.os());
EXPECT_TRUE(_context.minOS("", "5.0"));
EXPECT_FALSE(_context.minOS("", "6.0"));
}
TEST_F(DarwinLdParserTest, iOS_Simulator6) {
- EXPECT_TRUE(parse("ld", "-ios_simulator_version_min", "6.0", "a.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-ios_simulator_version_min", "6.0", "a.o",
+ "-arch", "i386", nullptr));
EXPECT_EQ(MachOLinkingContext::OS::iOS_simulator, _context.os());
EXPECT_TRUE(_context.minOS("", "5.0"));
EXPECT_TRUE(_context.minOS("", "6.0"));
@@ -173,58 +174,67 @@ TEST_F(DarwinLdParserTest, iOS_Simulator6) {
TEST_F(DarwinLdParserTest, compatibilityVersion) {
EXPECT_TRUE(
- parse("ld", "-dylib", "-compatibility_version", "1.2.3", "a.o", nullptr));
+ parse("ld", "-dylib", "-compatibility_version", "1.2.3", "a.o",
+ "-arch", "i386",nullptr));
EXPECT_EQ(_context.compatibilityVersion(), 0x10203U);
}
TEST_F(DarwinLdParserTest, compatibilityVersionInvalidType) {
EXPECT_FALSE(parse("ld", "-bundle", "-compatibility_version", "1.2.3", "a.o",
- nullptr));
+ "-arch", "i386",nullptr));
}
TEST_F(DarwinLdParserTest, compatibilityVersionInvalidValue) {
EXPECT_FALSE(parse("ld", "-bundle", "-compatibility_version", "1,2,3", "a.o",
- nullptr));
+ "-arch", "i386", nullptr));
}
TEST_F(DarwinLdParserTest, currentVersion) {
EXPECT_TRUE(
- parse("ld", "-dylib", "-current_version", "1.2.3", "a.o", nullptr));
+ parse("ld", "-dylib", "-current_version", "1.2.3", "a.o", "-arch", "i386",
+ nullptr));
EXPECT_EQ(_context.currentVersion(), 0x10203U);
}
TEST_F(DarwinLdParserTest, currentVersionInvalidType) {
EXPECT_FALSE(
- parse("ld", "-bundle", "-current_version", "1.2.3", "a.o", nullptr));
+ parse("ld", "-bundle", "-current_version", "1.2.3", "a.o",
+ "-arch", "i386", nullptr));
}
TEST_F(DarwinLdParserTest, currentVersionInvalidValue) {
EXPECT_FALSE(
- parse("ld", "-bundle", "-current_version", "1,2,3", "a.o", nullptr));
+ parse("ld", "-bundle", "-current_version", "1,2,3", "a.o",
+ "-arch", "i386", nullptr));
}
TEST_F(DarwinLdParserTest, bundleLoader) {
EXPECT_TRUE(
- parse("ld", "-bundle", "-bundle_loader", "/bin/ls", "a.o", nullptr));
+ parse("ld", "-bundle", "-bundle_loader", "/bin/ls", "a.o",
+ "-arch", "i386", nullptr));
EXPECT_EQ(_context.bundleLoader(), "/bin/ls");
}
TEST_F(DarwinLdParserTest, bundleLoaderInvalidType) {
- EXPECT_FALSE(parse("ld", "-bundle_loader", "/bin/ls", "a.o", nullptr));
+ EXPECT_FALSE(parse("ld", "-bundle_loader", "/bin/ls", "a.o", "-arch", "i386",
+ nullptr));
}
TEST_F(DarwinLdParserTest, deadStrippableDylib) {
EXPECT_TRUE(
- parse("ld", "-dylib", "-mark_dead_strippable_dylib", "a.o", nullptr));
+ parse("ld", "-dylib", "-mark_dead_strippable_dylib", "a.o",
+ "-arch", "i386", nullptr));
EXPECT_EQ(true, _context.deadStrippableDylib());
}
TEST_F(DarwinLdParserTest, deadStrippableDylibInvalidType) {
- EXPECT_FALSE(parse("ld", "-mark_dead_strippable_dylib", "a.o", nullptr));
+ EXPECT_FALSE(parse("ld", "-mark_dead_strippable_dylib", "a.o",
+ "-arch", "i386", nullptr));
}
TEST_F(DarwinLdParserTest, llvmOptions) {
- EXPECT_TRUE(parse("ld", "-mllvm", "-debug-only", "-mllvm", "foo", "a.o", nullptr));
+ EXPECT_TRUE(parse("ld", "-mllvm", "-debug-only", "-mllvm", "foo", "a.o",
+ "-arch", "i386", nullptr));
const std::vector<const char *> &options = _context.llvmOptions();
EXPECT_EQ(options.size(), 2UL);
EXPECT_EQ(strcmp(options[0],"-debug-only"), 0);
OpenPOWER on IntegriCloud