Skip to content

Commit 4632684

Browse files
authored
Merge pull request #117 from p-x9/feature/resolve-optional-rebase
Resolve optional rebase in dyld shared cache or mach-o file
2 parents 97a95b3 + be69d03 commit 4632684

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

Sources/MachOKit/DyldCache.swift

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,4 +454,88 @@ extension DyldCache {
454454

455455
return runtimeOffset + onDiskDylibChainedPointerBaseAddress
456456
}
457+
458+
// https://github.com/apple-oss-distributions/dyld/blob/a571176e8e00c47e95b95e3156820ebec0cbd5e6/common/MetadataVisitor.cpp#L424
459+
public func resolveOptionalRebase(at offset: UInt64) -> UInt64? {
460+
guard let mappingInfos,
461+
let unslidLoadAddress = mappingInfos.first?.address else {
462+
return nil
463+
}
464+
guard let mapping = mappingAndSlideInfo(forFileOffset: offset) else {
465+
return nil
466+
}
467+
guard let slideInfo = mapping.slideInfo(in: self) else {
468+
let version = mapping.slideInfoVersion(in: self) ?? .none
469+
if version == .none {
470+
if cpu.is64Bit {
471+
let value: UInt64 = fileHandle.read(offset: offset)
472+
guard value != 0 else { return nil }
473+
return value
474+
} else {
475+
let value: UInt32 = fileHandle.read(offset: offset)
476+
guard value != 0 else { return nil }
477+
return numericCast(value)
478+
}
479+
} else {
480+
481+
}
482+
return nil
483+
}
484+
485+
let runtimeOffset: UInt64
486+
let onDiskDylibChainedPointerBaseAddress: UInt64
487+
switch slideInfo {
488+
case .v1:
489+
let value: UInt32 = fileHandle.read(offset: offset)
490+
guard value != 0 else { return nil }
491+
runtimeOffset = numericCast(value) - unslidLoadAddress
492+
onDiskDylibChainedPointerBaseAddress = unslidLoadAddress
493+
494+
case let .v2(slideInfo):
495+
let rawValue: UInt64 = fileHandle.read(offset: offset)
496+
guard rawValue != 0 else { return nil }
497+
let deltaMask: UInt64 = 0x00FFFF0000000000
498+
let valueMask: UInt64 = ~deltaMask
499+
runtimeOffset = rawValue & valueMask
500+
onDiskDylibChainedPointerBaseAddress = slideInfo.value_add
501+
502+
case .v3:
503+
let rawValue: UInt64 = fileHandle.read(offset: offset)
504+
guard rawValue != 0 else { return nil }
505+
let _fixup = DyldChainedFixupPointerInfo.ARM64E(rawValue: rawValue)
506+
let fixup: DyldChainedFixupPointerInfo = .arm64e(_fixup)
507+
let pointer: DyldChainedFixupPointer = .init(
508+
offset: Int(offset),
509+
fixupInfo: fixup
510+
)
511+
guard let _runtimeOffset = pointer.rebaseTargetRuntimeOffset(
512+
preferedLoadAddress: unslidLoadAddress
513+
) else { return nil }
514+
runtimeOffset = _runtimeOffset
515+
onDiskDylibChainedPointerBaseAddress = unslidLoadAddress
516+
517+
case let .v4(slideInfo):
518+
let rawValue: UInt32 = fileHandle.read(offset: offset)
519+
guard rawValue != 0 else { return nil }
520+
let deltaMask: UInt64 = 0x00000000C0000000
521+
let valueMask: UInt64 = ~deltaMask
522+
runtimeOffset = numericCast(rawValue) & valueMask
523+
onDiskDylibChainedPointerBaseAddress = slideInfo.value_add
524+
525+
case let .v5(slideInfo):
526+
let rawValue: UInt64 = fileHandle.read(offset: offset)
527+
guard rawValue != 0 else { return nil }
528+
let _fixup = DyldChainedFixupPointerInfo.ARM64ESharedCache(
529+
rawValue: rawValue
530+
)
531+
let fixup: DyldChainedFixupPointerInfo = .arm64e_shared_cache(_fixup)
532+
guard let rebase = fixup.rebase else {
533+
return nil
534+
}
535+
runtimeOffset = numericCast(rebase.unpackedTarget)
536+
onDiskDylibChainedPointerBaseAddress = slideInfo.value_add
537+
}
538+
539+
return runtimeOffset + onDiskDylibChainedPointerBaseAddress
540+
}
457541
}

Sources/MachOKit/MachOFile.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,45 @@ extension MachOFile {
485485
return nil
486486
}
487487

488+
public func resolveOptionalRebase(at offset: UInt64) -> UInt64? {
489+
if isLoadedFromDyldCache,
490+
let cache = try? DyldCache(url: url) {
491+
return cache.resolveOptionalRebase(at: offset)
492+
}
493+
494+
guard let chainedFixup = dyldChainedFixups,
495+
let startsInImage = chainedFixup.startsInImage else {
496+
return nil
497+
}
498+
let startsInSegments = chainedFixup.startsInSegments(
499+
of: startsInImage
500+
)
501+
502+
for segment in startsInSegments {
503+
let pointers = chainedFixup.pointers(of: segment, in: self)
504+
guard let pointer = pointers.first(where: {
505+
$0.offset == offset
506+
}) else { continue }
507+
guard pointer.fixupInfo.rebase != nil,
508+
let offset = pointer.rebaseTargetRuntimeOffset(for: self) else {
509+
return nil
510+
}
511+
if is64Bit {
512+
let value: UInt64 = fileHandle.read(
513+
offset: numericCast(headerStartOffset + pointer.offset)
514+
)
515+
if value == 0 { return nil }
516+
} else {
517+
let value: UInt32 = fileHandle.read(
518+
offset: numericCast(headerStartOffset + pointer.offset)
519+
)
520+
if value == 0 { return nil }
521+
}
522+
return offset
523+
}
524+
return nil
525+
}
526+
488527
public func resolveBind(
489528
at offset: UInt64
490529
) -> (DyldChainedImport, addend: UInt64)? {

0 commit comments

Comments
 (0)