[lld] r217189 - [mach-o] Let darwin driver infer arch from .o files if -arch not used.
Shankar Easwaran
shankare at codeaurora.org
Thu Sep 4 14:17:08 PDT 2014
Nice!
Is this applicable in partial linking mode ?
What if the first file was an archive file or a script (that could
contain more inputs) ?
I think its better to get the first file from the input graph and query
for the arch type ?
Shankar Easwaran
On 9/4/2014 3:08 PM, Nick Kledzik wrote:
> 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);
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation
More information about the llvm-commits
mailing list