<NME> MachOLinkingContext.cpp
<BEF> //===- lib/ReaderWriter/MachO/MachOLinkingContext.cpp ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lld/Common/ErrorHandler.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "ArchHandler.h"
#include "File.h"
#include "FlatNamespaceFile.h"
#include "MachONormalizedFile.h"
#include "MachOPasses.h"
#include "SectCreateFile.h"
#include "lld/Common/Driver.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Reader.h"
#include "lld/Core/Writer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"

namespace lld {

MachOLinkingContext::PackedVersion::PackedVersion(StringRef str) {
  if (parse(str, *this))
    llvm_unreachable("bad version string");
}

/// Construct 32-bit PackedVersion from string "X.Y.Z" where
/// bits are xxxx.yy.zz.  Largest number is 65535.255.255
bool MachOLinkingContext::PackedVersion::parse(
    StringRef str, MachOLinkingContext::PackedVersion &result) {
  result._value = 0;

  if (str.empty())
    return false;
using lld::mach_o::ArchHandler;
using lld::mach_o::MachOFile;
using lld::mach_o::MachODylibFile;
using namespace llvm::MachO;

namespace lld {
    return true;
  if (num > 65535)
    return true;
  result._value = num << 16;

  if (parts.size() > 1) {
    if (llvm::getAsUnsignedInteger(parts[1], 10, num))
      return true;
    if (num > 255)
      return true;
    result._value |= (num << 8);
  }

  if (parts.size() > 2) {
    return true;
      return true;
    if (num > 255)
      return true;
    result._value |= num;
  }

  return false;
}

bool MachOLinkingContext::PackedVersion::
operator<(const PackedVersion &rhs) const {
  return _value < rhs._value;
}

bool MachOLinkingContext::PackedVersion::
operator>=(const PackedVersion &rhs) const {
  return _value >= rhs._value;
}

bool MachOLinkingContext::PackedVersion::
operator==(const PackedVersion &rhs) const {
  return _value == rhs._value;
}

struct ArchInfo {
  StringRef archName;
  MachOLinkingContext::Arch arch;
      return true;
    if (num > 255)
      return true;
    result |= num;
  }

  return false;
}

bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) {
  result = 0;

  if (str.empty())
    return false;

  SmallVector<StringRef, 5> parts;
  llvm::SplitString(str, parts, ".");

  unsigned long long num;
  if (llvm::getAsUnsignedInteger(parts[0], 10, num))
    return true;
  if (num > 0xFFFFFF)
    return true;
  result = num << 40;

  unsigned Shift = 30;
  for (StringRef str : llvm::makeArrayRef(parts).slice(1)) {
    if (llvm::getAsUnsignedInteger(str, 10, num))
      return true;
    if (num > 0x3FF)
      return true;
    result |= (num << Shift);
    Shift -= 10;
  }

  return false;
}

MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
  { "x86_64", arch_x86_64, true,  CPU_TYPE_X86_64,  CPU_SUBTYPE_X86_64_ALL },
  { "i386",   arch_x86,    true,  CPU_TYPE_I386,    CPU_SUBTYPE_X86_ALL },
  { "ppc",    arch_ppc,    false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL },
  { "armv6",  arch_armv6,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V6 },
  { "armv7",  arch_armv7,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7 },
  { "armv7s", arch_armv7s, true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7S },
  { "arm64",  arch_arm64,  true,  CPU_TYPE_ARM64,   CPU_SUBTYPE_ARM64_ALL },
  { "",       arch_unknown,false, 0,                0 }
};

MachOLinkingContext::Arch
MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {
  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
    if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype))
      return info->arch;
  }
  return arch_unknown;
}

MachOLinkingContext::MachOLinkingContext()
    : _outputFileType(mach_o::MH_EXECUTE), _outputFileTypeStatic(false),
      _doNothing(false), _arch(arch_unknown), _os(OS::macOSX),
      _osMinVersion("0.0"), _pageZeroSize(0x1000), _kindHandler(nullptr) {}

MachOLinkingContext::~MachOLinkingContext() {}

}

StringRef MachOLinkingContext::nameFromArch(Arch arch) {
  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
    if (info->arch == arch)
      return info->archName;
  }
  return "<unknown>";
}

uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {
  assert(arch != arch_unknown);
  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
    if (info->arch == arch)
      return info->cputype;
  }
  llvm_unreachable("Unknown arch type");
}

bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
  switch (_os) {
  case OS::macOSX:
    return (_osMinVersion >= PackedVersion(mac));
  case OS::iOS:
  case OS::iOS_simulator:
    return (_osMinVersion >= PackedVersion(iOS));
  }
  llvm_unreachable("target not configured for iOS or MacOSX");
}
MachOLinkingContext::MachOLinkingContext() {}

MachOLinkingContext::~MachOLinkingContext() {
  // Atoms are allocated on BumpPtrAllocator's on File's.
  // As we transfer atoms from one file to another, we need to clear all of the
  // atoms before we remove any of the BumpPtrAllocator's.
  auto &nodes = getNodes();
  for (unsigned i = 0, e = nodes.size(); i != e; ++i) {
    FileNode *node = dyn_cast<FileNode>(nodes[i].get());
    if (!node)
      continue;
    File *file = node->getFile();
    file->clearAtoms();
  }
}

void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
                                    uint32_t minOSVersion,
                                    bool exportDynamicSymbols) {
  _outputMachOType = type;
  _arch = arch;
  _os = os;
  _osMinVersion = minOSVersion;

  // If min OS not specified on command line, use reasonable defaults.
  // Note that we only do sensible defaults when emitting something other than
  // object and preload.
  if (_outputMachOType != llvm::MachO::MH_OBJECT &&
      _outputMachOType != llvm::MachO::MH_PRELOAD) {
    if (minOSVersion == 0) {
      switch (_arch) {
      case arch_x86_64:
      case arch_x86:
        parsePackedVersion("10.8", _osMinVersion);
        _os = MachOLinkingContext::OS::macOSX;
        break;
      case arch_armv6:
      case arch_armv7:
      case arch_armv7s:
      case arch_arm64:
        parsePackedVersion("7.0", _osMinVersion);

bool MachOLinkingContext::setOS(OS os, StringRef minOSVersion) {
  _os = os;
  return PackedVersion::parse(minOSVersion, _osMinVersion);
}

void MachOLinkingContext::addPasses(PassManager &pm) const {

  switch (_outputMachOType) {
  case llvm::MachO::MH_EXECUTE:
    // If targeting newer OS, use _main
    if (minOS("10.8", "6.0")) {
      _entrySymbolName = "_main";
    } else {
      // If targeting older OS, use start (in crt1.o)
      _entrySymbolName = "start";
    }

    // __PAGEZERO defaults to 4GB on 64-bit (except for PP64 which lld does not
    // support) and 4KB on 32-bit.
    if (is64Bit(_arch)) {
      _pageZeroSize = 0x100000000;
    } else {
      _pageZeroSize = 0x1000;
    }

    // Initial base address is __PAGEZERO size.
    _baseAddress = _pageZeroSize;

    // Make PIE by default when targetting newer OSs.
    switch (os) {
      case OS::macOSX:
        if (minOSVersion >= 0x000A0700) // MacOSX 10.7
          _pie = true;
        break;
      case OS::iOS:
        if (minOSVersion >= 0x00040300) // iOS 4.3
          _pie = true;
       break;
       case OS::iOS_simulator:
        _pie = true;
       break;
       case OS::unknown:
       break;
    }
    setGlobalsAreDeadStripRoots(exportDynamicSymbols);
    break;
  case llvm::MachO::MH_DYLIB:
    setGlobalsAreDeadStripRoots(exportDynamicSymbols);
    break;
  case llvm::MachO::MH_BUNDLE:
    break;
  case llvm::MachO::MH_OBJECT:
    _printRemainingUndefines = false;
    _allowRemainingUndefines = true;
    break;
  default:
    break;
  }

  // Set default segment page sizes based on arch.
  if (arch == arch_arm64)
    _pageSize = 4*4096;
}

uint32_t MachOLinkingContext::getCPUType() const {
  return cpuTypeFromArch(_arch);
}

uint32_t MachOLinkingContext::getCPUSubType() const {
  return cpuSubtypeFromArch(_arch);
}

bool MachOLinkingContext::is64Bit(Arch arch) {
  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
    if (info->arch == arch) {
      return (info->cputype & CPU_ARCH_ABI64);
    }
  }
  // unknown archs are not 64-bit.
  return false;
}

bool MachOLinkingContext::isHostEndian(Arch arch) {
  assert(arch != arch_unknown);
  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
    if (info->arch == arch) {
      return (info->littleEndian == llvm::sys::IsLittleEndianHost);
    }
  }
  llvm_unreachable("Unknown arch type");
}

bool MachOLinkingContext::isBigEndian(Arch arch) {
  assert(arch != arch_unknown);
  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
    if (info->arch == arch) {
      return ! info->littleEndian;
    }
  }
  llvm_unreachable("Unknown arch type");
}

bool MachOLinkingContext::is64Bit() const {
  return is64Bit(_arch);
}

bool MachOLinkingContext::outputTypeHasEntry() const {
  switch (_outputMachOType) {
  case MH_EXECUTE:
  case MH_DYLINKER:
  case MH_PRELOAD:
    return true;
  default:
    return false;
  }
}

bool MachOLinkingContext::needsStubsPass() const {
  switch (_outputMachOType) {
  case MH_EXECUTE:
    return !_outputMachOTypeStatic;
  case MH_DYLIB:
  case MH_BUNDLE:
    return true;
  default:
    return false;
  }
}

bool MachOLinkingContext::needsGOTPass() const {
  // GOT pass not used in -r mode.
  if (_outputMachOType == MH_OBJECT)
    return false;
  // Only some arches use GOT pass.
  switch (_arch) {
    case arch_x86_64:
    case arch_arm64:
      return true;
    default:
      return false;
  }
}

bool MachOLinkingContext::needsCompactUnwindPass() const {
  switch (_outputMachOType) {
  case MH_EXECUTE:
  case MH_DYLIB:
  case MH_BUNDLE:
    return archHandler().needsCompactUnwind();
  default:
    return false;
  }
}

bool MachOLinkingContext::needsObjCPass() const {
  // ObjC pass is only needed if any of the inputs were ObjC.
  return _objcConstraint != objc_unknown;
}

bool MachOLinkingContext::needsShimPass() const {
  // Shim pass only used in final executables.
  if (_outputMachOType == MH_OBJECT)
    return false;
  // Only 32-bit arm arches use Shim pass.
  switch (_arch) {
  case arch_armv6:
  case arch_armv7:
  case arch_armv7s:
    return true;
  default:
    return false;
  }
}

bool MachOLinkingContext::needsTLVPass() const {
  switch (_outputMachOType) {
  case MH_BUNDLE:
  case MH_EXECUTE:
  case MH_DYLIB:
    return true;
  default:
    return false;
  }
}

StringRef MachOLinkingContext::binderSymbolName() const {
  return archHandler().stubInfo().binderSymbolName;
}

bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
  uint32_t parsedVersion;
  switch (_os) {
  case OS::macOSX:
    if (parsePackedVersion(mac, parsedVersion))
      return false;
    return _osMinVersion >= parsedVersion;
  case OS::iOS:
  case OS::iOS_simulator:
    if (parsePackedVersion(iOS, parsedVersion))
      return false;
    return _osMinVersion >= parsedVersion;
  case OS::unknown:
    // If we don't know the target, then assume that we don't meet the min OS.
    // This matches the ld64 behaviour
    return false;
  }
  llvm_unreachable("invalid OS enum");
}

bool MachOLinkingContext::addEntryPointLoadCommand() const {
  if ((_outputMachOType == MH_EXECUTE) && !_outputMachOTypeStatic) {
    return minOS("10.8", "6.0");
  }
  return false;
}

bool MachOLinkingContext::addUnixThreadLoadCommand() const {
  switch (_outputMachOType) {
  case MH_EXECUTE:
    if (_outputMachOTypeStatic)
      return true;
    else
      return !minOS("10.8", "6.0");
    break;
  case MH_DYLINKER:
  case MH_PRELOAD:
    return true;
  default:
    return false;
  }
}

bool MachOLinkingContext::pathExists(StringRef path) const {
  if (!_testingFileUsage)
    return llvm::sys::fs::exists(path.str());

  // Otherwise, we're in test mode: only files explicitly provided on the
  // command-line exist.
  std::string key = path.str();
  std::replace(key.begin(), key.end(), '\\', '/');
  return _existingPaths.find(key) != _existingPaths.end();
}

bool MachOLinkingContext::fileExists(StringRef path) const {
  bool found = pathExists(path);
  // Log search misses.
  if (!found)
    addInputFileNotFound(path);

  // When testing, file is never opened, so logging is done here.
  if (_testingFileUsage && found)
    addInputFileDependency(path);

  return found;
}

void MachOLinkingContext::setSysLibRoots(const StringRefVector &paths) {
  _syslibRoots = paths;
}

void MachOLinkingContext::addRpath(StringRef rpath) {
  _rpaths.push_back(rpath);
}

void MachOLinkingContext::addModifiedSearchDir(StringRef libPath,
                                               bool isSystemPath) {
  bool addedModifiedPath = false;

  // -syslibroot only applies to absolute paths.
  if (libPath.startswith("/")) {
    for (auto syslibRoot : _syslibRoots) {
      SmallString<256> path(syslibRoot);
      llvm::sys::path::append(path, libPath);
      if (pathExists(path)) {
        _searchDirs.push_back(path.str().copy(_allocator));
        addedModifiedPath = true;
      }
    }
  }

  if (addedModifiedPath)
    return;

  // Finally, if only one -syslibroot is given, system paths which aren't in it
  // get suppressed.
  if (_syslibRoots.size() != 1 || !isSystemPath) {
    if (pathExists(libPath)) {
      _searchDirs.push_back(libPath);
    }
  }
}

void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,
                                                bool isSystemPath) {
  bool pathAdded = false;

  // -syslibroot only used with to absolute framework search paths.
  if (fwPath.startswith("/")) {
    for (auto syslibRoot : _syslibRoots) {
      SmallString<256> path(syslibRoot);
      llvm::sys::path::append(path, fwPath);
      if (pathExists(path)) {
        _frameworkDirs.push_back(path.str().copy(_allocator));
        pathAdded = true;
      }
    }
  }
  // If fwPath found in any -syslibroot, then done.
  if (pathAdded)
    return;

  // If only one -syslibroot, system paths not in that SDK are suppressed.
  if (isSystemPath && (_syslibRoots.size() == 1))
    return;

  // Only use raw fwPath if that directory exists.
  if (pathExists(fwPath))
    _frameworkDirs.push_back(fwPath);
}

llvm::Optional<StringRef>
MachOLinkingContext::searchDirForLibrary(StringRef path,
                                         StringRef libName) const {
  SmallString<256> fullPath;
  if (libName.endswith(".o")) {
    // A request ending in .o is special: just search for the file directly.
    fullPath.assign(path);
    llvm::sys::path::append(fullPath, libName);
    if (fileExists(fullPath))
      return fullPath.str().copy(_allocator);
    return llvm::None;
  }

  // Search for dynamic library
  fullPath.assign(path);
  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".dylib");
  if (fileExists(fullPath))
    return fullPath.str().copy(_allocator);

  // If not, try for a static library
  fullPath.assign(path);
  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a");
  if (fileExists(fullPath))
    return fullPath.str().copy(_allocator);

  return llvm::None;
}

llvm::Optional<StringRef>
MachOLinkingContext::searchLibrary(StringRef libName) const {
  SmallString<256> path;
  for (StringRef dir : searchDirs()) {
    llvm::Optional<StringRef> searchDir = searchDirForLibrary(dir, libName);
    if (searchDir)
      return searchDir;
  }

  return llvm::None;
}

llvm::Optional<StringRef>
MachOLinkingContext::findPathForFramework(StringRef fwName) const{
  SmallString<256> fullPath;
  for (StringRef dir : frameworkDirs()) {
    fullPath.assign(dir);
    llvm::sys::path::append(fullPath, Twine(fwName) + ".framework", fwName);
    if (fileExists(fullPath))
      return fullPath.str().copy(_allocator);
  }

  return llvm::None;
}

bool MachOLinkingContext::validateImpl() {
  // TODO: if -arch not specified, look at arch of first .o file.

  if (_currentVersion && _outputMachOType != MH_DYLIB) {
    error("-current_version can only be used with dylibs");
    return false;
  }

  if (_compatibilityVersion && _outputMachOType != MH_DYLIB) {
    error("-compatibility_version can only be used with dylibs");
    return false;
  }

  if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) {
    error("-mark_dead_strippable_dylib can only be used with dylibs");
    return false;
  }

  if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) {
    error("-bundle_loader can only be used with Mach-O bundles");
    return false;
  }

  // If -exported_symbols_list used, all exported symbols must be defined.
  if (_exportMode == ExportMode::whiteList) {
    for (const auto &symbol : _exportedSymbols)
      addInitialUndefinedSymbol(symbol.getKey());
  }

  // If -dead_strip, set up initial live symbols.
  if (deadStrip()) {
    // Entry point is live.
    if (outputTypeHasEntry())
      addDeadStripRoot(entrySymbolName());
    // Lazy binding helper is live.
    if (needsStubsPass())
      addDeadStripRoot(binderSymbolName());
    // If using -exported_symbols_list, make all exported symbols live.
    if (_exportMode == ExportMode::whiteList) {
      setGlobalsAreDeadStripRoots(false);
      for (const auto &symbol : _exportedSymbols)
        addDeadStripRoot(symbol.getKey());
    }
  }

  addOutputFileDependency(outputPath());

  return true;
}

void MachOLinkingContext::addPasses(PassManager &pm) {
  // objc pass should be before layout pass.  Otherwise test cases may contain
  // no atoms which confuses the layout pass.
  if (needsObjCPass())
    mach_o::addObjCPass(pm, *this);
  mach_o::addLayoutPass(pm, *this);
  if (needsStubsPass())
    mach_o::addStubsPass(pm, *this);
  if (needsCompactUnwindPass())
    mach_o::addCompactUnwindPass(pm, *this);
  if (needsGOTPass())
    mach_o::addGOTPass(pm, *this);
  if (needsTLVPass())
    mach_o::addTLVPass(pm, *this);
  if (needsShimPass())
    mach_o::addShimPass(pm, *this); // Shim pass must run after stubs pass.
}

Writer &MachOLinkingContext::writer() const {
  if (!_writer)
    _writer = createWriterMachO(*this);
  return *_writer;
}

ErrorOr<std::unique_ptr<MemoryBuffer>>
MachOLinkingContext::getMemoryBuffer(StringRef path) {
  addInputFileDependency(path);

  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
    MemoryBuffer::getFileOrSTDIN(path);
  if (std::error_code ec = mbOrErr.getError())
    return ec;
  std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());

  // If buffer contains a fat file, find required arch in fat buffer
  // and switch buffer to point to just that required slice.
  uint32_t offset;
  uint32_t size;
  if (sliceFromFatFile(mb->getMemBufferRef(), offset, size))
    return MemoryBuffer::getFileSlice(path, size, offset);
  return std::move(mb);
}

MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {
  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = getMemoryBuffer(path);
  if (mbOrErr.getError())
    return nullptr;

  ErrorOr<std::unique_ptr<File>> fileOrErr =
      registry().loadFile(std::move(mbOrErr.get()));
  if (!fileOrErr)
    return nullptr;
  std::unique_ptr<File> &file = fileOrErr.get();
  file->parse();
  MachODylibFile *result = reinterpret_cast<MachODylibFile *>(file.get());
  // Node object now owned by _indirectDylibs vector.
  _indirectDylibs.push_back(std::move(file));
  return result;
}

MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) {
  // See if already loaded.
  auto pos = _pathToDylibMap.find(path);
  if (pos != _pathToDylibMap.end())
    return pos->second;

  // Search -L paths if of the form "libXXX.dylib"
  std::pair<StringRef, StringRef> split = path.rsplit('/');
  StringRef leafName = split.second;
  if (leafName.startswith("lib") && leafName.endswith(".dylib")) {
    // FIXME: Need to enhance searchLibrary() to only look for .dylib
    auto libPath = searchLibrary(leafName);
    if (libPath)
      return loadIndirectDylib(libPath.getValue());
  }

  // Try full path with sysroot.
  for (StringRef sysPath : _syslibRoots) {
    SmallString<256> fullPath;
    fullPath.assign(sysPath);
    llvm::sys::path::append(fullPath, path);
    if (pathExists(fullPath))
      return loadIndirectDylib(fullPath);
  }

  // Try full path.
  if (pathExists(path)) {
    return loadIndirectDylib(path);
  }

  return nullptr;
}

uint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const {
  auto pos = _pathToDylibMap.find(installName);
  if (pos != _pathToDylibMap.end())
    return pos->second->currentVersion();
  else
    return 0x10000; // 1.0
}

uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {
  auto pos = _pathToDylibMap.find(installName);
  if (pos != _pathToDylibMap.end())
    return pos->second->compatVersion();
  else
    return 0x10000; // 1.0
}

void MachOLinkingContext::createImplicitFiles(
                            std::vector<std::unique_ptr<File> > &result) {
  // Add indirect dylibs by asking each linked dylib to add its indirects.
  // Iterate until no more dylibs get loaded.
  size_t dylibCount = 0;
  while (dylibCount != _allDylibs.size()) {
    dylibCount = _allDylibs.size();
    for (MachODylibFile *dylib : _allDylibs) {
      dylib->loadReExportedDylibs([this] (StringRef path) -> MachODylibFile* {
                                  return findIndirectDylib(path); });
    }
  }

  // Let writer add output type specific extras.
  writer().createImplicitFiles(result);

  // If undefinedMode is != error, add a FlatNamespaceFile instance. This will
  // provide a SharedLibraryAtom for symbols that aren't defined elsewhere.
  if (undefinedMode() != UndefinedMode::error) {
    result.emplace_back(new mach_o::FlatNamespaceFile(*this));
    _flatNamespaceFile = result.back().get();
  }
}

void MachOLinkingContext::registerDylib(MachODylibFile *dylib,
                                        bool upward) const {
  std::lock_guard<std::mutex> lock(_dylibsMutex);

  if (!llvm::count(_allDylibs, dylib))
    _allDylibs.push_back(dylib);
  _pathToDylibMap[dylib->installName()] = dylib;
  // If path is different than install name, register path too.
  if (!dylib->path().equals(dylib->installName()))
    _pathToDylibMap[dylib->path()] = dylib;
  if (upward)
    _upwardDylibs.insert(dylib);
}

bool MachOLinkingContext::isUpwardDylib(StringRef installName) const {
  for (MachODylibFile *dylib : _upwardDylibs) {
    if (dylib->installName().equals(installName))
      return true;
  }
  return false;
}

ArchHandler &MachOLinkingContext::archHandler() const {
  if (!_archHandler)
    _archHandler = ArchHandler::create(_arch);
  return *_archHandler;
}

void MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect,
                                              uint16_t align) {
  SectionAlign entry = { seg, sect, align };
  _sectAligns.push_back(entry);
}

void MachOLinkingContext::addSectCreateSection(
                                        StringRef seg, StringRef sect,
                                        std::unique_ptr<MemoryBuffer> content) {

  if (!_sectCreateFile) {
    auto sectCreateFile = std::make_unique<mach_o::SectCreateFile>();
    _sectCreateFile = sectCreateFile.get();
    getNodes().push_back(std::make_unique<FileNode>(std::move(sectCreateFile)));
  }

  assert(_sectCreateFile && "sectcreate file does not exist.");
  _sectCreateFile->addSection(seg, sect, std::move(content));
}

bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,
                                         uint16_t &align) const {
  for (const SectionAlign &entry : _sectAligns) {
    if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) {
      align = entry.align;
      return true;
    }
  }
  return false;
}

void MachOLinkingContext::addExportSymbol(StringRef sym) {
  // Support old crufty export lists with bogus entries.
  if (sym.endswith(".eh") || sym.startswith(".objc_category_name_")) {
    llvm::errs() << "warning: ignoring " << sym << " in export list\n";
    return;
  }
  // Only i386 MacOSX uses old ABI, so don't change those.
  if ((_os != OS::macOSX) || (_arch != arch_x86)) {
    // ObjC has two differnent ABIs.  Be nice and allow one export list work for
    // both ABIs by renaming symbols.
    if (sym.startswith(".objc_class_name_")) {
      std::string abi2className("_OBJC_CLASS_$_");
      abi2className += sym.substr(17);
      _exportedSymbols.insert(copy(abi2className));
      std::string abi2metaclassName("_OBJC_METACLASS_$_");
      abi2metaclassName += sym.substr(17);
      _exportedSymbols.insert(copy(abi2metaclassName));
      return;
    }
  }

  // FIXME: Support wildcards.
  _exportedSymbols.insert(sym);
}

bool MachOLinkingContext::exportSymbolNamed(StringRef sym) const {
  switch (_exportMode) {
  case ExportMode::globals:
    llvm_unreachable("exportSymbolNamed() should not be called in this mode");
    break;
  case ExportMode::whiteList:
    return _exportedSymbols.count(sym);
  case ExportMode::blackList:
    return !_exportedSymbols.count(sym);
  }
  llvm_unreachable("_exportMode unknown enum value");
}

std::string MachOLinkingContext::demangle(StringRef symbolName) const {
  // Only try to demangle symbols if -demangle on command line
  if (!demangleSymbols())
    return symbolName;

  // Only try to demangle symbols that look like C++ symbols
  if (!symbolName.startswith("__Z"))
    return symbolName;

  SmallString<256> symBuff;
  StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
  // Mach-O has extra leading underscore that needs to be removed.
  const char *cstr = nullTermSym.data() + 1;
  int status;
  char *demangled = llvm::itaniumDemangle(cstr, nullptr, nullptr, &status);
  if (demangled) {
    std::string result(demangled);
    // __cxa_demangle() always uses a malloc'ed buffer to return the result.
    free(demangled);
    return result;
  }

  return symbolName;
}

static void addDependencyInfoHelper(llvm::raw_fd_ostream *DepInfo,
                                    char Opcode, StringRef Path) {
  if (!DepInfo)
    return;

  *DepInfo << Opcode;
  *DepInfo << Path;
  *DepInfo << '\0';
}

std::error_code MachOLinkingContext::createDependencyFile(StringRef path) {
  std::error_code ec;
  _dependencyInfo = std::unique_ptr<llvm::raw_fd_ostream>(
      new llvm::raw_fd_ostream(path, ec, llvm::sys::fs::OF_None));
  if (ec) {
    _dependencyInfo.reset();
    return ec;
  }

  addDependencyInfoHelper(_dependencyInfo.get(), 0x00, "lld" /*FIXME*/);
  return std::error_code();
}

void MachOLinkingContext::addInputFileDependency(StringRef path) const {
  addDependencyInfoHelper(_dependencyInfo.get(), 0x10, path);
}

void MachOLinkingContext::addInputFileNotFound(StringRef path) const {
  addDependencyInfoHelper(_dependencyInfo.get(), 0x11, path);
}

void MachOLinkingContext::addOutputFileDependency(StringRef path) const {
  addDependencyInfoHelper(_dependencyInfo.get(), 0x40, path);
}

void MachOLinkingContext::appendOrderedSymbol(StringRef symbol,
                                              StringRef filename) {
  // To support sorting static functions which may have the same name in
  // multiple .o files, _orderFiles maps the symbol name to a vector
  // of OrderFileNode each of which can specify a file prefix.
  OrderFileNode info;
  if (!filename.empty())
    info.fileFilter = copy(filename);
  info.order = _orderFileEntries++;
  _orderFiles[symbol].push_back(info);
}

bool
MachOLinkingContext::findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
                                      const DefinedAtom *atom,
                                      unsigned &ordinal) {
  const File *objFile = &atom->file();
  assert(objFile);
  StringRef objName = objFile->path();
  std::pair<StringRef, StringRef> dirAndLeaf = objName.rsplit('/');
  if (!dirAndLeaf.second.empty())
    objName = dirAndLeaf.second;
  for (const OrderFileNode &info : nodes) {
    if (info.fileFilter.empty()) {
      // Have unprefixed symbol name in order file that matches this atom.
      ordinal = info.order;
      return true;
    }
    if (info.fileFilter.equals(objName)) {
      // Have prefixed symbol name in order file that matches atom's path.
      ordinal = info.order;
      return true;
    }
  }
  return false;
}

bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left,
                                            const DefinedAtom *right,
                                            bool &leftBeforeRight) const {
  // No custom sorting if no order file entries.
  if (!_orderFileEntries)
    return false;

  // Order files can only order named atoms.
  StringRef leftName = left->name();
  StringRef rightName = right->name();
  if (leftName.empty() || rightName.empty())
    return false;

  // If neither is in order file list, no custom sorter.
  auto leftPos = _orderFiles.find(leftName);
  auto rightPos = _orderFiles.find(rightName);
  bool leftIsOrdered = (leftPos != _orderFiles.end());
  bool rightIsOrdered = (rightPos != _orderFiles.end());
  if (!leftIsOrdered && !rightIsOrdered)
    return false;

  // There could be multiple symbols with same name but different file prefixes.
  unsigned leftOrder;
  unsigned rightOrder;
  bool foundLeft =
      leftIsOrdered && findOrderOrdinal(leftPos->getValue(), left, leftOrder);
  bool foundRight = rightIsOrdered &&
                    findOrderOrdinal(rightPos->getValue(), right, rightOrder);
  if (!foundLeft && !foundRight)
    return false;

  // If only one is in order file list, ordered one goes first.
  if (foundLeft != foundRight)
    leftBeforeRight = foundLeft;
  else
    leftBeforeRight = (leftOrder < rightOrder);

  return true;
}

static bool isLibrary(const std::unique_ptr<Node> &elem) {
  if (FileNode *node = dyn_cast<FileNode>(const_cast<Node *>(elem.get()))) {
    File *file = node->getFile();
    return isa<SharedLibraryFile>(file) || isa<ArchiveLibraryFile>(file);
  }
  return false;
}

// The darwin linker processes input files in two phases.  The first phase
// links in all object (.o) files in command line order. The second phase
// links in libraries in command line order.
// In this function we reorder the input files so that all the object files
// comes before any library file. We also make a group for the library files
// so that the Resolver will reiterate over the libraries as long as we find
// new undefines from libraries.
void MachOLinkingContext::finalizeInputFiles() {
  std::vector<std::unique_ptr<Node>> &elements = getNodes();
  llvm::stable_sort(elements, [](const std::unique_ptr<Node> &a,
                                 const std::unique_ptr<Node> &b) {
    return !isLibrary(a) && isLibrary(b);
  });
  size_t numLibs = std::count_if(elements.begin(), elements.end(), isLibrary);
  elements.push_back(std::make_unique<GroupEnd>(numLibs));
}

llvm::Error MachOLinkingContext::handleLoadedFile(File &file) {
  auto *machoFile = dyn_cast<MachOFile>(&file);
  if (!machoFile)
    return llvm::Error::success();

  // Check that the arch of the context matches that of the file.
  // Also set the arch of the context if it didn't have one.
  if (_arch == arch_unknown) {
    _arch = machoFile->arch();
  } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) {
    // Archs are different.
    return llvm::make_error<GenericError>(file.path() +
                  Twine(" cannot be linked due to incompatible architecture"));
  }

  // Check that the OS of the context matches that of the file.
  // Also set the OS of the context if it didn't have one.
  if (_os == OS::unknown) {
    _os = machoFile->OS();
  } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) {
    // OSes are different.
    return llvm::make_error<GenericError>(file.path() +
              Twine(" cannot be linked due to incompatible operating systems"));
  }

  // Check that if the objc info exists, that it is compatible with the target
  // OS.
  switch (machoFile->objcConstraint()) {
    case objc_unknown:
      // The file is not compiled with objc, so skip the checks.
      break;
    case objc_gc_only:
    case objc_supports_gc:
      llvm_unreachable("GC support should already have thrown an error");
    case objc_retainReleaseForSimulator:
      // The file is built with simulator objc, so make sure that the context
      // is also building with simulator support.
      if (_os != OS::iOS_simulator)
        return llvm::make_error<GenericError>(file.path() +
          Twine(" cannot be linked.  It contains ObjC built for the simulator"
                " while we are linking a non-simulator target"));
      assert((_objcConstraint == objc_unknown ||
              _objcConstraint == objc_retainReleaseForSimulator) &&
             "Must be linking with retain/release for the simulator");
      _objcConstraint = objc_retainReleaseForSimulator;
      break;
    case objc_retainRelease:
      // The file is built without simulator objc, so make sure that the
      // context is also building without simulator support.
      if (_os == OS::iOS_simulator)
        return llvm::make_error<GenericError>(file.path() +
          Twine(" cannot be linked.  It contains ObjC built for a non-simulator"
                " target while we are linking a simulator target"));
      assert((_objcConstraint == objc_unknown ||
              _objcConstraint == objc_retainRelease) &&
             "Must be linking with retain/release for a non-simulator target");
      _objcConstraint = objc_retainRelease;
      break;
  }

  // Check that the swift version of the context matches that of the file.
  // Also set the swift version of the context if it didn't have one.
  if (!_swiftVersion) {
    _swiftVersion = machoFile->swiftVersion();
  } else if (machoFile->swiftVersion() &&
             machoFile->swiftVersion() != _swiftVersion) {
    // Swift versions are different.
    return llvm::make_error<GenericError>("different swift versions");
  }

  return llvm::Error::success();
}

} // end namespace lld

<MSG> Remove PackedVersion from MachOLinkingContext and replace with uint32_t
and a parsePackedVersion() utility.

Patch by Joe Ranieri



git-svn-id: f6089bf0e6284f307027cef4f64114ee9ebb0424@190451 91177308-0d34-0410-b5e6-96231b3b80d8

<DFF> @@ -25,16 +25,8 @@ using lld::mach_o::KindHandler;
 
 namespace lld {
 
-MachOLinkingContext::PackedVersion::PackedVersion(StringRef str) {
-  if (parse(str, *this))
-    llvm_unreachable("bad version string");
-}
-
-/// Construct 32-bit PackedVersion from string "X.Y.Z" where
-/// bits are xxxx.yy.zz.  Largest number is 65535.255.255
-bool MachOLinkingContext::PackedVersion::parse(
-    StringRef str, MachOLinkingContext::PackedVersion &result) {
-  result._value = 0;
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {
+  result = 0;
 
   if (str.empty())
     return false;
@@ -47,14 +39,14 @@ bool MachOLinkingContext::PackedVersion::parse(
     return true;
   if (num > 65535)
     return true;
-  result._value = num << 16;
+  result = num << 16;
 
   if (parts.size() > 1) {
     if (llvm::getAsUnsignedInteger(parts[1], 10, num))
       return true;
     if (num > 255)
       return true;
-    result._value |= (num << 8);
+    result |= (num << 8);
   }
 
   if (parts.size() > 2) {
@@ -62,27 +54,12 @@ bool MachOLinkingContext::PackedVersion::parse(
       return true;
     if (num > 255)
       return true;
-    result._value |= num;
+    result |= num;
   }
 
   return false;
 }
 
-bool MachOLinkingContext::PackedVersion::
-operator<(const PackedVersion &rhs) const {
-  return _value < rhs._value;
-}
-
-bool MachOLinkingContext::PackedVersion::
-operator>=(const PackedVersion &rhs) const {
-  return _value >= rhs._value;
-}
-
-bool MachOLinkingContext::PackedVersion::
-operator==(const PackedVersion &rhs) const {
-  return _value == rhs._value;
-}
-
 struct ArchInfo {
   StringRef archName;
   MachOLinkingContext::Arch arch;
@@ -146,8 +123,8 @@ uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
 
 MachOLinkingContext::MachOLinkingContext()
     : _outputFileType(mach_o::MH_EXECUTE), _outputFileTypeStatic(false),
-      _doNothing(false), _arch(arch_unknown), _os(OS::macOSX),
-      _osMinVersion("0.0"), _pageZeroSize(0x1000), _kindHandler(nullptr) {}
+      _doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
+      _pageZeroSize(0x1000), _kindHandler(nullptr) {}
 
 MachOLinkingContext::~MachOLinkingContext() {}
 
@@ -172,11 +149,19 @@ bool MachOLinkingContext::outputTypeHasEntry() const {
 
 bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
   switch (_os) {
-  case OS::macOSX:
-    return (_osMinVersion >= PackedVersion(mac));
+  case OS::macOSX: {
+    uint32_t parsedVersion;
+    if (parsePackedVersion(mac, parsedVersion))
+      return false;
+    return _osMinVersion >= parsedVersion;
+  }
   case OS::iOS:
-  case OS::iOS_simulator:
-    return (_osMinVersion >= PackedVersion(iOS));
+  case OS::iOS_simulator: {
+    uint32_t parsedVersion;
+    if (parsePackedVersion(iOS, parsedVersion))
+      return false;
+    return _osMinVersion >= parsedVersion;
+  }
   }
   llvm_unreachable("target not configured for iOS or MacOSX");
 }
@@ -224,7 +209,7 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
 
 bool MachOLinkingContext::setOS(OS os, StringRef minOSVersion) {
   _os = os;
-  return PackedVersion::parse(minOSVersion, _osMinVersion);
+  return parsePackedVersion(minOSVersion, _osMinVersion);
 }
 
 void MachOLinkingContext::addPasses(PassManager &pm) const {

{'commit': 'diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h\nindex 0cb3f1561..3ae78665c 100644\n--- a/include/lld/ReaderWriter/MachOLinkingContext.h\n+++ b/include/lld/ReaderWriter/MachOLinkingContext.h\n@@ -77,29 +77,19 @@ public:\n   static uint32_t cpuTypeFromArch(Arch arch);\n   static uint32_t cpuSubtypeFromArch(Arch arch);\n \n+  /// Construct 32-bit value from string "X.Y.Z" where\n+  /// bits are xxxx.yy.zz.  Largest number is 65535.255.255\n+  static bool parsePackedVersion(StringRef str, uint32_t &result);\n+\n private:\n   virtual Writer &writer() const;\n \n-  /// 32-bit packed encoding of "X.Y.Z" where nibbles are xxxx.yy.zz.\n-  struct PackedVersion {\n-    PackedVersion(StringRef);\n-    static bool parse(StringRef, PackedVersion &);\n-    bool operator<(const PackedVersion &) const;\n-    bool operator>=(const PackedVersion &) const;\n-    bool operator==(const PackedVersion &) const;\n-\n-  private:\n-    PackedVersion(uint32_t v) : _value(v) {}\n-\n-    uint32_t _value;\n-  };\n-\n   uint32_t _outputFileType;   // e.g MH_EXECUTE\n   bool _outputFileTypeStatic; // Disambiguate static vs dynamic prog\n   bool _doNothing;            // for -help and -v which just print info\n   Arch _arch;\n   OS _os;\n-  PackedVersion _osMinVersion;\n+  uint32_t _osMinVersion;\n   uint64_t _pageZeroSize;\n   mutable std::unique_ptr<mach_o::KindHandler> _kindHandler;\n   mutable std::unique_ptr<Reader> _machoReader;\ndiff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp\nindex 456f8bd48..9e8601418 100644\n--- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp\n+++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp\n@@ -25,16 +25,8 @@ using lld::mach_o::KindHandler;\n \n namespace lld {\n \n-MachOLinkingContext::PackedVersion::PackedVersion(StringRef str) {\n-  if (parse(str, *this))\n-    llvm_unreachable("bad version string");\n-}\n-\n-/// Construct 32-bit PackedVersion from string "X.Y.Z" where\n-/// bits are xxxx.yy.zz.  Largest number is 65535.255.255\n-bool MachOLinkingContext::PackedVersion::parse(\n-    StringRef str, MachOLinkingContext::PackedVersion &result) {\n-  result._value = 0;\n+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {\n+  result = 0;\n \n   if (str.empty())\n     return false;\n@@ -47,14 +39,14 @@ bool MachOLinkingContext::PackedVersion::parse(\n     return true;\n   if (num > 65535)\n     return true;\n-  result._value = num << 16;\n+  result = num << 16;\n \n   if (parts.size() > 1) {\n     if (llvm::getAsUnsignedInteger(parts[1], 10, num))\n       return true;\n     if (num > 255)\n       return true;\n-    result._value |= (num << 8);\n+    result |= (num << 8);\n   }\n \n   if (parts.size() > 2) {\n@@ -62,27 +54,12 @@ bool MachOLinkingContext::PackedVersion::parse(\n       return true;\n     if (num > 255)\n       return true;\n-    result._value |= num;\n+    result |= num;\n   }\n \n   return false;\n }\n \n-bool MachOLinkingContext::PackedVersion::\n-operator<(const PackedVersion &rhs) const {\n-  return _value < rhs._value;\n-}\n-\n-bool MachOLinkingContext::PackedVersion::\n-operator>=(const PackedVersion &rhs) const {\n-  return _value >= rhs._value;\n-}\n-\n-bool MachOLinkingContext::PackedVersion::\n-operator==(const PackedVersion &rhs) const {\n-  return _value == rhs._value;\n-}\n-\n struct ArchInfo {\n   StringRef archName;\n   MachOLinkingContext::Arch arch;\n@@ -146,8 +123,8 @@ uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {\n \n MachOLinkingContext::MachOLinkingContext()\n     : _outputFileType(mach_o::MH_EXECUTE), _outputFileTypeStatic(false),\n-      _doNothing(false), _arch(arch_unknown), _os(OS::macOSX),\n-      _osMinVersion("0.0"), _pageZeroSize(0x1000), _kindHandler(nullptr) {}\n+      _doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),\n+      _pageZeroSize(0x1000), _kindHandler(nullptr) {}\n \n MachOLinkingContext::~MachOLinkingContext() {}\n \n@@ -172,11 +149,19 @@ bool MachOLinkingContext::outputTypeHasEntry() const {\n \n bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {\n   switch (_os) {\n-  case OS::macOSX:\n-    return (_osMinVersion >= PackedVersion(mac));\n+  case OS::macOSX: {\n+    uint32_t parsedVersion;\n+    if (parsePackedVersion(mac, parsedVersion))\n+      return false;\n+    return _osMinVersion >= parsedVersion;\n+  }\n   case OS::iOS:\n-  case OS::iOS_simulator:\n-    return (_osMinVersion >= PackedVersion(iOS));\n+  case OS::iOS_simulator: {\n+    uint32_t parsedVersion;\n+    if (parsePackedVersion(iOS, parsedVersion))\n+      return false;\n+    return _osMinVersion >= parsedVersion;\n+  }\n   }\n   llvm_unreachable("target not configured for iOS or MacOSX");\n }\n@@ -224,7 +209,7 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {\n \n bool MachOLinkingContext::setOS(OS os, StringRef minOSVersion) {\n   _os = os;\n-  return PackedVersion::parse(minOSVersion, _osMinVersion);\n+  return parsePackedVersion(minOSVersion, _osMinVersion);\n }\n \n void MachOLinkingContext::addPasses(PassManager &pm) const {\n', 'commit_subject': 'Remove PackedVersion from MachOLinkingContext and replace with uint32_t and a parsePackedVersion() utility.', 'repo_name': 'llvm-mirror/lld', 'committer': {'name': 'Nick Kledzik', 'email': '038bc50b1680b0d0d1e196fd4d1aa474d0d1ef20@apple.com', 'time_sec': '1378856817', 'tz_offset': '0', 'date': {'seconds': '1378856817'}}, 'commit_tree': '62232c07909ad1bcf546aa6414d9df9d19e91855', 'commit_message': 'Remove PackedVersion from MachOLinkingContext and replace with uint32_t\nand a parsePackedVersion() utility.\n\nPatch by Joe Ranieri\n\n\n\ngit-svn-id: f6089bf0e6284f307027cef4f64114ee9ebb0424@190451 91177308-0d34-0410-b5e6-96231b3b80d8\n', 'language_name': 'Python', 'license': 'apache-2.0', 'hunks': '@@ -25,16 +25,8 @@ using lld::mach_o::KindHandler;\n \n namespace lld {\n \n-MachOLinkingContext::PackedVersion::PackedVersion(StringRef str) {\n-  if (parse(str, *this))\n-    llvm_unreachable("bad version string");\n-}\n-\n-/// Construct 32-bit PackedVersion from string "X.Y.Z" where\n-/// bits are xxxx.yy.zz.  Largest number is 65535.255.255\n-bool MachOLinkingContext::PackedVersion::parse(\n-    StringRef str, MachOLinkingContext::PackedVersion &result) {\n-  result._value = 0;\n+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {\n+  result = 0;\n \n   if (str.empty())\n     return false;\n@@ -47,14 +39,14 @@ bool MachOLinkingContext::PackedVersion::parse(\n     return true;\n   if (num > 65535)\n     return true;\n-  result._value = num << 16;\n+  result = num << 16;\n \n   if (parts.size() > 1) {\n     if (llvm::getAsUnsignedInteger(parts[1], 10, num))\n       return true;\n     if (num > 255)\n       return true;\n-    result._value |= (num << 8);\n+    result |= (num << 8);\n   }\n \n   if (parts.size() > 2) {\n@@ -62,27 +54,12 @@ bool MachOLinkingContext::PackedVersion::parse(\n       return true;\n     if (num > 255)\n       return true;\n-    result._value |= num;\n+    result |= num;\n   }\n \n   return false;\n }\n \n-bool MachOLinkingContext::PackedVersion::\n-operator<(const PackedVersion &rhs) const {\n-  return _value < rhs._value;\n-}\n-\n-bool MachOLinkingContext::PackedVersion::\n-operator>=(const PackedVersion &rhs) const {\n-  return _value >= rhs._value;\n-}\n-\n-bool MachOLinkingContext::PackedVersion::\n-operator==(const PackedVersion &rhs) const {\n-  return _value == rhs._value;\n-}\n-\n struct ArchInfo {\n   StringRef archName;\n   MachOLinkingContext::Arch arch;\n@@ -146,8 +123,8 @@ uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {\n \n MachOLinkingContext::MachOLinkingContext()\n     : _outputFileType(mach_o::MH_EXECUTE), _outputFileTypeStatic(false),\n-      _doNothing(false), _arch(arch_unknown), _os(OS::macOSX),\n-      _osMinVersion("0.0"), _pageZeroSize(0x1000), _kindHandler(nullptr) {}\n+      _doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),\n+      _pageZeroSize(0x1000), _kindHandler(nullptr) {}\n \n MachOLinkingContext::~MachOLinkingContext() {}\n \n@@ -172,11 +149,19 @@ bool MachOLinkingContext::outputTypeHasEntry() const {\n \n bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {\n   switch (_os) {\n-  case OS::macOSX:\n-    return (_osMinVersion >= PackedVersion(mac));\n+  case OS::macOSX: {\n+    uint32_t parsedVersion;\n+    if (parsePackedVersion(mac, parsedVersion))\n+      return false;\n+    return _osMinVersion >= parsedVersion;\n+  }\n   case OS::iOS:\n-  case OS::iOS_simulator:\n-    return (_osMinVersion >= PackedVersion(iOS));\n+  case OS::iOS_simulator: {\n+    uint32_t parsedVersion;\n+    if (parsePackedVersion(iOS, parsedVersion))\n+      return false;\n+    return _osMinVersion >= parsedVersion;\n+  }\n   }\n   llvm_unreachable("target not configured for iOS or MacOSX");\n }\n@@ -224,7 +209,7 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {\n \n bool MachOLinkingContext::setOS(OS os, StringRef minOSVersion) {\n   _os = os;\n-  return PackedVersion::parse(minOSVersion, _osMinVersion);\n+  return parsePackedVersion(minOSVersion, _osMinVersion);\n }\n \n void MachOLinkingContext::addPasses(PassManager &pm) const {\n', 'addition_count': 20, 'deletion_count': 35, 'src_file': 'a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp', 'tgt_file': 'b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp', 'file_extension': '.cpp', 'before_file': '//===- lib/ReaderWriter/MachO/MachOLinkingContext.cpp ---------------------===//\n//\n// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.\n// See https://llvm.org/LICENSE.txt for license information.\n// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n//\n//===----------------------------------------------------------------------===//\n\n#include "lld/Common/ErrorHandler.h"\n#include "lld/ReaderWriter/MachOLinkingContext.h"\n#include "ArchHandler.h"\n#include "File.h"\n#include "FlatNamespaceFile.h"\n#include "MachONormalizedFile.h"\n#include "MachOPasses.h"\n#include "SectCreateFile.h"\n#include "lld/Common/Driver.h"\n#include "lld/Core/ArchiveLibraryFile.h"\n#include "lld/Core/PassManager.h"\n#include "lld/Core/Reader.h"\n#include "lld/Core/Writer.h"\n#include "llvm/ADT/STLExtras.h"\n#include "llvm/ADT/StringExtras.h"\n#include "llvm/ADT/Triple.h"\n\nnamespace lld {\n\nMachOLinkingContext::PackedVersion::PackedVersion(StringRef str) {\n  if (parse(str, *this))\n    llvm_unreachable("bad version string");\n}\n\n/// Construct 32-bit PackedVersion from string "X.Y.Z" where\n/// bits are xxxx.yy.zz.  Largest number is 65535.255.255\nbool MachOLinkingContext::PackedVersion::parse(\n    StringRef str, MachOLinkingContext::PackedVersion &result) {\n  result._value = 0;\n\n  if (str.empty())\n    return false;\nusing lld::mach_o::ArchHandler;\nusing lld::mach_o::MachOFile;\nusing lld::mach_o::MachODylibFile;\nusing namespace llvm::MachO;\n\nnamespace lld {\n    return true;\n  if (num > 65535)\n    return true;\n  result._value = num << 16;\n\n  if (parts.size() > 1) {\n    if (llvm::getAsUnsignedInteger(parts[1], 10, num))\n      return true;\n    if (num > 255)\n      return true;\n    result._value |= (num << 8);\n  }\n\n  if (parts.size() > 2) {\n    return true;\n      return true;\n    if (num > 255)\n      return true;\n    result._value |= num;\n  }\n\n  return false;\n}\n\nbool MachOLinkingContext::PackedVersion::\noperator<(const PackedVersion &rhs) const {\n  return _value < rhs._value;\n}\n\nbool MachOLinkingContext::PackedVersion::\noperator>=(const PackedVersion &rhs) const {\n  return _value >= rhs._value;\n}\n\nbool MachOLinkingContext::PackedVersion::\noperator==(const PackedVersion &rhs) const {\n  return _value == rhs._value;\n}\n\nstruct ArchInfo {\n  StringRef archName;\n  MachOLinkingContext::Arch arch;\n      return true;\n    if (num > 255)\n      return true;\n    result |= num;\n  }\n\n  return false;\n}\n\nbool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) {\n  result = 0;\n\n  if (str.empty())\n    return false;\n\n  SmallVector<StringRef, 5> parts;\n  llvm::SplitString(str, parts, ".");\n\n  unsigned long long num;\n  if (llvm::getAsUnsignedInteger(parts[0], 10, num))\n    return true;\n  if (num > 0xFFFFFF)\n    return true;\n  result = num << 40;\n\n  unsigned Shift = 30;\n  for (StringRef str : llvm::makeArrayRef(parts).slice(1)) {\n    if (llvm::getAsUnsignedInteger(str, 10, num))\n      return true;\n    if (num > 0x3FF)\n      return true;\n    result |= (num << Shift);\n    Shift -= 10;\n  }\n\n  return false;\n}\n\nMachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {\n  { "x86_64", arch_x86_64, true,  CPU_TYPE_X86_64,  CPU_SUBTYPE_X86_64_ALL },\n  { "i386",   arch_x86,    true,  CPU_TYPE_I386,    CPU_SUBTYPE_X86_ALL },\n  { "ppc",    arch_ppc,    false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL },\n  { "armv6",  arch_armv6,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V6 },\n  { "armv7",  arch_armv7,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7 },\n  { "armv7s", arch_armv7s, true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7S },\n  { "arm64",  arch_arm64,  true,  CPU_TYPE_ARM64,   CPU_SUBTYPE_ARM64_ALL },\n  { "",       arch_unknown,false, 0,                0 }\n};\n\nMachOLinkingContext::Arch\nMachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {\n  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {\n    if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype))\n      return info->arch;\n  }\n  return arch_unknown;\n}\n\nMachOLinkingContext::MachOLinkingContext()\n    : _outputFileType(mach_o::MH_EXECUTE), _outputFileTypeStatic(false),\n      _doNothing(false), _arch(arch_unknown), _os(OS::macOSX),\n      _osMinVersion("0.0"), _pageZeroSize(0x1000), _kindHandler(nullptr) {}\n\nMachOLinkingContext::~MachOLinkingContext() {}\n\n}\n\nStringRef MachOLinkingContext::nameFromArch(Arch arch) {\n  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {\n    if (info->arch == arch)\n      return info->archName;\n  }\n  return "<unknown>";\n}\n\nuint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {\n  assert(arch != arch_unknown);\n  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {\n    if (info->arch == arch)\n      return info->cputype;\n  }\n  llvm_unreachable("Unknown arch type");\n}\n\nbool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {\n  switch (_os) {\n  case OS::macOSX:\n    return (_osMinVersion >= PackedVersion(mac));\n  case OS::iOS:\n  case OS::iOS_simulator:\n    return (_osMinVersion >= PackedVersion(iOS));\n  }\n  llvm_unreachable("target not configured for iOS or MacOSX");\n}\nMachOLinkingContext::MachOLinkingContext() {}\n\nMachOLinkingContext::~MachOLinkingContext() {\n  // Atoms are allocated on BumpPtrAllocator\'s on File\'s.\n  // As we transfer atoms from one file to another, we need to clear all of the\n  // atoms before we remove any of the BumpPtrAllocator\'s.\n  auto &nodes = getNodes();\n  for (unsigned i = 0, e = nodes.size(); i != e; ++i) {\n    FileNode *node = dyn_cast<FileNode>(nodes[i].get());\n    if (!node)\n      continue;\n    File *file = node->getFile();\n    file->clearAtoms();\n  }\n}\n\nvoid MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,\n                                    uint32_t minOSVersion,\n                                    bool exportDynamicSymbols) {\n  _outputMachOType = type;\n  _arch = arch;\n  _os = os;\n  _osMinVersion = minOSVersion;\n\n  // If min OS not specified on command line, use reasonable defaults.\n  // Note that we only do sensible defaults when emitting something other than\n  // object and preload.\n  if (_outputMachOType != llvm::MachO::MH_OBJECT &&\n      _outputMachOType != llvm::MachO::MH_PRELOAD) {\n    if (minOSVersion == 0) {\n      switch (_arch) {\n      case arch_x86_64:\n      case arch_x86:\n        parsePackedVersion("10.8", _osMinVersion);\n        _os = MachOLinkingContext::OS::macOSX;\n        break;\n      case arch_armv6:\n      case arch_armv7:\n      case arch_armv7s:\n      case arch_arm64:\n        parsePackedVersion("7.0", _osMinVersion);\n\nbool MachOLinkingContext::setOS(OS os, StringRef minOSVersion) {\n  _os = os;\n  return PackedVersion::parse(minOSVersion, _osMinVersion);\n}\n\nvoid MachOLinkingContext::addPasses(PassManager &pm) const {\n\n  switch (_outputMachOType) {\n  case llvm::MachO::MH_EXECUTE:\n    // If targeting newer OS, use _main\n    if (minOS("10.8", "6.0")) {\n      _entrySymbolName = "_main";\n    } else {\n      // If targeting older OS, use start (in crt1.o)\n      _entrySymbolName = "start";\n    }\n\n    // __PAGEZERO defaults to 4GB on 64-bit (except for PP64 which lld does not\n    // support) and 4KB on 32-bit.\n    if (is64Bit(_arch)) {\n      _pageZeroSize = 0x100000000;\n    } else {\n      _pageZeroSize = 0x1000;\n    }\n\n    // Initial base address is __PAGEZERO size.\n    _baseAddress = _pageZeroSize;\n\n    // Make PIE by default when targetting newer OSs.\n    switch (os) {\n      case OS::macOSX:\n        if (minOSVersion >= 0x000A0700) // MacOSX 10.7\n          _pie = true;\n        break;\n      case OS::iOS:\n        if (minOSVersion >= 0x00040300) // iOS 4.3\n          _pie = true;\n       break;\n       case OS::iOS_simulator:\n        _pie = true;\n       break;\n       case OS::unknown:\n       break;\n    }\n    setGlobalsAreDeadStripRoots(exportDynamicSymbols);\n    break;\n  case llvm::MachO::MH_DYLIB:\n    setGlobalsAreDeadStripRoots(exportDynamicSymbols);\n    break;\n  case llvm::MachO::MH_BUNDLE:\n    break;\n  case llvm::MachO::MH_OBJECT:\n    _printRemainingUndefines = false;\n    _allowRemainingUndefines = true;\n    break;\n  default:\n    break;\n  }\n\n  // Set default segment page sizes based on arch.\n  if (arch == arch_arm64)\n    _pageSize = 4*4096;\n}\n\nuint32_t MachOLinkingContext::getCPUType() const {\n  return cpuTypeFromArch(_arch);\n}\n\nuint32_t MachOLinkingContext::getCPUSubType() const {\n  return cpuSubtypeFromArch(_arch);\n}\n\nbool MachOLinkingContext::is64Bit(Arch arch) {\n  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {\n    if (info->arch == arch) {\n      return (info->cputype & CPU_ARCH_ABI64);\n    }\n  }\n  // unknown archs are not 64-bit.\n  return false;\n}\n\nbool MachOLinkingContext::isHostEndian(Arch arch) {\n  assert(arch != arch_unknown);\n  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {\n    if (info->arch == arch) {\n      return (info->littleEndian == llvm::sys::IsLittleEndianHost);\n    }\n  }\n  llvm_unreachable("Unknown arch type");\n}\n\nbool MachOLinkingContext::isBigEndian(Arch arch) {\n  assert(arch != arch_unknown);\n  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {\n    if (info->arch == arch) {\n      return ! info->littleEndian;\n    }\n  }\n  llvm_unreachable("Unknown arch type");\n}\n\nbool MachOLinkingContext::is64Bit() const {\n  return is64Bit(_arch);\n}\n\nbool MachOLinkingContext::outputTypeHasEntry() const {\n  switch (_outputMachOType) {\n  case MH_EXECUTE:\n  case MH_DYLINKER:\n  case MH_PRELOAD:\n    return true;\n  default:\n    return false;\n  }\n}\n\nbool MachOLinkingContext::needsStubsPass() const {\n  switch (_outputMachOType) {\n  case MH_EXECUTE:\n    return !_outputMachOTypeStatic;\n  case MH_DYLIB:\n  case MH_BUNDLE:\n    return true;\n  default:\n    return false;\n  }\n}\n\nbool MachOLinkingContext::needsGOTPass() const {\n  // GOT pass not used in -r mode.\n  if (_outputMachOType == MH_OBJECT)\n    return false;\n  // Only some arches use GOT pass.\n  switch (_arch) {\n    case arch_x86_64:\n    case arch_arm64:\n      return true;\n    default:\n      return false;\n  }\n}\n\nbool MachOLinkingContext::needsCompactUnwindPass() const {\n  switch (_outputMachOType) {\n  case MH_EXECUTE:\n  case MH_DYLIB:\n  case MH_BUNDLE:\n    return archHandler().needsCompactUnwind();\n  default:\n    return false;\n  }\n}\n\nbool MachOLinkingContext::needsObjCPass() const {\n  // ObjC pass is only needed if any of the inputs were ObjC.\n  return _objcConstraint != objc_unknown;\n}\n\nbool MachOLinkingContext::needsShimPass() const {\n  // Shim pass only used in final executables.\n  if (_outputMachOType == MH_OBJECT)\n    return false;\n  // Only 32-bit arm arches use Shim pass.\n  switch (_arch) {\n  case arch_armv6:\n  case arch_armv7:\n  case arch_armv7s:\n    return true;\n  default:\n    return false;\n  }\n}\n\nbool MachOLinkingContext::needsTLVPass() const {\n  switch (_outputMachOType) {\n  case MH_BUNDLE:\n  case MH_EXECUTE:\n  case MH_DYLIB:\n    return true;\n  default:\n    return false;\n  }\n}\n\nStringRef MachOLinkingContext::binderSymbolName() const {\n  return archHandler().stubInfo().binderSymbolName;\n}\n\nbool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {\n  uint32_t parsedVersion;\n  switch (_os) {\n  case OS::macOSX:\n    if (parsePackedVersion(mac, parsedVersion))\n      return false;\n    return _osMinVersion >= parsedVersion;\n  case OS::iOS:\n  case OS::iOS_simulator:\n    if (parsePackedVersion(iOS, parsedVersion))\n      return false;\n    return _osMinVersion >= parsedVersion;\n  case OS::unknown:\n    // If we don\'t know the target, then assume that we don\'t meet the min OS.\n    // This matches the ld64 behaviour\n    return false;\n  }\n  llvm_unreachable("invalid OS enum");\n}\n\nbool MachOLinkingContext::addEntryPointLoadCommand() const {\n  if ((_outputMachOType == MH_EXECUTE) && !_outputMachOTypeStatic) {\n    return minOS("10.8", "6.0");\n  }\n  return false;\n}\n\nbool MachOLinkingContext::addUnixThreadLoadCommand() const {\n  switch (_outputMachOType) {\n  case MH_EXECUTE:\n    if (_outputMachOTypeStatic)\n      return true;\n    else\n      return !minOS("10.8", "6.0");\n    break;\n  case MH_DYLINKER:\n  case MH_PRELOAD:\n    return true;\n  default:\n    return false;\n  }\n}\n\nbool MachOLinkingContext::pathExists(StringRef path) const {\n  if (!_testingFileUsage)\n    return llvm::sys::fs::exists(path.str());\n\n  // Otherwise, we\'re in test mode: only files explicitly provided on the\n  // command-line exist.\n  std::string key = path.str();\n  std::replace(key.begin(), key.end(), \'\\\\\', \'/\');\n  return _existingPaths.find(key) != _existingPaths.end();\n}\n\nbool MachOLinkingContext::fileExists(StringRef path) const {\n  bool found = pathExists(path);\n  // Log search misses.\n  if (!found)\n    addInputFileNotFound(path);\n\n  // When testing, file is never opened, so logging is done here.\n  if (_testingFileUsage && found)\n    addInputFileDependency(path);\n\n  return found;\n}\n\nvoid MachOLinkingContext::setSysLibRoots(const StringRefVector &paths) {\n  _syslibRoots = paths;\n}\n\nvoid MachOLinkingContext::addRpath(StringRef rpath) {\n  _rpaths.push_back(rpath);\n}\n\nvoid MachOLinkingContext::addModifiedSearchDir(StringRef libPath,\n                                               bool isSystemPath) {\n  bool addedModifiedPath = false;\n\n  // -syslibroot only applies to absolute paths.\n  if (libPath.startswith("/")) {\n    for (auto syslibRoot : _syslibRoots) {\n      SmallString<256> path(syslibRoot);\n      llvm::sys::path::append(path, libPath);\n      if (pathExists(path)) {\n        _searchDirs.push_back(path.str().copy(_allocator));\n        addedModifiedPath = true;\n      }\n    }\n  }\n\n  if (addedModifiedPath)\n    return;\n\n  // Finally, if only one -syslibroot is given, system paths which aren\'t in it\n  // get suppressed.\n  if (_syslibRoots.size() != 1 || !isSystemPath) {\n    if (pathExists(libPath)) {\n      _searchDirs.push_back(libPath);\n    }\n  }\n}\n\nvoid MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,\n                                                bool isSystemPath) {\n  bool pathAdded = false;\n\n  // -syslibroot only used with to absolute framework search paths.\n  if (fwPath.startswith("/")) {\n    for (auto syslibRoot : _syslibRoots) {\n      SmallString<256> path(syslibRoot);\n      llvm::sys::path::append(path, fwPath);\n      if (pathExists(path)) {\n        _frameworkDirs.push_back(path.str().copy(_allocator));\n        pathAdded = true;\n      }\n    }\n  }\n  // If fwPath found in any -syslibroot, then done.\n  if (pathAdded)\n    return;\n\n  // If only one -syslibroot, system paths not in that SDK are suppressed.\n  if (isSystemPath && (_syslibRoots.size() == 1))\n    return;\n\n  // Only use raw fwPath if that directory exists.\n  if (pathExists(fwPath))\n    _frameworkDirs.push_back(fwPath);\n}\n\nllvm::Optional<StringRef>\nMachOLinkingContext::searchDirForLibrary(StringRef path,\n                                         StringRef libName) const {\n  SmallString<256> fullPath;\n  if (libName.endswith(".o")) {\n    // A request ending in .o is special: just search for the file directly.\n    fullPath.assign(path);\n    llvm::sys::path::append(fullPath, libName);\n    if (fileExists(fullPath))\n      return fullPath.str().copy(_allocator);\n    return llvm::None;\n  }\n\n  // Search for dynamic library\n  fullPath.assign(path);\n  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".dylib");\n  if (fileExists(fullPath))\n    return fullPath.str().copy(_allocator);\n\n  // If not, try for a static library\n  fullPath.assign(path);\n  llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a");\n  if (fileExists(fullPath))\n    return fullPath.str().copy(_allocator);\n\n  return llvm::None;\n}\n\nllvm::Optional<StringRef>\nMachOLinkingContext::searchLibrary(StringRef libName) const {\n  SmallString<256> path;\n  for (StringRef dir : searchDirs()) {\n    llvm::Optional<StringRef> searchDir = searchDirForLibrary(dir, libName);\n    if (searchDir)\n      return searchDir;\n  }\n\n  return llvm::None;\n}\n\nllvm::Optional<StringRef>\nMachOLinkingContext::findPathForFramework(StringRef fwName) const{\n  SmallString<256> fullPath;\n  for (StringRef dir : frameworkDirs()) {\n    fullPath.assign(dir);\n    llvm::sys::path::append(fullPath, Twine(fwName) + ".framework", fwName);\n    if (fileExists(fullPath))\n      return fullPath.str().copy(_allocator);\n  }\n\n  return llvm::None;\n}\n\nbool MachOLinkingContext::validateImpl() {\n  // TODO: if -arch not specified, look at arch of first .o file.\n\n  if (_currentVersion && _outputMachOType != MH_DYLIB) {\n    error("-current_version can only be used with dylibs");\n    return false;\n  }\n\n  if (_compatibilityVersion && _outputMachOType != MH_DYLIB) {\n    error("-compatibility_version can only be used with dylibs");\n    return false;\n  }\n\n  if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) {\n    error("-mark_dead_strippable_dylib can only be used with dylibs");\n    return false;\n  }\n\n  if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) {\n    error("-bundle_loader can only be used with Mach-O bundles");\n    return false;\n  }\n\n  // If -exported_symbols_list used, all exported symbols must be defined.\n  if (_exportMode == ExportMode::whiteList) {\n    for (const auto &symbol : _exportedSymbols)\n      addInitialUndefinedSymbol(symbol.getKey());\n  }\n\n  // If -dead_strip, set up initial live symbols.\n  if (deadStrip()) {\n    // Entry point is live.\n    if (outputTypeHasEntry())\n      addDeadStripRoot(entrySymbolName());\n    // Lazy binding helper is live.\n    if (needsStubsPass())\n      addDeadStripRoot(binderSymbolName());\n    // If using -exported_symbols_list, make all exported symbols live.\n    if (_exportMode == ExportMode::whiteList) {\n      setGlobalsAreDeadStripRoots(false);\n      for (const auto &symbol : _exportedSymbols)\n        addDeadStripRoot(symbol.getKey());\n    }\n  }\n\n  addOutputFileDependency(outputPath());\n\n  return true;\n}\n\nvoid MachOLinkingContext::addPasses(PassManager &pm) {\n  // objc pass should be before layout pass.  Otherwise test cases may contain\n  // no atoms which confuses the layout pass.\n  if (needsObjCPass())\n    mach_o::addObjCPass(pm, *this);\n  mach_o::addLayoutPass(pm, *this);\n  if (needsStubsPass())\n    mach_o::addStubsPass(pm, *this);\n  if (needsCompactUnwindPass())\n    mach_o::addCompactUnwindPass(pm, *this);\n  if (needsGOTPass())\n    mach_o::addGOTPass(pm, *this);\n  if (needsTLVPass())\n    mach_o::addTLVPass(pm, *this);\n  if (needsShimPass())\n    mach_o::addShimPass(pm, *this); // Shim pass must run after stubs pass.\n}\n\nWriter &MachOLinkingContext::writer() const {\n  if (!_writer)\n    _writer = createWriterMachO(*this);\n  return *_writer;\n}\n\nErrorOr<std::unique_ptr<MemoryBuffer>>\nMachOLinkingContext::getMemoryBuffer(StringRef path) {\n  addInputFileDependency(path);\n\n  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =\n    MemoryBuffer::getFileOrSTDIN(path);\n  if (std::error_code ec = mbOrErr.getError())\n    return ec;\n  std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());\n\n  // If buffer contains a fat file, find required arch in fat buffer\n  // and switch buffer to point to just that required slice.\n  uint32_t offset;\n  uint32_t size;\n  if (sliceFromFatFile(mb->getMemBufferRef(), offset, size))\n    return MemoryBuffer::getFileSlice(path, size, offset);\n  return std::move(mb);\n}\n\nMachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {\n  ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = getMemoryBuffer(path);\n  if (mbOrErr.getError())\n    return nullptr;\n\n  ErrorOr<std::unique_ptr<File>> fileOrErr =\n      registry().loadFile(std::move(mbOrErr.get()));\n  if (!fileOrErr)\n    return nullptr;\n  std::unique_ptr<File> &file = fileOrErr.get();\n  file->parse();\n  MachODylibFile *result = reinterpret_cast<MachODylibFile *>(file.get());\n  // Node object now owned by _indirectDylibs vector.\n  _indirectDylibs.push_back(std::move(file));\n  return result;\n}\n\nMachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) {\n  // See if already loaded.\n  auto pos = _pathToDylibMap.find(path);\n  if (pos != _pathToDylibMap.end())\n    return pos->second;\n\n  // Search -L paths if of the form "libXXX.dylib"\n  std::pair<StringRef, StringRef> split = path.rsplit(\'/\');\n  StringRef leafName = split.second;\n  if (leafName.startswith("lib") && leafName.endswith(".dylib")) {\n    // FIXME: Need to enhance searchLibrary() to only look for .dylib\n    auto libPath = searchLibrary(leafName);\n    if (libPath)\n      return loadIndirectDylib(libPath.getValue());\n  }\n\n  // Try full path with sysroot.\n  for (StringRef sysPath : _syslibRoots) {\n    SmallString<256> fullPath;\n    fullPath.assign(sysPath);\n    llvm::sys::path::append(fullPath, path);\n    if (pathExists(fullPath))\n      return loadIndirectDylib(fullPath);\n  }\n\n  // Try full path.\n  if (pathExists(path)) {\n    return loadIndirectDylib(path);\n  }\n\n  return nullptr;\n}\n\nuint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const {\n  auto pos = _pathToDylibMap.find(installName);\n  if (pos != _pathToDylibMap.end())\n    return pos->second->currentVersion();\n  else\n    return 0x10000; // 1.0\n}\n\nuint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {\n  auto pos = _pathToDylibMap.find(installName);\n  if (pos != _pathToDylibMap.end())\n    return pos->second->compatVersion();\n  else\n    return 0x10000; // 1.0\n}\n\nvoid MachOLinkingContext::createImplicitFiles(\n                            std::vector<std::unique_ptr<File> > &result) {\n  // Add indirect dylibs by asking each linked dylib to add its indirects.\n  // Iterate until no more dylibs get loaded.\n  size_t dylibCount = 0;\n  while (dylibCount != _allDylibs.size()) {\n    dylibCount = _allDylibs.size();\n    for (MachODylibFile *dylib : _allDylibs) {\n      dylib->loadReExportedDylibs([this] (StringRef path) -> MachODylibFile* {\n                                  return findIndirectDylib(path); });\n    }\n  }\n\n  // Let writer add output type specific extras.\n  writer().createImplicitFiles(result);\n\n  // If undefinedMode is != error, add a FlatNamespaceFile instance. This will\n  // provide a SharedLibraryAtom for symbols that aren\'t defined elsewhere.\n  if (undefinedMode() != UndefinedMode::error) {\n    result.emplace_back(new mach_o::FlatNamespaceFile(*this));\n    _flatNamespaceFile = result.back().get();\n  }\n}\n\nvoid MachOLinkingContext::registerDylib(MachODylibFile *dylib,\n                                        bool upward) const {\n  std::lock_guard<std::mutex> lock(_dylibsMutex);\n\n  if (!llvm::count(_allDylibs, dylib))\n    _allDylibs.push_back(dylib);\n  _pathToDylibMap[dylib->installName()] = dylib;\n  // If path is different than install name, register path too.\n  if (!dylib->path().equals(dylib->installName()))\n    _pathToDylibMap[dylib->path()] = dylib;\n  if (upward)\n    _upwardDylibs.insert(dylib);\n}\n\nbool MachOLinkingContext::isUpwardDylib(StringRef installName) const {\n  for (MachODylibFile *dylib : _upwardDylibs) {\n    if (dylib->installName().equals(installName))\n      return true;\n  }\n  return false;\n}\n\nArchHandler &MachOLinkingContext::archHandler() const {\n  if (!_archHandler)\n    _archHandler = ArchHandler::create(_arch);\n  return *_archHandler;\n}\n\nvoid MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect,\n                                              uint16_t align) {\n  SectionAlign entry = { seg, sect, align };\n  _sectAligns.push_back(entry);\n}\n\nvoid MachOLinkingContext::addSectCreateSection(\n                                        StringRef seg, StringRef sect,\n                                        std::unique_ptr<MemoryBuffer> content) {\n\n  if (!_sectCreateFile) {\n    auto sectCreateFile = std::make_unique<mach_o::SectCreateFile>();\n    _sectCreateFile = sectCreateFile.get();\n    getNodes().push_back(std::make_unique<FileNode>(std::move(sectCreateFile)));\n  }\n\n  assert(_sectCreateFile && "sectcreate file does not exist.");\n  _sectCreateFile->addSection(seg, sect, std::move(content));\n}\n\nbool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,\n                                         uint16_t &align) const {\n  for (const SectionAlign &entry : _sectAligns) {\n    if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) {\n      align = entry.align;\n      return true;\n    }\n  }\n  return false;\n}\n\nvoid MachOLinkingContext::addExportSymbol(StringRef sym) {\n  // Support old crufty export lists with bogus entries.\n  if (sym.endswith(".eh") || sym.startswith(".objc_category_name_")) {\n    llvm::errs() << "warning: ignoring " << sym << " in export list\\n";\n    return;\n  }\n  // Only i386 MacOSX uses old ABI, so don\'t change those.\n  if ((_os != OS::macOSX) || (_arch != arch_x86)) {\n    // ObjC has two differnent ABIs.  Be nice and allow one export list work for\n    // both ABIs by renaming symbols.\n    if (sym.startswith(".objc_class_name_")) {\n      std::string abi2className("_OBJC_CLASS_$_");\n      abi2className += sym.substr(17);\n      _exportedSymbols.insert(copy(abi2className));\n      std::string abi2metaclassName("_OBJC_METACLASS_$_");\n      abi2metaclassName += sym.substr(17);\n      _exportedSymbols.insert(copy(abi2metaclassName));\n      return;\n    }\n  }\n\n  // FIXME: Support wildcards.\n  _exportedSymbols.insert(sym);\n}\n\nbool MachOLinkingContext::exportSymbolNamed(StringRef sym) const {\n  switch (_exportMode) {\n  case ExportMode::globals:\n    llvm_unreachable("exportSymbolNamed() should not be called in this mode");\n    break;\n  case ExportMode::whiteList:\n    return _exportedSymbols.count(sym);\n  case ExportMode::blackList:\n    return !_exportedSymbols.count(sym);\n  }\n  llvm_unreachable("_exportMode unknown enum value");\n}\n\nstd::string MachOLinkingContext::demangle(StringRef symbolName) const {\n  // Only try to demangle symbols if -demangle on command line\n  if (!demangleSymbols())\n    return symbolName;\n\n  // Only try to demangle symbols that look like C++ symbols\n  if (!symbolName.startswith("__Z"))\n    return symbolName;\n\n  SmallString<256> symBuff;\n  StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);\n  // Mach-O has extra leading underscore that needs to be removed.\n  const char *cstr = nullTermSym.data() + 1;\n  int status;\n  char *demangled = llvm::itaniumDemangle(cstr, nullptr, nullptr, &status);\n  if (demangled) {\n    std::string result(demangled);\n    // __cxa_demangle() always uses a malloc\'ed buffer to return the result.\n    free(demangled);\n    return result;\n  }\n\n  return symbolName;\n}\n\nstatic void addDependencyInfoHelper(llvm::raw_fd_ostream *DepInfo,\n                                    char Opcode, StringRef Path) {\n  if (!DepInfo)\n    return;\n\n  *DepInfo << Opcode;\n  *DepInfo << Path;\n  *DepInfo << \'\\0\';\n}\n\nstd::error_code MachOLinkingContext::createDependencyFile(StringRef path) {\n  std::error_code ec;\n  _dependencyInfo = std::unique_ptr<llvm::raw_fd_ostream>(\n      new llvm::raw_fd_ostream(path, ec, llvm::sys::fs::OF_None));\n  if (ec) {\n    _dependencyInfo.reset();\n    return ec;\n  }\n\n  addDependencyInfoHelper(_dependencyInfo.get(), 0x00, "lld" /*FIXME*/);\n  return std::error_code();\n}\n\nvoid MachOLinkingContext::addInputFileDependency(StringRef path) const {\n  addDependencyInfoHelper(_dependencyInfo.get(), 0x10, path);\n}\n\nvoid MachOLinkingContext::addInputFileNotFound(StringRef path) const {\n  addDependencyInfoHelper(_dependencyInfo.get(), 0x11, path);\n}\n\nvoid MachOLinkingContext::addOutputFileDependency(StringRef path) const {\n  addDependencyInfoHelper(_dependencyInfo.get(), 0x40, path);\n}\n\nvoid MachOLinkingContext::appendOrderedSymbol(StringRef symbol,\n                                              StringRef filename) {\n  // To support sorting static functions which may have the same name in\n  // multiple .o files, _orderFiles maps the symbol name to a vector\n  // of OrderFileNode each of which can specify a file prefix.\n  OrderFileNode info;\n  if (!filename.empty())\n    info.fileFilter = copy(filename);\n  info.order = _orderFileEntries++;\n  _orderFiles[symbol].push_back(info);\n}\n\nbool\nMachOLinkingContext::findOrderOrdinal(const std::vector<OrderFileNode> &nodes,\n                                      const DefinedAtom *atom,\n                                      unsigned &ordinal) {\n  const File *objFile = &atom->file();\n  assert(objFile);\n  StringRef objName = objFile->path();\n  std::pair<StringRef, StringRef> dirAndLeaf = objName.rsplit(\'/\');\n  if (!dirAndLeaf.second.empty())\n    objName = dirAndLeaf.second;\n  for (const OrderFileNode &info : nodes) {\n    if (info.fileFilter.empty()) {\n      // Have unprefixed symbol name in order file that matches this atom.\n      ordinal = info.order;\n      return true;\n    }\n    if (info.fileFilter.equals(objName)) {\n      // Have prefixed symbol name in order file that matches atom\'s path.\n      ordinal = info.order;\n      return true;\n    }\n  }\n  return false;\n}\n\nbool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left,\n                                            const DefinedAtom *right,\n                                            bool &leftBeforeRight) const {\n  // No custom sorting if no order file entries.\n  if (!_orderFileEntries)\n    return false;\n\n  // Order files can only order named atoms.\n  StringRef leftName = left->name();\n  StringRef rightName = right->name();\n  if (leftName.empty() || rightName.empty())\n    return false;\n\n  // If neither is in order file list, no custom sorter.\n  auto leftPos = _orderFiles.find(leftName);\n  auto rightPos = _orderFiles.find(rightName);\n  bool leftIsOrdered = (leftPos != _orderFiles.end());\n  bool rightIsOrdered = (rightPos != _orderFiles.end());\n  if (!leftIsOrdered && !rightIsOrdered)\n    return false;\n\n  // There could be multiple symbols with same name but different file prefixes.\n  unsigned leftOrder;\n  unsigned rightOrder;\n  bool foundLeft =\n      leftIsOrdered && findOrderOrdinal(leftPos->getValue(), left, leftOrder);\n  bool foundRight = rightIsOrdered &&\n                    findOrderOrdinal(rightPos->getValue(), right, rightOrder);\n  if (!foundLeft && !foundRight)\n    return false;\n\n  // If only one is in order file list, ordered one goes first.\n  if (foundLeft != foundRight)\n    leftBeforeRight = foundLeft;\n  else\n    leftBeforeRight = (leftOrder < rightOrder);\n\n  return true;\n}\n\nstatic bool isLibrary(const std::unique_ptr<Node> &elem) {\n  if (FileNode *node = dyn_cast<FileNode>(const_cast<Node *>(elem.get()))) {\n    File *file = node->getFile();\n    return isa<SharedLibraryFile>(file) || isa<ArchiveLibraryFile>(file);\n  }\n  return false;\n}\n\n// The darwin linker processes input files in two phases.  The first phase\n// links in all object (.o) files in command line order. The second phase\n// links in libraries in command line order.\n// In this function we reorder the input files so that all the object files\n// comes before any library file. We also make a group for the library files\n// so that the Resolver will reiterate over the libraries as long as we find\n// new undefines from libraries.\nvoid MachOLinkingContext::finalizeInputFiles() {\n  std::vector<std::unique_ptr<Node>> &elements = getNodes();\n  llvm::stable_sort(elements, [](const std::unique_ptr<Node> &a,\n                                 const std::unique_ptr<Node> &b) {\n    return !isLibrary(a) && isLibrary(b);\n  });\n  size_t numLibs = std::count_if(elements.begin(), elements.end(), isLibrary);\n  elements.push_back(std::make_unique<GroupEnd>(numLibs));\n}\n\nllvm::Error MachOLinkingContext::handleLoadedFile(File &file) {\n  auto *machoFile = dyn_cast<MachOFile>(&file);\n  if (!machoFile)\n    return llvm::Error::success();\n\n  // Check that the arch of the context matches that of the file.\n  // Also set the arch of the context if it didn\'t have one.\n  if (_arch == arch_unknown) {\n    _arch = machoFile->arch();\n  } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) {\n    // Archs are different.\n    return llvm::make_error<GenericError>(file.path() +\n                  Twine(" cannot be linked due to incompatible architecture"));\n  }\n\n  // Check that the OS of the context matches that of the file.\n  // Also set the OS of the context if it didn\'t have one.\n  if (_os == OS::unknown) {\n    _os = machoFile->OS();\n  } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) {\n    // OSes are different.\n    return llvm::make_error<GenericError>(file.path() +\n              Twine(" cannot be linked due to incompatible operating systems"));\n  }\n\n  // Check that if the objc info exists, that it is compatible with the target\n  // OS.\n  switch (machoFile->objcConstraint()) {\n    case objc_unknown:\n      // The file is not compiled with objc, so skip the checks.\n      break;\n    case objc_gc_only:\n    case objc_supports_gc:\n      llvm_unreachable("GC support should already have thrown an error");\n    case objc_retainReleaseForSimulator:\n      // The file is built with simulator objc, so make sure that the context\n      // is also building with simulator support.\n      if (_os != OS::iOS_simulator)\n        return llvm::make_error<GenericError>(file.path() +\n          Twine(" cannot be linked.  It contains ObjC built for the simulator"\n                " while we are linking a non-simulator target"));\n      assert((_objcConstraint == objc_unknown ||\n              _objcConstraint == objc_retainReleaseForSimulator) &&\n             "Must be linking with retain/release for the simulator");\n      _objcConstraint = objc_retainReleaseForSimulator;\n      break;\n    case objc_retainRelease:\n      // The file is built without simulator objc, so make sure that the\n      // context is also building without simulator support.\n      if (_os == OS::iOS_simulator)\n        return llvm::make_error<GenericError>(file.path() +\n          Twine(" cannot be linked.  It contains ObjC built for a non-simulator"\n                " target while we are linking a simulator target"));\n      assert((_objcConstraint == objc_unknown ||\n              _objcConstraint == objc_retainRelease) &&\n             "Must be linking with retain/release for a non-simulator target");\n      _objcConstraint = objc_retainRelease;\n      break;\n  }\n\n  // Check that the swift version of the context matches that of the file.\n  // Also set the swift version of the context if it didn\'t have one.\n  if (!_swiftVersion) {\n    _swiftVersion = machoFile->swiftVersion();\n  } else if (machoFile->swiftVersion() &&\n             machoFile->swiftVersion() != _swiftVersion) {\n    // Swift versions are different.\n    return llvm::make_error<GenericError>("different swift versions");\n  }\n\n  return llvm::Error::success();\n}\n\n} // end namespace lld\n', 'message': 'Remove PackedVersion from MachOLinkingContext and replace with uint32_t\nand a parsePackedVersion() utility.\n\nPatch by Joe Ranieri\n\n\n\ngit-svn-id: f6089bf0e6284f307027cef4f64114ee9ebb0424@190451 91177308-0d34-0410-b5e6-96231b3b80d8\n', 'author_name': 'Nick Kledzik', 'lang': 'cpp'}