[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