/// search paths to allow indirect dylibs to be overridden.
mach_o::MachODylibFile* findIndirectDylib(StringRef path);
+ uint32_t dylibCurrentVersion(StringRef installName) const;
+
+ uint32_t dylibCompatVersion(StringRef installName) const;
+
/// Creates a copy (owned by this MachOLinkingContext) of a string.
StringRef copy(StringRef str) { return str.copy(_allocator); }
class MachODylibFile : public SharedLibraryFile {
public:
- MachODylibFile(StringRef path, StringRef installName)
- : SharedLibraryFile(path), _installName(installName) {
+ MachODylibFile(StringRef path, StringRef installName, uint32_t compatVersion,
+ uint32_t currentVersion)
+ : SharedLibraryFile(path), _installName(installName),
+ _currentVersion(currentVersion), _compatVersion(compatVersion) {
}
const SharedLibraryAtom *exports(StringRef name,
StringRef installName() { return _installName; }
+ uint32_t currentVersion() { return _currentVersion; }
+
+ uint32_t compatVersion() { return _compatVersion; }
+
typedef std::function<MachODylibFile *(StringRef)> FindDylib;
void loadReExportedDylibs(FindDylib find) {
bool weakDef;
};
- StringRef _installName;
+ StringRef _installName;
+ uint32_t _currentVersion;
+ uint32_t _compatVersion;
atom_collection_vector<DefinedAtom> _definedAtoms;
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
return nullptr;
}
+uint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const {
+ auto pos = _pathToDylibMap.find(installName);
+ if (pos != _pathToDylibMap.end())
+ return pos->second->currentVersion();
+ else
+ return 0x1000; // 1.0
+}
+
+uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {
+ auto pos = _pathToDylibMap.find(installName);
+ if (pos != _pathToDylibMap.end())
+ return pos->second->compatVersion();
+ else
+ return 0x1000; // 1.0
+}
+
bool MachOLinkingContext::createImplicitFiles(
std::vector<std::unique_ptr<File> > &result) {
// Add indirect dylibs by asking each linked dylib to add its indirects.
-//===- lib/ReaderWriter/MachO/NormalizedFile.h ----------------------===//
+//===- lib/ReaderWriter/MachO/MachONormalizedFile.h -----------------------===//
//
// The LLVM Linker
//
/// A typedef so that YAML I/O can (de/en)code the protection bits of a segment.
LLVM_YAML_STRONG_TYPEDEF(uint32_t, VMProtect)
+/// A typedef to hold verions X.Y.X packed into 32-bit xxxx.yy.zz
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, PackedVersion)
+
/// Segments are only used in normalized final linked images (not in relocatable
/// object files). They specify how a range of the file is loaded.
struct Segment {
struct DependentDylib {
StringRef path;
LoadCommandType kind;
+ PackedVersion compatVersion;
+ PackedVersion currentVersion;
};
/// A normalized rebasing entry. Only used in normalized final linked images.
/// A typedef so that YAML I/O can encode/decode mach_header.flags.
LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags)
-
///
struct NormalizedFile {
NormalizedFile() : arch(MachOLinkingContext::arch_unknown),
// Maps to load commands with no LINKEDIT content (final linked images only).
std::vector<DependentDylib> dependentDylibs;
- StringRef installName;
+ StringRef installName; // dylibs only
+ PackedVersion compatVersion; // dylibs only
+ PackedVersion currentVersion; // dylibs only
bool hasUUID;
std::vector<StringRef> rpaths;
Hex64 entryAddress;
MachOLinkingContext::OS os;
Hex64 sourceVersion;
- Hex32 minOSverson;
- Hex32 sdkVersion;
+ PackedVersion minOSverson;
+ PackedVersion sdkVersion;
// Maps to load commands with LINKEDIT content (final linked images only).
Hex32 pageSize;
DependentDylib entry;
entry.path = lc + read32(&dl->dylib.name, isBig);
entry.kind = LoadCommandType(cmd);
+ entry.compatVersion = read32(&dl->dylib.compatibility_version, isBig);
+ entry.currentVersion = read32(&dl->dylib.current_version, isBig);
f->dependentDylibs.push_back(entry);
- }
+ }
break;
case LC_DYLD_INFO:
case LC_DYLD_INFO_ONLY:
dc->cmd = LC_ID_DYLIB;
dc->cmdsize = size;
dc->dylib.name = sizeof(dylib_command); // offset
- dc->dylib.timestamp = 0; // FIXME
- dc->dylib.current_version = 0; // FIXME
- dc->dylib.compatibility_version = 0; // FIXME
+ dc->dylib.timestamp = 2;
+ dc->dylib.current_version = _file.currentVersion;
+ dc->dylib.compatibility_version = _file.compatVersion;
if (_swap)
swapStruct(*dc);
memcpy(lc + sizeof(dylib_command), path.begin(), path.size());
dc->cmd = dep.kind;
dc->cmdsize = size;
dc->dylib.name = sizeof(dylib_command); // offset
- dc->dylib.timestamp = 0; // FIXME
- dc->dylib.current_version = 0; // FIXME
- dc->dylib.compatibility_version = 0; // FIXME
+ dc->dylib.timestamp = 2;
+ dc->dylib.current_version = dep.currentVersion;
+ dc->dylib.compatibility_version = dep.compatVersion;
if (_swap)
swapStruct(*dc);
memcpy(lc+sizeof(dylib_command), dep.path.begin(), dep.path.size());
DependentDylib depInfo;
depInfo.path = loadPath;
depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
+ depInfo.currentVersion = _context.dylibCurrentVersion(loadPath);
+ depInfo.compatVersion = _context.dylibCompatVersion(loadPath);
nFile.dependentDylibs.push_back(depInfo);
} else {
if ( slAtom->canBeNullAtRuntime() )
normFile.fileType = context.outputMachOType();
normFile.flags = util.fileFlags();
normFile.installName = context.installName();
+ normFile.currentVersion = context.currentVersion();
+ normFile.compatVersion = context.compatibilityVersion();
normFile.pageSize = context.pageSize();
util.addDependentDylibs(atomFile, normFile);
util.copySegmentInfo(normFile);
bool copyRefs) {
// Instantiate SharedLibraryFile object.
std::unique_ptr<MachODylibFile> file(
- new MachODylibFile(path, normalizedFile.installName));
+ new MachODylibFile(path, normalizedFile.installName,
+ normalizedFile.compatVersion,
+ normalizedFile.currentVersion));
// Tell MachODylibFile object about all symbols it exports.
if (!normalizedFile.exportInfo.empty()) {
// If exports trie exists, use it instead of traditional symbol table.
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
template <>
struct MappingTraits<DependentDylib> {
static void mapping(IO &io, DependentDylib& dylib) {
- io.mapRequired("path", dylib.path);
- io.mapOptional("kind", dylib.kind, llvm::MachO::LC_LOAD_DYLIB);
+ io.mapRequired("path", dylib.path);
+ io.mapOptional("kind", dylib.kind,
+ llvm::MachO::LC_LOAD_DYLIB);
+ io.mapOptional("compat-version", dylib.compatVersion,
+ PackedVersion(0x10000));
+ io.mapOptional("current-version", dylib.currentVersion,
+ PackedVersion(0x10000));
}
};
}
};
+template <>
+struct ScalarTraits<PackedVersion> {
+ static void output(const PackedVersion &value, void*, raw_ostream &out) {
+ out << llvm::format("%d.%d", (value >> 16), (value >> 8) & 0xFF);
+ if (value & 0xFF) {
+ out << llvm::format(".%d", (value & 0xFF));
+ }
+ }
+ static StringRef input(StringRef scalar, void*, PackedVersion &result) {
+ uint32_t value;
+ if (lld::MachOLinkingContext::parsePackedVersion(scalar, value))
+ return "malformed version number";
+ result = value;
+ // Return the empty string on success,
+ return StringRef();
+ }
+ static bool mustQuote(StringRef) { return false; }
+};
template <>
struct MappingTraits<NormalizedFile> {
io.mapOptional("flags", file.flags);
io.mapOptional("dependents", file.dependentDylibs);
io.mapOptional("install-name", file.installName, StringRef());
+ io.mapOptional("compat-version", file.compatVersion, PackedVersion(0x10000));
+ io.mapOptional("current-version", file.currentVersion, PackedVersion(0x10000));
io.mapOptional("has-UUID", file.hasUUID, true);
io.mapOptional("rpaths", file.rpaths);
io.mapOptional("entry-point", file.entryAddress, Hex64(0));
io.mapOptional("source-version", file.sourceVersion, Hex64(0));
io.mapOptional("OS", file.os);
- io.mapOptional("min-os-version", file.minOSverson, Hex32(0));
- io.mapOptional("sdk-version", file.sdkVersion, Hex32(0));
+ io.mapOptional("min-os-version", file.minOSverson, PackedVersion(0));
+ io.mapOptional("sdk-version", file.sdkVersion, PackedVersion(0));
io.mapOptional("segments", file.segments);
io.mapOptional("sections", file.sections);
io.mapOptional("local-symbols", file.localSymbols);
# Check we accept -install_name correctly:
# RUN: lld -flavor darwin -arch x86_64 -install_name libwibble.dylib -dylib \
+# RUN: -compatibility_version 2.0 -current_version 5.3 \
# RUN: %p/Inputs/libSystem.yaml %s -o %t.dylib
# RUN: macho-dump %t.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
# Check we default the install-name to the output file:
# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o libwibble.dylib \
+# RUN: -compatibility_version 2.0 -current_version 5.3 \
# RUN: %p/Inputs/libSystem.yaml
# RUN: macho-dump libwibble.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
# RUN: rm -f libwibble.dylib
# Check -single_module does nothing
# RUN: lld -flavor darwin -arch x86_64 -dylib %s -install_name libwibble.dylib \
+# RUN: -compatibility_version 2.0 -current_version 5.3 \
# RUN: -single_module -o %t2.dylib %p/Inputs/libSystem.yaml
# RUN: macho-dump %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
# CHECK-BINARY-WRITE: (('command', 13)
# CHECK-BINARY-WRITE-NEXT: ('size', 40)
# CHECK-BINARY-WRITE-NEXT: ('install_name', 'libwibble.dylib')
+# CHECK-BINARY-WRITE-NEXT: ('timestamp,
+# CHECK-BINARY-WRITE-NEXT: ('cur_version, 328448)
+# CHECK-BINARY-WRITE-NEXT: ('compat_version, 131072)
# CHECK-BINARY-READ: shared-library-atoms:
# CHECK-BINARY-READ: - name: _myGlobal
# RUN: llvm-objdump -lazy-bind %t | FileCheck %s
# RUN: llvm-nm -m %t | FileCheck --check-prefix=CHECK-NM %s
# RUN: llvm-objdump -disassemble %t | FileCheck --check-prefix=CHECK-HELPERS %s
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DYLIBS %s
#
# Test that correct two-level namespace ordinals are used for lazy bindings.
#
value: 0x0000000000000000
--- !mach-o
-arch: x86_64
-file-type: MH_DYLIB
-install-name: /usr/lib/libbar.dylib
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libbar.dylib
+compat-version: 1.0
+current-version: 2.3
exports:
- name: _bar
--- !mach-o
-arch: x86_64
-file-type: MH_DYLIB
-install-name: /usr/lib/libfoo.dylib
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libfoo.dylib
+compat-version: 2.0
+current-version: 3.4
exports:
- name: _foo
--- !mach-o
-arch: x86_64
-file-type: MH_DYLIB
-install-name: /usr/lib/libbaz.dylib
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libbaz.dylib
+compat-version: 3.0
+current-version: 4.5
exports:
- name: _baz
# CHECK-HELPERS: 68 10 00 00 00 pushq $16
# CHECK-HELPERS: 68 20 00 00 00 pushq $32
+
+# CHECK-DYLIBS: cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS: name /usr/lib/libbar.dylib (offset 24)
+# CHECK-DYLIBS: current version 2.3.0
+# CHECK-DYLIBS: compatibility version 1.0.0
+# CHECK-DYLIBS: cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS: name /usr/lib/libfoo.dylib (offset 24)
+# CHECK-DYLIBS: current version 3.4.0
+# CHECK-DYLIBS: compatibility version 2.0.0
+# CHECK-DYLIBS: cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS: name /usr/lib/libbaz.dylib (offset 24)
+# CHECK-DYLIBS: current version 4.5.0
+# CHECK-DYLIBS: compatibility version 3.0.0
+
+