diff options
| -rw-r--r-- | lld/include/lld/ReaderWriter/MachOLinkingContext.h | 1 | ||||
| -rw-r--r-- | lld/lib/Driver/DarwinLdDriver.cpp | 14 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp | 5 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFile.h | 2 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp | 73 | ||||
| -rw-r--r-- | lld/test/mach-o/infer-arch.yaml | 29 | ||||
| -rw-r--r-- | lld/unittests/DriverTests/DarwinLdDriverTest.cpp | 70 |
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); |

