[lld] r217189 - [mach-o] Let darwin driver infer arch from .o files if -arch not used.
Nick Kledzik
kledzik at apple.com
Thu Sep 4 13:08:31 PDT 2014
Author: kledzik
Date: Thu Sep 4 15:08:30 2014
New Revision: 217189
URL: http://llvm.org/viewvc/llvm-project?rev=217189&view=rev
Log:
[mach-o] Let darwin driver infer arch from .o files if -arch not used.
Mach-O has a "fat" (or "universal") variant where the same contents built for
different architectures are concatenated into one file with a table-of-contents
header at the start. But this leaves a dilemma for the linker - which
architecture to use.
Normally, the linker command line -arch is used to force which slice of any fat
files are used. The clang compiler always passes -arch to the linker when
invoking it. But some Makefiles invoke the linker directly and don’t specify
the -arch option. For those cases, the linker scans all input files in command
line order and finds the first non-fat object file. Whatever architecture it
is becomes the architecture for the link.
Added:
lld/trunk/test/mach-o/infer-arch.yaml
Modified:
lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
lld/trunk/lib/Driver/DarwinLdDriver.cpp
lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
lld/trunk/unittests/DriverTests/DarwinLdDriverTest.cpp
Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=217189&r1=217188&r2=217189&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Thu Sep 4 15:08:30 2014
@@ -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);
Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=217189&r1=217188&r2=217189&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Thu Sep 4 15:08:30 2014
@@ -243,6 +243,20 @@ bool DarwinLdDriver::parse(int argc, con
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;
Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=217189&r1=217188&r2=217189&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Thu Sep 4 15:08:30 2014
@@ -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::cpuSubtype
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),
Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h?rev=217189&r1=217188&r2=217189&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h Thu Sep 4 15:08:30 2014
@@ -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>>
Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp?rev=217189&r1=217188&r2=217189&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp Thu Sep 4 15:08:30 2014
@@ -117,6 +117,59 @@ template <typename T> static T readBigEn
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>
}
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;
Added: lld/trunk/test/mach-o/infer-arch.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/infer-arch.yaml?rev=217189&view=auto
==============================================================================
--- lld/trunk/test/mach-o/infer-arch.yaml (added)
+++ lld/trunk/test/mach-o/infer-arch.yaml Thu Sep 4 15:08:30 2014
@@ -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
Modified: lld/trunk/unittests/DriverTests/DarwinLdDriverTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/DarwinLdDriverTest.cpp?rev=217189&r1=217188&r2=217189&view=diff
==============================================================================
--- lld/trunk/unittests/DriverTests/DarwinLdDriverTest.cpp (original)
+++ lld/trunk/unittests/DriverTests/DarwinLdDriverTest.cpp Thu Sep 4 15:08:30 2014
@@ -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_Simulator
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);
More information about the llvm-commits
mailing list