summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/lib/ReaderWriter/MachO/File.h12
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFile.h1
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp9
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp68
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp58
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp2
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp9
-rw-r--r--lld/test/mach-o/Inputs/no-version-min-load-command-object.yaml22
-rw-r--r--lld/test/mach-o/version-min-load-command-object.yaml35
9 files changed, 184 insertions, 32 deletions
diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h
index f282d5da204..a0d20ea540f 100644
--- a/lld/lib/ReaderWriter/MachO/File.h
+++ b/lld/lib/ReaderWriter/MachO/File.h
@@ -201,6 +201,16 @@ public:
_objcConstraint = v;
}
+ uint32_t minVersion() const { return _minVersion; }
+ void setMinVersion(uint32_t v) { _minVersion = v; }
+
+ LoadCommandType minVersionLoadCommandKind() const {
+ return _minVersionLoadCommandKind;
+ }
+ void setMinVersionLoadCommandKind(LoadCommandType v) {
+ _minVersionLoadCommandKind = v;
+ }
+
uint32_t swiftVersion() const { return _swiftVersion; }
void setSwiftVersion(uint32_t v) { _swiftVersion = v; }
@@ -249,6 +259,8 @@ private:
NameToAtom _undefAtoms;
MachOLinkingContext::Arch _arch = MachOLinkingContext::arch_unknown;
MachOLinkingContext::OS _os = MachOLinkingContext::OS::unknown;
+ uint32_t _minVersion = 0;
+ LoadCommandType _minVersionLoadCommandKind = (LoadCommandType)0;
MachOLinkingContext::ObjCConstraint _objcConstraint =
MachOLinkingContext::objc_unknown;
uint32_t _swiftVersion = 0;
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
index d2b4806565d..6dab8babe65 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
@@ -253,6 +253,7 @@ struct NormalizedFile {
Hex64 sourceVersion = 0;
PackedVersion minOSverson = 0;
PackedVersion sdkVersion = 0;
+ LoadCommandType minOSVersionKind = (LoadCommandType)0;
// Maps to load commands with LINKEDIT content (final linked images only).
Hex32 pageSize = 0;
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
index 1013d3ddaef..7a9dd4b7fb9 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -471,6 +471,15 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
case LC_DYLD_INFO_ONLY:
dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
break;
+ case LC_VERSION_MIN_MACOSX:
+ case LC_VERSION_MIN_IPHONEOS:
+ case LC_VERSION_MIN_WATCHOS:
+ case LC_VERSION_MIN_TVOS:
+ // If we are emitting an object file, then we may take the load command
+ // kind from these commands and pass it on to the output
+ // file.
+ f->minOSVersionKind = (LoadCommandType)cmd;
+ break;
}
return false;
});
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
index d46cf2ce386..0eb2b11eaaa 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -317,6 +317,10 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
+ file.sections.size() * sectsSize
+ sizeof(symtab_command);
_countOfLoadCommands = 2;
+ if (file.hasMinVersionLoadCommand) {
+ _endOfLoadCommands += sizeof(version_min_command);
+ _countOfLoadCommands++;
+ }
if (!_file.dataInCode.empty()) {
_endOfLoadCommands += sizeof(linkedit_data_command);
_countOfLoadCommands++;
@@ -738,6 +742,38 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
return std::error_code();
}
+static void writeVersionMinLoadCommand(const NormalizedFile &_file,
+ bool _swap,
+ uint8_t *&lc) {
+ if (!_file.hasMinVersionLoadCommand)
+ return;
+ version_min_command *vm = reinterpret_cast<version_min_command*>(lc);
+ switch (_file.os) {
+ case MachOLinkingContext::OS::unknown:
+ vm->cmd = _file.minOSVersionKind;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = 0;
+ break;
+ case MachOLinkingContext::OS::macOSX:
+ vm->cmd = LC_VERSION_MIN_MACOSX;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = _file.sdkVersion;
+ break;
+ case MachOLinkingContext::OS::iOS:
+ case MachOLinkingContext::OS::iOS_simulator:
+ vm->cmd = LC_VERSION_MIN_IPHONEOS;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = _file.sdkVersion;
+ break;
+ }
+ if (_swap)
+ swapStruct(*vm);
+ lc += sizeof(version_min_command);
+}
+
std::error_code MachOFileLayout::writeLoadCommands() {
std::error_code ec;
uint8_t *lc = &_buffer[_startOfLoadCommands];
@@ -759,6 +795,11 @@ std::error_code MachOFileLayout::writeLoadCommands() {
if (_swap)
swapStruct(*st);
lc += sizeof(symtab_command);
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
+ // LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS
+ writeVersionMinLoadCommand(_file, _swap, lc);
+
// Add LC_DATA_IN_CODE if needed.
if (_dataInCodeSize != 0) {
linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
@@ -872,32 +913,7 @@ std::error_code MachOFileLayout::writeLoadCommands() {
// Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
// LC_VERSION_MIN_TVOS
- if (_file.hasMinVersionLoadCommand) {
- version_min_command *vm = reinterpret_cast<version_min_command*>(lc);
- switch (_file.os) {
- case MachOLinkingContext::OS::unknown:
- // TODO: We need to emit the load command if we managed to derive
- // a platform from one of the files we are linking.
- llvm_unreachable("Version commands for unknown OS aren't supported");
- break;
- case MachOLinkingContext::OS::macOSX:
- vm->cmd = LC_VERSION_MIN_MACOSX;
- vm->cmdsize = sizeof(version_min_command);
- vm->version = _file.minOSverson;
- vm->sdk = _file.sdkVersion;
- break;
- case MachOLinkingContext::OS::iOS:
- case MachOLinkingContext::OS::iOS_simulator:
- vm->cmd = LC_VERSION_MIN_MACOSX;
- vm->cmdsize = sizeof(version_min_command);
- vm->version = _file.minOSverson;
- vm->sdk = _file.sdkVersion;
- break;
- }
- if (_swap)
- swapStruct(*vm);
- lc += sizeof(version_min_command);
- }
+ writeVersionMinLoadCommand(_file, _swap, lc);
// If main executable, add LC_MAIN.
if (_file.fileType == llvm::MachO::MH_EXECUTE) {
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index a2b33796b8f..087b557bf8d 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -128,6 +128,18 @@ public:
void copyEntryPointAddress(NormalizedFile &file);
void copySectionContent(NormalizedFile &file);
+ bool allSourceFilesHaveMinVersions() const {
+ return _allSourceFilesHaveMinVersions;
+ }
+
+ uint32_t minVersion() const {
+ return _minVersion;
+ }
+
+ LoadCommandType minVersionCommandType() const {
+ return _minVersionCommandType;
+ }
+
private:
typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
@@ -183,6 +195,9 @@ private:
std::vector<const Atom *> _machHeaderAliasAtoms;
bool _hasTLVDescriptors;
bool _subsectionsViaSymbols;
+ bool _allSourceFilesHaveMinVersions = true;
+ LoadCommandType _minVersionCommandType = (LoadCommandType)0;
+ uint32_t _minVersion = 0;
};
Util::~Util() {
@@ -378,11 +393,25 @@ void Util::processDefinedAtoms(const lld::File &atomFile) {
}
void Util::processAtomAttributes(const DefinedAtom *atom) {
- // If the file doesn't use subsections via symbols, then make sure we don't
- // add that flag to the final output file if we have a relocatable file.
- if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file()))
+ if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) {
+ // If the file doesn't use subsections via symbols, then make sure we don't
+ // add that flag to the final output file if we have a relocatable file.
if (!machoFile->subsectionsViaSymbols())
_subsectionsViaSymbols = false;
+
+ // All the source files must have min versions for us to output an object
+ // file with a min version.
+ if (auto v = machoFile->minVersion())
+ _minVersion = std::max(_minVersion, v);
+ else
+ _allSourceFilesHaveMinVersions = false;
+
+ // If we don't have a platform load command, but one of the source files
+ // does, then take the one from the file.
+ if (!_minVersionCommandType)
+ if (auto v = machoFile->minVersionLoadCommandKind())
+ _minVersionCommandType = v;
+ }
}
void Util::assignAtomToSection(const DefinedAtom *atom) {
@@ -1245,14 +1274,31 @@ normalizedFromAtoms(const lld::File &atomFile,
normFile.currentVersion = context.currentVersion();
normFile.compatVersion = context.compatibilityVersion();
normFile.os = context.os();
- normFile.minOSverson = context.osMinVersion();
- // FIXME: We need to get the SDK version from the system. For now the min
- // OS version is better than nothing.
+
+ // If we are emitting an object file, then the min version is the maximum
+ // of the min's of all the source files and the cmdline.
+ if (normFile.fileType == llvm::MachO::MH_OBJECT)
+ normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion());
+ else
+ normFile.minOSverson = context.osMinVersion();
+
+ normFile.minOSVersionKind = util.minVersionCommandType();
+
normFile.sdkVersion = context.sdkVersion();
if (context.generateVersionLoadCommand() &&
context.os() != MachOLinkingContext::OS::unknown)
normFile.hasMinVersionLoadCommand = true;
+ else if (normFile.fileType == llvm::MachO::MH_OBJECT &&
+ util.allSourceFilesHaveMinVersions() &&
+ ((normFile.os != MachOLinkingContext::OS::unknown) ||
+ util.minVersionCommandType())) {
+ // If we emit an object file, then it should contain a min version load
+ // command if all of the source files also contained min version commands.
+ // Also, we either need to have a platform, or found a platform from the
+ // source object files.
+ normFile.hasMinVersionLoadCommand = true;
+ }
normFile.pageSize = context.pageSize();
normFile.rpaths = context.rpaths();
util.addDependentDylibs(atomFile, normFile);
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index 80f2038d98b..3d4457ab912 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -1061,6 +1061,8 @@ normalizedObjectToAtoms(MachOFile *file,
file->setFlags(normalizedFile.flags);
file->setArch(normalizedFile.arch);
file->setOS(normalizedFile.os);
+ file->setMinVersion(normalizedFile.minOSverson);
+ file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind);
// Sort references in each atom to their canonical order.
for (const DefinedAtom* defAtom : file->defined()) {
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
index 0b92a68eeae..c795a72530a 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
@@ -524,6 +524,14 @@ struct ScalarEnumerationTraits<LoadCommandType> {
llvm::MachO::LC_LOAD_UPWARD_DYLIB);
io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
llvm::MachO::LC_LAZY_LOAD_DYLIB);
+ io.enumCase(value, "LC_VERSION_MIN_MACOSX",
+ llvm::MachO::LC_VERSION_MIN_MACOSX);
+ io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
+ llvm::MachO::LC_VERSION_MIN_IPHONEOS);
+ io.enumCase(value, "LC_VERSION_MIN_TVOS",
+ llvm::MachO::LC_VERSION_MIN_TVOS);
+ io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
+ llvm::MachO::LC_VERSION_MIN_WATCHOS);
}
};
@@ -692,6 +700,7 @@ struct MappingTraits<NormalizedFile> {
io.mapOptional("source-version", file.sourceVersion, Hex64(0));
io.mapOptional("OS", file.os);
io.mapOptional("min-os-version", file.minOSverson, PackedVersion(0));
+ io.mapOptional("min-os-version-kind", file.minOSVersionKind, (LoadCommandType)0);
io.mapOptional("sdk-version", file.sdkVersion, PackedVersion(0));
io.mapOptional("segments", file.segments);
io.mapOptional("sections", file.sections);
diff --git a/lld/test/mach-o/Inputs/no-version-min-load-command-object.yaml b/lld/test/mach-o/Inputs/no-version-min-load-command-object.yaml
new file mode 100644
index 00000000000..35f83c6fd08
--- /dev/null
+++ b/lld/test/mach-o/Inputs/no-version-min-load-command-object.yaml
@@ -0,0 +1,22 @@
+
+# This object file has no version min and so will prevent any -r link from emitting
+# a version min.
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _main2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+...
diff --git a/lld/test/mach-o/version-min-load-command-object.yaml b/lld/test/mach-o/version-min-load-command-object.yaml
new file mode 100644
index 00000000000..33001cc6f71
--- /dev/null
+++ b/lld/test/mach-o/version-min-load-command-object.yaml
@@ -0,0 +1,35 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r -macosx_version_min 10.8 && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r && llvm-objdump -private-headers %t | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r %p/Inputs/no-version-min-load-command-object.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN
+
+# If we are emitting an object file, then we only emit a min version load command if the source object file(s) all have
+# version(s) and either known platforms or contain min version load commands themselves.
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+min-os-version-kind: LC_VERSION_MIN_MACOSX
+min-os-version: 10.8
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+...
+
+# CHECK: Load command {{[0-9]*}}
+# CHECK: cmd LC_VERSION_MIN_MACOSX
+# CHECK: cmdsize 16
+# CHECK: version 10.8
+# CHECK: sdk n/a
+
+# NO_VERSION_MIN-NOT: LC_VERSION_MIN_MACOSX \ No newline at end of file
OpenPOWER on IntegriCloud