[lld][MachO] Add support for LC_VERSION_MIN_* load commands

This diff adds initial support for the legacy LC_VERSION_MIN_* load commands.

Test plan: make check-lld-macho

Differential revision: https://reviews.llvm.org/D100523
This commit is contained in:
Alexander Shaposhnikov 2021-04-21 05:41:14 -07:00
parent 8c16c8b7ef
commit 5c835e1ae5
13 changed files with 237 additions and 90 deletions

View File

@ -33,6 +33,7 @@ using SectionRenameMap = llvm::DenseMap<NamePair, NamePair>;
using SegmentRenameMap = llvm::DenseMap<llvm::StringRef, llvm::StringRef>; using SegmentRenameMap = llvm::DenseMap<llvm::StringRef, llvm::StringRef>;
struct PlatformInfo { struct PlatformInfo {
llvm::MachO::Target target;
llvm::VersionTuple minimum; llvm::VersionTuple minimum;
llvm::VersionTuple sdk; llvm::VersionTuple sdk;
}; };
@ -101,7 +102,6 @@ struct Configuration {
llvm::StringRef ltoObjPath; llvm::StringRef ltoObjPath;
llvm::StringRef thinLTOJobs; llvm::StringRef thinLTOJobs;
bool demangle = false; bool demangle = false;
llvm::MachO::Target target;
PlatformInfo platformInfo; PlatformInfo platformInfo;
NamespaceKind namespaceKind = NamespaceKind::twolevel; NamespaceKind namespaceKind = NamespaceKind::twolevel;
UndefinedSymbolTreatment undefinedSymbolTreatment = UndefinedSymbolTreatment undefinedSymbolTreatment =

View File

@ -616,9 +616,10 @@ static TargetInfo *createTargetInfo(InputArgList &args) {
fatal("must specify -arch"); fatal("must specify -arch");
PlatformKind platform = parsePlatformVersion(args); PlatformKind platform = parsePlatformVersion(args);
config->target = MachO::Target(getArchitectureFromName(archName), platform); config->platformInfo.target =
MachO::Target(getArchitectureFromName(archName), platform);
switch (getCPUTypeFromArchitecture(config->target.Arch).first) { switch (getCPUTypeFromArchitecture(config->platformInfo.target.Arch).first) {
case CPU_TYPE_X86_64: case CPU_TYPE_X86_64:
return createX86_64TargetInfo(); return createX86_64TargetInfo();
case CPU_TYPE_ARM64: case CPU_TYPE_ARM64:
@ -699,17 +700,18 @@ static const char *getReproduceOption(InputArgList &args) {
static bool isPie(InputArgList &args) { static bool isPie(InputArgList &args) {
if (config->outputType != MH_EXECUTE || args.hasArg(OPT_no_pie)) if (config->outputType != MH_EXECUTE || args.hasArg(OPT_no_pie))
return false; return false;
if (config->target.Arch == AK_arm64 || config->target.Arch == AK_arm64e || if (config->platformInfo.target.Arch == AK_arm64 ||
config->target.Arch == AK_arm64_32) config->platformInfo.target.Arch == AK_arm64e ||
config->platformInfo.target.Arch == AK_arm64_32)
return true; return true;
// TODO: add logic here as we support more archs. E.g. i386 should default // TODO: add logic here as we support more archs. E.g. i386 should default
// to PIE from 10.7 // to PIE from 10.7
assert(config->target.Arch == AK_x86_64 || assert(config->platformInfo.target.Arch == AK_x86_64 ||
config->target.Arch == AK_x86_64h || config->platformInfo.target.Arch == AK_x86_64h ||
config->target.Arch == AK_arm64_32); config->platformInfo.target.Arch == AK_arm64_32);
PlatformKind kind = config->target.Platform; PlatformKind kind = config->platformInfo.target.Platform;
if (kind == PlatformKind::macOS && if (kind == PlatformKind::macOS &&
config->platformInfo.minimum >= VersionTuple(10, 6)) config->platformInfo.minimum >= VersionTuple(10, 6))
return true; return true;
@ -1029,7 +1031,7 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
StringRef segName = arg->getValue(0); StringRef segName = arg->getValue(0);
uint32_t maxProt = parseProtection(arg->getValue(1)); uint32_t maxProt = parseProtection(arg->getValue(1));
uint32_t initProt = parseProtection(arg->getValue(2)); uint32_t initProt = parseProtection(arg->getValue(2));
if (maxProt != initProt && config->target.Arch != AK_i386) if (maxProt != initProt && config->platformInfo.target.Arch != AK_i386)
error("invalid argument '" + arg->getAsString(args) + error("invalid argument '" + arg->getAsString(args) +
"': max and init must be the same for non-i386 archs"); "': max and init must be the same for non-i386 archs");
if (segName == segment_names::linkEdit) if (segName == segment_names::linkEdit)
@ -1051,8 +1053,9 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
config->adhocCodesign = args.hasFlag( config->adhocCodesign = args.hasFlag(
OPT_adhoc_codesign, OPT_no_adhoc_codesign, OPT_adhoc_codesign, OPT_no_adhoc_codesign,
(config->target.Arch == AK_arm64 || config->target.Arch == AK_arm64e) && (config->platformInfo.target.Arch == AK_arm64 ||
config->target.Platform == PlatformKind::macOS); config->platformInfo.target.Arch == AK_arm64e) &&
config->platformInfo.target.Platform == PlatformKind::macOS);
if (args.hasArg(OPT_v)) { if (args.hasArg(OPT_v)) {
message(getLLDVersion()); message(getLLDVersion());

View File

@ -95,6 +95,71 @@ SetVector<InputFile *> macho::inputFiles;
std::unique_ptr<TarWriter> macho::tar; std::unique_ptr<TarWriter> macho::tar;
int InputFile::idCount = 0; int InputFile::idCount = 0;
static VersionTuple decodeVersion(uint32_t version) {
unsigned major = version >> 16;
unsigned minor = (version >> 8) & 0xffu;
unsigned subMinor = version & 0xffu;
return VersionTuple(major, minor, subMinor);
}
template <class LP>
static Optional<PlatformInfo> getPlatformInfo(const InputFile *input) {
if (!isa<ObjFile>(input) && !isa<DylibFile>(input))
return None;
using Header = typename LP::mach_header;
auto *hdr = reinterpret_cast<const Header *>(input->mb.getBufferStart());
PlatformInfo platformInfo;
if (const auto *cmd =
findCommand<build_version_command>(hdr, LC_BUILD_VERSION)) {
platformInfo.target.Platform = static_cast<PlatformKind>(cmd->platform);
platformInfo.minimum = decodeVersion(cmd->minos);
return platformInfo;
} else if (const auto *cmd =
findCommand<version_min_command>(hdr, LC_VERSION_MIN_MACOSX)) {
platformInfo.target.Platform = PlatformKind::macOS;
platformInfo.minimum = decodeVersion(cmd->version);
return platformInfo;
} else if (const auto *cmd = findCommand<version_min_command>(
hdr, LC_VERSION_MIN_IPHONEOS)) {
platformInfo.target.Platform = PlatformKind::iOS;
platformInfo.minimum = decodeVersion(cmd->version);
return platformInfo;
} else if (const auto *cmd =
findCommand<version_min_command>(hdr, LC_VERSION_MIN_TVOS)) {
platformInfo.target.Platform = PlatformKind::tvOS;
platformInfo.minimum = decodeVersion(cmd->version);
} else if (const auto *cmd = findCommand<version_min_command>(
hdr, LC_VERSION_MIN_WATCHOS)) {
platformInfo.target.Platform = PlatformKind::watchOS;
platformInfo.minimum = decodeVersion(cmd->version);
return platformInfo;
}
return None;
}
template <class LP> static bool checkCompatibility(const InputFile *input) {
Optional<PlatformInfo> platformInfo = getPlatformInfo<LP>(input);
if (!platformInfo)
return true;
// TODO: Correctly detect simulator platforms or relax this check.
if (config->platformInfo.target.Platform != platformInfo->target.Platform) {
error(toString(input) + " has platform " +
getPlatformName(platformInfo->target.Platform) +
Twine(", which is different from target platform ") +
getPlatformName(config->platformInfo.target.Platform));
return false;
}
if (platformInfo->minimum >= config->platformInfo.minimum)
return true;
error(toString(input) + " has version " +
platformInfo->minimum.getAsString() +
", which is incompatible with target version of " +
config->platformInfo.minimum.getAsString());
return false;
}
// Open a given file path and return it as a memory-mapped file. // Open a given file path and return it as a memory-mapped file.
Optional<MemoryBufferRef> macho::readFile(StringRef path) { Optional<MemoryBufferRef> macho::readFile(StringRef path) {
// Open a file. // Open a file.
@ -365,32 +430,6 @@ static macho::Symbol *createDefined(const NList &sym, StringRef name,
/*isExternal=*/false, /*isPrivateExtern=*/false); /*isExternal=*/false, /*isPrivateExtern=*/false);
} }
// Checks if the version specified in `cmd` is compatible with target
// version. IOW, check if cmd's version >= config's version.
static bool hasCompatVersion(const InputFile *input,
const build_version_command *cmd) {
if (config->target.Platform != static_cast<PlatformKind>(cmd->platform)) {
error(toString(input) + " has platform " +
getPlatformName(static_cast<PlatformKind>(cmd->platform)) +
Twine(", which is different from target platform ") +
getPlatformName(config->target.Platform));
return false;
}
unsigned major = cmd->minos >> 16;
unsigned minor = (cmd->minos >> 8) & 0xffu;
unsigned subMinor = cmd->minos & 0xffu;
VersionTuple version(major, minor, subMinor);
if (version >= config->platformInfo.minimum)
return true;
error(toString(input) + " has version " + version.getAsString() +
", which is incompatible with target version of " +
config->platformInfo.minimum.getAsString());
return false;
}
// Absolute symbols are defined symbols that do not have an associated // Absolute symbols are defined symbols that do not have an associated
// InputSection. They cannot be weak. // InputSection. They cannot be weak.
template <class NList> template <class NList>
@ -542,18 +581,15 @@ template <class LP> void ObjFile::parse() {
auto *hdr = reinterpret_cast<const Header *>(mb.getBufferStart()); auto *hdr = reinterpret_cast<const Header *>(mb.getBufferStart());
Architecture arch = getArchitectureFromCpuType(hdr->cputype, hdr->cpusubtype); Architecture arch = getArchitectureFromCpuType(hdr->cputype, hdr->cpusubtype);
if (arch != config->target.Arch) { if (arch != config->platformInfo.target.Arch) {
error(toString(this) + " has architecture " + getArchitectureName(arch) + error(toString(this) + " has architecture " + getArchitectureName(arch) +
" which is incompatible with target architecture " + " which is incompatible with target architecture " +
getArchitectureName(config->target.Arch)); getArchitectureName(config->platformInfo.target.Arch));
return; return;
} }
if (const auto *cmd = if (!checkCompatibility<LP>(this))
findCommand<build_version_command>(hdr, LC_BUILD_VERSION)) {
if (!hasCompatVersion(this, cmd))
return; return;
}
if (const load_command *cmd = findCommand(hdr, LC_LINKER_OPTION)) { if (const load_command *cmd = findCommand(hdr, LC_LINKER_OPTION)) {
auto *c = reinterpret_cast<const linker_option_command *>(cmd); auto *c = reinterpret_cast<const linker_option_command *>(cmd);
@ -719,11 +755,8 @@ template <class LP> void DylibFile::parse(DylibFile *umbrella) {
return; return;
} }
if (const build_version_command *cmd = if (!checkCompatibility<LP>(this))
findCommand<build_version_command>(hdr, LC_BUILD_VERSION)) {
if (!hasCompatVersion(this, cmd))
return; return;
}
// Initialize symbols. // Initialize symbols.
DylibFile *exportingFile = isImplicitlyLinked(dylibName) ? this : umbrella; DylibFile *exportingFile = isImplicitlyLinked(dylibName) ? this : umbrella;
@ -791,9 +824,9 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
"/usr/lib/system/libsystem_pthread.dylib"}; "/usr/lib/system/libsystem_pthread.dylib"};
if (!is_contained(skipPlatformChecks, dylibName) && if (!is_contained(skipPlatformChecks, dylibName) &&
!is_contained(interface.targets(), config->target)) { !is_contained(interface.targets(), config->platformInfo.target)) {
error(toString(this) + " is incompatible with " + error(toString(this) + " is incompatible with " +
std::string(config->target)); std::string(config->platformInfo.target));
return; return;
} }
@ -806,7 +839,7 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
// TODO(compnerd) filter out symbols based on the target platform // TODO(compnerd) filter out symbols based on the target platform
// TODO: handle weak defs, thread locals // TODO: handle weak defs, thread locals
for (const auto *symbol : interface.symbols()) { for (const auto *symbol : interface.symbols()) {
if (!symbol->getArchitectures().has(config->target.Arch)) if (!symbol->getArchitectures().has(config->platformInfo.target.Arch))
continue; continue;
switch (symbol->getKind()) { switch (symbol->getKind()) {
@ -834,7 +867,7 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
for (InterfaceFileRef intfRef : interface.reexportedLibraries()) { for (InterfaceFileRef intfRef : interface.reexportedLibraries()) {
InterfaceFile::const_target_range targets = intfRef.targets(); InterfaceFile::const_target_range targets = intfRef.targets();
if (is_contained(skipPlatformChecks, intfRef.getInstallName()) || if (is_contained(skipPlatformChecks, intfRef.getInstallName()) ||
is_contained(targets, config->target)) is_contained(targets, config->platformInfo.target))
loadReexport(intfRef.getInstallName(), exportingFile, topLevel); loadReexport(intfRef.getInstallName(), exportingFile, topLevel);
} }
} }

View File

@ -37,6 +37,7 @@ class TarWriter;
namespace lld { namespace lld {
namespace macho { namespace macho {
struct PlatformInfo;
class InputSection; class InputSection;
class Symbol; class Symbol;
struct Reloc; struct Reloc;

View File

@ -117,8 +117,9 @@ std::vector<ObjFile *> BitcodeCompiler::compile() {
uint32_t modTime = 0; uint32_t modTime = 0;
if (!config->ltoObjPath.empty()) { if (!config->ltoObjPath.empty()) {
filePath = config->ltoObjPath; filePath = config->ltoObjPath;
path::append(filePath, Twine(i) + "." + path::append(filePath,
getArchitectureName(config->target.Arch) + Twine(i) + "." +
getArchitectureName(config->platformInfo.target.Arch) +
".lto.o"); ".lto.o");
saveBuffer(buf[i], filePath); saveBuffer(buf[i], filePath);
modTime = getModTime(filePath); modTime = getModTime(filePath);

View File

@ -108,8 +108,9 @@ void macho::writeMapFile() {
os << format("# Path: %s\n", config->outputFile.str().c_str()); os << format("# Path: %s\n", config->outputFile.str().c_str());
// Dump output architecture. // Dump output architecture.
os << format("# Arch: %s\n", os << format(
getArchitectureName(config->target.Arch).str().c_str()); "# Arch: %s\n",
getArchitectureName(config->platformInfo.target.Arch).str().c_str());
// Dump table of object files. // Dump table of object files.
os << "# Object files:\n"; os << "# Object files:\n";

View File

@ -37,7 +37,7 @@ static uint32_t initProt(StringRef name) {
} }
static uint32_t maxProt(StringRef name) { static uint32_t maxProt(StringRef name) {
assert(config->target.Arch != AK_i386 && assert(config->platformInfo.target.Arch != AK_i386 &&
"TODO: i386 has different maxProt requirements"); "TODO: i386 has different maxProt requirements");
return initProt(name); return initProt(name);
} }

View File

@ -93,7 +93,7 @@ static uint32_t cpuSubtype() {
if (config->outputType == MH_EXECUTE && !config->staticLink && if (config->outputType == MH_EXECUTE && !config->staticLink &&
target->cpuSubtype == CPU_SUBTYPE_X86_64_ALL && target->cpuSubtype == CPU_SUBTYPE_X86_64_ALL &&
config->target.Platform == PlatformKind::macOS && config->platformInfo.target.Platform == PlatformKind::macOS &&
config->platformInfo.minimum >= VersionTuple(10, 5)) config->platformInfo.minimum >= VersionTuple(10, 5))
subtype |= CPU_SUBTYPE_LIB64; subtype |= CPU_SUBTYPE_LIB64;

View File

@ -359,10 +359,54 @@ private:
StringRef path; StringRef path;
}; };
static uint32_t encodeVersion(const VersionTuple &version) {
return ((version.getMajor() << 020) |
(version.getMinor().getValueOr(0) << 010) |
version.getSubminor().getValueOr(0));
}
class LCMinVersion : public LoadCommand {
public:
explicit LCMinVersion(const PlatformInfo &platformInfo)
: platformInfo(platformInfo) {}
uint32_t getSize() const override { return sizeof(version_min_command); }
void writeTo(uint8_t *buf) const override {
auto *c = reinterpret_cast<version_min_command *>(buf);
switch (platformInfo.target.Platform) {
case PlatformKind::macOS:
c->cmd = LC_VERSION_MIN_MACOSX;
break;
case PlatformKind::iOS:
case PlatformKind::iOSSimulator:
c->cmd = LC_VERSION_MIN_IPHONEOS;
break;
case PlatformKind::tvOS:
case PlatformKind::tvOSSimulator:
c->cmd = LC_VERSION_MIN_TVOS;
break;
case PlatformKind::watchOS:
case PlatformKind::watchOSSimulator:
c->cmd = LC_VERSION_MIN_WATCHOS;
break;
default:
llvm_unreachable("invalid platform");
break;
}
c->cmdsize = getSize();
c->version = encodeVersion(platformInfo.minimum);
c->sdk = encodeVersion(platformInfo.sdk);
}
private:
const PlatformInfo &platformInfo;
};
class LCBuildVersion : public LoadCommand { class LCBuildVersion : public LoadCommand {
public: public:
LCBuildVersion(PlatformKind platform, const PlatformInfo &platformInfo) explicit LCBuildVersion(const PlatformInfo &platformInfo)
: platform(platform), platformInfo(platformInfo) {} : platformInfo(platformInfo) {}
const int ntools = 1; const int ntools = 1;
@ -374,21 +418,17 @@ public:
auto *c = reinterpret_cast<build_version_command *>(buf); auto *c = reinterpret_cast<build_version_command *>(buf);
c->cmd = LC_BUILD_VERSION; c->cmd = LC_BUILD_VERSION;
c->cmdsize = getSize(); c->cmdsize = getSize();
c->platform = static_cast<uint32_t>(platform); c->platform = static_cast<uint32_t>(platformInfo.target.Platform);
c->minos = ((platformInfo.minimum.getMajor() << 020) | c->minos = encodeVersion(platformInfo.minimum);
(platformInfo.minimum.getMinor().getValueOr(0) << 010) | c->sdk = encodeVersion(platformInfo.sdk);
platformInfo.minimum.getSubminor().getValueOr(0));
c->sdk = ((platformInfo.sdk.getMajor() << 020) |
(platformInfo.sdk.getMinor().getValueOr(0) << 010) |
platformInfo.sdk.getSubminor().getValueOr(0));
c->ntools = ntools; c->ntools = ntools;
auto *t = reinterpret_cast<build_tool_version *>(&c[1]); auto *t = reinterpret_cast<build_tool_version *>(&c[1]);
t->tool = TOOL_LD; t->tool = TOOL_LD;
t->version = (LLVM_VERSION_MAJOR << 020) | (LLVM_VERSION_MINOR << 010) | t->version = encodeVersion(llvm::VersionTuple(
LLVM_VERSION_PATCH; LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH));
} }
PlatformKind platform; private:
const PlatformInfo &platformInfo; const PlatformInfo &platformInfo;
}; };
@ -553,6 +593,20 @@ void Writer::scanSymbols() {
} }
} }
// TODO: ld64 enforces the old load commands in a few other cases.
static bool useLCBuildVersion(const PlatformInfo &platformInfo) {
static const std::map<PlatformKind, llvm::VersionTuple> minVersion = {
{PlatformKind::macOS, llvm::VersionTuple(10, 14)},
{PlatformKind::iOS, llvm::VersionTuple(12, 0)},
{PlatformKind::iOSSimulator, llvm::VersionTuple(13, 0)},
{PlatformKind::tvOS, llvm::VersionTuple(12, 0)},
{PlatformKind::tvOSSimulator, llvm::VersionTuple(13, 0)},
{PlatformKind::watchOS, llvm::VersionTuple(5, 0)},
{PlatformKind::watchOSSimulator, llvm::VersionTuple(6, 0)}};
auto it = minVersion.find(platformInfo.target.Platform);
return it == minVersion.end() ? true : platformInfo.minimum >= it->second;
}
template <class LP> void Writer::createLoadCommands() { template <class LP> void Writer::createLoadCommands() {
uint8_t segIndex = 0; uint8_t segIndex = 0;
for (OutputSegment *seg : outputSegments) { for (OutputSegment *seg : outputSegments) {
@ -589,8 +643,10 @@ template <class LP> void Writer::createLoadCommands() {
uuidCommand = make<LCUuid>(); uuidCommand = make<LCUuid>();
in.header->addLoadCommand(uuidCommand); in.header->addLoadCommand(uuidCommand);
in.header->addLoadCommand( if (useLCBuildVersion(config->platformInfo))
make<LCBuildVersion>(config->target.Platform, config->platformInfo)); in.header->addLoadCommand(make<LCBuildVersion>(config->platformInfo));
else
in.header->addLoadCommand(make<LCMinVersion>(config->platformInfo));
int64_t dylibOrdinal = 1; int64_t dylibOrdinal = 1;
for (InputFile *file : inputFiles) { for (InputFile *file : inputFiles) {

View File

@ -1,16 +1,68 @@
# REQUIRES: x86 # REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
# RUN: %lld -platform_version macos 10.14.1 10.15 -o %t %t.o
# RUN: llvm-objdump --macho --all-headers %t | FileCheck %s
# CHECK: cmd LC_BUILD_VERSION # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
# CHECK-NEXT: cmdsize 32
# CHECK-NEXT: platform macos # RUN: %lld -platform_version macos 10.14 10.15 -o %t.macos_10_14 %t.o
# CHECK-NEXT: sdk 10.15 # RUN: llvm-objdump --macho --all-headers %t.macos_10_14 | FileCheck %s --check-prefix=MACOS_10_14
# CHECK-NEXT: minos 10.14.1
# CHECK-NEXT: ntools 1 # MACOS_10_14: cmd LC_BUILD_VERSION
# CHECK-NEXT: tool ld # MACOS_10_14-NEXT: cmdsize 32
# CHECK-NEXT: version {{[0-9\.]+}} # MACOS_10_14-NEXT: platform macos
# MACOS_10_14-NEXT: sdk 10.15
# MACOS_10_14-NEXT: minos 10.14
# MACOS_10_14-NEXT: ntools 1
# MACOS_10_14-NEXT: tool ld
# MACOS_10_14-NEXT: version {{[0-9\.]+}}
# RUN: %lld -platform_version macos 10.13 10.15 -o %t.macos_10_13 %t.o
# RUN: llvm-objdump --macho --all-headers %t.macos_10_13 | FileCheck %s --check-prefix=MACOS_10_13
# MACOS_10_13: cmd LC_VERSION_MIN_MACOSX
# MACOS_10_13-NEXT: cmdsize 16
# MACOS_10_13-NEXT: version 10.13
# MACOS_10_13-NEXT: sdk 10.15
# RUN: %lld -platform_version ios 12.0 10.15 -o %t.ios_12_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.ios_12_0 | FileCheck %s --check-prefix=IOS_12_0
# RUN: %lld -platform_version ios-simulator 13.0 10.15 -o %t.ios_sim_13_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.ios_sim_13_0 | FileCheck %s --check-prefix=IOS_12_0
# IOS_12_0: cmd LC_BUILD_VERSION
# RUN: %lld -platform_version ios 11.0 10.15 -o %t.ios_11_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.ios_11_0 | FileCheck %s --check-prefix=IOS_11_0
# RUN: %lld -platform_version ios-simulator 12.0 10.15 -o %t.ios_sim_12_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.ios_sim_12_0 | FileCheck %s --check-prefix=IOS_11_0
# IOS_11_0: cmd LC_VERSION_MIN_IPHONEOS
# RUN: %lld -platform_version tvos 12.0 10.15 -o %t.tvos_12_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.tvos_12_0 | FileCheck %s --check-prefix=TVOS_12_0
# RUN: %lld -platform_version tvos-simulator 13.0 10.15 -o %t.tvos_sim_13_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.tvos_sim_13_0 | FileCheck %s --check-prefix=TVOS_12_0
# TVOS_12_0: cmd LC_BUILD_VERSION
# RUN: %lld -platform_version tvos 11.0 10.15 -o %t.tvos_11_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.tvos_11_0 | FileCheck %s --check-prefix=TVOS_11_0
# RUN: %lld -platform_version tvos-simulator 12.0 10.15 -o %t.tvos_sim_12_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.tvos_sim_12_0 | FileCheck %s --check-prefix=TVOS_11_0
# TVOS_11_0: cmd LC_VERSION_MIN_TVOS
# RUN: %lld -platform_version watchos 5.0 10.15 -o %t.watchos_5_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.watchos_5_0 | FileCheck %s --check-prefix=WATCHOS_5_0
# RUN: %lld -platform_version watchos-simulator 6.0 10.15 -o %t.watchos_sim_6_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.watchos_sim_6_0 | FileCheck %s --check-prefix=WATCHOS_5_0
# WATCHOS_5_0: cmd LC_BUILD_VERSION
# RUN: %lld -platform_version watchos 4.0 10.15 -o %t.watchos_4_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.watchos_4_0 | FileCheck %s --check-prefix=WATCHOS_4_0
# RUN: %lld -platform_version watchos-simulator 5.0 10.15 -o %t.watchos_sim_5_0 %t.o
# RUN: llvm-objdump --macho --all-headers %t.watchos_sim_5_0 | FileCheck %s --check-prefix=WATCHOS_4_0
# WATCHOS_4_0: cmd LC_VERSION_MIN_WATCHOS
.text .text
.global _main .global _main

View File

@ -47,7 +47,7 @@
# DYLIB: cmd LC_ID_DYLIB # DYLIB: cmd LC_ID_DYLIB
# COMMON: cmd LC_UUID # COMMON: cmd LC_UUID
# COMMON: cmd LC_BUILD_VERSION # COMMON: cmd LC_VERSION_MIN_MACOSX
# COMMON: cmd LC_LOAD_DYLIB # COMMON: cmd LC_LOAD_DYLIB
.section __TEXT,__cstring .section __TEXT,__cstring

View File

@ -12,12 +12,12 @@
## address offset and the contents at that address very similarly, so am using ## address offset and the contents at that address very similarly, so am using
## --match-full-lines to make sure we match on the right thing. ## --match-full-lines to make sure we match on the right thing.
# CHECK: Contents of section __TEXT,__cstring: # CHECK: Contents of section __TEXT,__cstring:
# CHECK-NEXT: 100000434 {{.*}} # CHECK-NEXT: 100000424 {{.*}}
## 1st 8 bytes refer to the start of __cstring + 0xe, 2nd 8 bytes refer to the ## 1st 8 bytes refer to the start of __cstring + 0xe, 2nd 8 bytes refer to the
## start of __cstring ## start of __cstring
# CHECK: Contents of section __DATA_CONST,__got: # CHECK: Contents of section __DATA_CONST,__got:
# CHECK-NEXT: [[#%X,ADDR:]] 42040000 01000000 34040000 01000000 {{.*}} # CHECK-NEXT: [[#%X,ADDR:]] 32040000 01000000 24040000 01000000 {{.*}}
# CHECK-NEXT: [[#ADDR + 16]] 00000000 00000000 {{.*}} # CHECK-NEXT: [[#ADDR + 16]] 00000000 00000000 {{.*}}
## Check that the rebase table is empty. ## Check that the rebase table is empty.

View File

@ -21,7 +21,7 @@
# RUN: llvm-objdump --section=__const --full-contents %t | FileCheck %s --check-prefix=NONPCREL # RUN: llvm-objdump --section=__const --full-contents %t | FileCheck %s --check-prefix=NONPCREL
# NONPCREL: Contents of section __DATA,__const: # NONPCREL: Contents of section __DATA,__const:
# NONPCREL-NEXT: 100001000 18040000 01000000 18040000 01000000 # NONPCREL-NEXT: 100001000 08040000 01000000 08040000 01000000
.section __TEXT,__text .section __TEXT,__text
.globl _main, _f .globl _main, _f