Skip to content

Commit 708af3d

Browse files
authored
Merge pull request #143 from p-x9/feature/enhance-prebuilt-loader
Enhance prebuilt loader
2 parents 2cd02cf + c6e1c79 commit 708af3d

File tree

6 files changed

+275
-2
lines changed

6 files changed

+275
-2
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// ObjCBinaryInfo.swift
3+
// MachOKit
4+
//
5+
// Created by p-x9 on 2024/11/16
6+
//
7+
//
8+
9+
import Foundation
10+
11+
public struct ObjCBinaryInfo: LayoutWrapper {
12+
public typealias Layout = objc_binary_info
13+
14+
public var layout: Layout
15+
}

Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,25 @@ extension PrebuiltLoader {
2121
layout.loader.isPrebuilt != 0
2222
}
2323

24+
public var neverUnload: Bool {
25+
layout.loader.neverUnload != 0
26+
}
27+
28+
public var isPremapped: Bool {
29+
layout.loader.isPremapped != 0
30+
}
31+
2432
public var ref: LoaderRef {
2533
.init(layout: layout.loader.ref)
2634
}
35+
36+
public var uuid: UUID {
37+
.init(uuid: layout.loader.uuid)
38+
}
39+
40+
public var sectionLocations: SectionLocations {
41+
.init(layout: layout.sectionLocations)
42+
}
2743
}
2844

2945
extension PrebuiltLoader {
@@ -34,6 +50,14 @@ extension PrebuiltLoader {
3450
return cache.fileHandle.readString(offset: offset)
3551
}
3652

53+
public func altPath(in cache: DyldCache) -> String? {
54+
guard layout.altPathOffset != 0 else { return nil }
55+
guard let offset = cache.fileOffset(
56+
of: numericCast(address) + numericCast(layout.altPathOffset)
57+
) else { return nil }
58+
return cache.fileHandle.readString(offset: offset)
59+
}
60+
3761
public func dependentLoaderRefs(in cache: DyldCache) -> DataSequence<LoaderRef>? {
3862
guard layout.dependentLoaderRefsArrayOffset != 0,
3963
let offset = cache.fileOffset(
@@ -46,6 +70,14 @@ extension PrebuiltLoader {
4670
numberOfElements: numericCast(layout.depCount)
4771
)
4872
}
73+
74+
public func objcBinaryInfo(in cache: DyldCache) -> ObjCBinaryInfo? {
75+
guard layout.objcBinaryInfoOffset != 0 else { return nil }
76+
guard let offset = cache.fileOffset(
77+
of: numericCast(address) + numericCast(layout.objcBinaryInfoOffset)
78+
) else { return nil }
79+
return cache.fileHandle.read(offset: offset)
80+
}
4981
}
5082

5183
extension PrebuiltLoader {
@@ -61,6 +93,19 @@ extension PrebuiltLoader {
6193
)
6294
}
6395

96+
public func altPath(in cache: DyldCacheLoaded) -> String? {
97+
// swiftlint:disable:previous unused_parameter
98+
guard layout.altPathOffset != 0 else { return nil }
99+
guard let baseAddress = UnsafeRawPointer(bitPattern: address) else {
100+
return nil
101+
}
102+
return String(
103+
cString: baseAddress
104+
.advanced(by: numericCast(layout.altPathOffset))
105+
.assumingMemoryBound(to: CChar.self)
106+
)
107+
}
108+
64109
public func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence<LoaderRef>? {
65110
// swiftlint:disable:previous unused_parameter
66111
guard layout.dependentLoaderRefsArrayOffset != 0,
@@ -74,6 +119,18 @@ extension PrebuiltLoader {
74119
numberOfElements: numericCast(layout.depCount)
75120
)
76121
}
122+
123+
public func objcBinaryInfo(in cache: DyldCacheLoaded) -> ObjCBinaryInfo? {
124+
// swiftlint:disable:previous unused_parameter
125+
guard layout.objcBinaryInfoOffset != 0,
126+
let baseAddress = UnsafeRawPointer(bitPattern: address) else {
127+
return nil
128+
}
129+
return baseAddress
130+
.advanced(by: numericCast(layout.objcBinaryInfoOffset))
131+
.assumingMemoryBound(to: ObjCBinaryInfo.self)
132+
.pointee
133+
}
77134
}
78135

79136
extension PrebuiltLoader {

Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,47 @@ public protocol PrebuiltLoaderProtocol {
1717

1818
/// magic of loader starts
1919
var magic: String? { get }
20-
/// PrebuiltLoader vs JustInTimeLoader
20+
/// PrebuiltLoader vs JustInTimeLoader
2121
var isPrebuilt: Bool { get }
22+
var neverUnload: Bool { get }
23+
var isPremapped: Bool { get }
24+
2225
var ref: LoaderRef { get }
2326

27+
// Information for all pre-calculated sections that we know about
28+
var sectionLocations: SectionLocations { get }
29+
2430
/// path for target mach-o image
2531
/// - Parameter cache: DyldCache to which `self` belongs
2632
/// - Returns: path name
2733
func path(in cache: DyldCache) -> String?
34+
/// alternative path for target mach-o image if install_name does not match real path
35+
/// - Parameter cache: DyldCache to which `self` belongs
36+
/// - Returns: path name
37+
func altPath(in cache: DyldCache) -> String?
2838
/// loader reference list of target 's dependencies
2939
/// - Parameter cache: DyldCache to which `self` belongs
3040
/// - Returns: sequence of loader reference
3141
func dependentLoaderRefs(in cache: DyldCache) -> DataSequence<LoaderRef>?
42+
/// Stores information about the layout of the objc sections in a binary
43+
/// - Parameter cache: DyldCache to which `self` belongs
44+
/// - Returns: binary info for objc
45+
func objcBinaryInfo(in cache: DyldCache) -> ObjCBinaryInfo?
3246

3347
/// path for target mach-o image
3448
/// - Parameter cache: DyldCacheLoaded to which `self` belongs
3549
/// - Returns: path name
3650
func path(in cache: DyldCacheLoaded) -> String?
51+
/// alternative path for target mach-o image if install_name does not match real path
52+
/// - Parameter cache: DyldCacheLoaded to which `self` belongs
53+
/// - Returns: path name
54+
func altPath(in cache: DyldCacheLoaded) -> String?
3755
/// loader reference list of target 's dependencies
3856
/// - Parameter cache: DyldCacheLoaded to which `self` belongs
3957
/// - Returns: sequence of loader reference
4058
func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence<LoaderRef>?
59+
/// Stores information about the layout of the objc sections in a binary
60+
/// - Parameter cache: DyldCacheLoaded to which `self` belongs
61+
/// - Returns: binary info for objc
62+
func objcBinaryInfo(in cache: DyldCacheLoaded) -> ObjCBinaryInfo?
4163
}

Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,21 @@ extension PrebuiltLoader_Pre1165_3 {
1919
layout.loader.isPrebuilt != 0
2020
}
2121

22+
public var neverUnload: Bool {
23+
layout.loader.neverUnload != 0
24+
}
25+
26+
public var isPremapped: Bool {
27+
layout.loader.isPremapped != 0
28+
}
29+
2230
public var ref: LoaderRef {
2331
.init(layout: layout.loader.ref)
2432
}
33+
34+
public var sectionLocations: SectionLocations {
35+
.init(layout: layout.sectionLocations)
36+
}
2537
}
2638

2739
extension PrebuiltLoader_Pre1165_3 {
@@ -32,6 +44,14 @@ extension PrebuiltLoader_Pre1165_3 {
3244
return cache.fileHandle.readString(offset: offset)
3345
}
3446

47+
public func altPath(in cache: DyldCache) -> String? {
48+
guard layout.altPathOffset != 0 else { return nil }
49+
guard let offset = cache.fileOffset(
50+
of: numericCast(address) + numericCast(layout.altPathOffset)
51+
) else { return nil }
52+
return cache.fileHandle.readString(offset: offset)
53+
}
54+
3555
public func dependentLoaderRefs(in cache: DyldCache) -> DataSequence<LoaderRef>? {
3656
guard layout.dependentLoaderRefsArrayOffset != 0,
3757
let offset = cache.fileOffset(
@@ -44,6 +64,14 @@ extension PrebuiltLoader_Pre1165_3 {
4464
numberOfElements: numericCast(layout.depCount)
4565
)
4666
}
67+
68+
public func objcBinaryInfo(in cache: DyldCache) -> ObjCBinaryInfo? {
69+
guard layout.objcBinaryInfoOffset != 0 else { return nil }
70+
guard let offset = cache.fileOffset(
71+
of: numericCast(address) + numericCast(layout.objcBinaryInfoOffset)
72+
) else { return nil }
73+
return cache.fileHandle.read(offset: offset)
74+
}
4775
}
4876

4977
extension PrebuiltLoader_Pre1165_3 {
@@ -59,6 +87,19 @@ extension PrebuiltLoader_Pre1165_3 {
5987
)
6088
}
6189

90+
public func altPath(in cache: DyldCacheLoaded) -> String? {
91+
// swiftlint:disable:previous unused_parameter
92+
guard layout.altPathOffset != 0 else { return nil }
93+
guard let baseAddress = UnsafeRawPointer(bitPattern: address) else {
94+
return nil
95+
}
96+
return String(
97+
cString: baseAddress
98+
.advanced(by: numericCast(layout.altPathOffset))
99+
.assumingMemoryBound(to: CChar.self)
100+
)
101+
}
102+
62103
public func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence<LoaderRef>? {
63104
// swiftlint:disable:previous unused_parameter
64105
guard layout.dependentLoaderRefsArrayOffset != 0,
@@ -72,6 +113,18 @@ extension PrebuiltLoader_Pre1165_3 {
72113
numberOfElements: numericCast(layout.depCount)
73114
)
74115
}
116+
117+
public func objcBinaryInfo(in cache: DyldCacheLoaded) -> ObjCBinaryInfo? {
118+
// swiftlint:disable:previous unused_parameter
119+
guard layout.objcBinaryInfoOffset != 0,
120+
let baseAddress = UnsafeRawPointer(bitPattern: address) else {
121+
return nil
122+
}
123+
return baseAddress
124+
.advanced(by: numericCast(layout.objcBinaryInfoOffset))
125+
.assumingMemoryBound(to: ObjCBinaryInfo.self)
126+
.pointee
127+
}
75128
}
76129

77130
extension PrebuiltLoader_Pre1165_3 {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// SectionLocations.swift
3+
// MachOKit
4+
//
5+
// Created by p-x9 on 2024/11/16
6+
//
7+
//
8+
9+
import Foundation
10+
11+
public struct SectionLocations: LayoutWrapper {
12+
public typealias Layout = section_locations
13+
14+
public var layout: Layout
15+
}
16+
17+
extension SectionLocations {
18+
// [dyld implementation](https://github.com/apple-oss-distributions/dyld/blob/65bbeed63cec73f313b1d636e63f243964725a9d/include/mach-o/dyld_priv.h#L62)
19+
public enum SectionKind: Int, CaseIterable {
20+
// TEXT:
21+
case text_swift5_protos
22+
case text_swift5_proto
23+
case text_swift5_types
24+
case text_swift5_replace
25+
case text_swift5_replace2
26+
case text_swift5_ac_funcs
27+
28+
// DATA*:
29+
case objc_image_info
30+
case data_sel_refs
31+
case data_msg_refs
32+
case data_class_refs
33+
case data_super_refs
34+
case data_protocol_refs
35+
case data_class_list
36+
case data_non_lazy_class_list
37+
case data_stub_list
38+
case data_category_list
39+
case data_category_list2
40+
case data_non_lazy_category_list
41+
case data_protocol_list
42+
case data_objc_fork_ok
43+
case data_raw_isa
44+
45+
// ~~ version 1 ~~
46+
}
47+
}
48+
49+
extension SectionLocations {
50+
public struct Section {
51+
public let offset: Int
52+
public let size: Int
53+
public let kind: SectionKind
54+
}
55+
}
56+
57+
extension SectionLocations {
58+
public func section(for kind: SectionKind) -> Section {
59+
var offsets = layout.offsets
60+
var sizes = layout.sizes
61+
let offset = withUnsafePointer(to: &offsets) {
62+
UnsafeRawPointer($0)
63+
.assumingMemoryBound(to: UInt64.self)
64+
.advanced(by: kind.rawValue).pointee
65+
}
66+
let size = withUnsafePointer(to: &sizes) {
67+
UnsafeRawPointer($0)
68+
.assumingMemoryBound(to: UInt64.self)
69+
.advanced(by: kind.rawValue).pointee
70+
}
71+
return .init(
72+
offset: numericCast(offset),
73+
size: numericCast(size),
74+
kind: kind
75+
)
76+
}
77+
}

Sources/MachOKitC/include/dyld_cache_loader.h

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef dyld_cache_loader_h
1010
#define dyld_cache_loader_h
1111

12+
#include <stdbool.h>
1213
// https://github.com/apple-oss-distributions/dyld/blob/d552c40cd1de105f0ec95008e0e0c0972de43456/dyld/PrebuiltLoader.h#L254
1314
struct prebuilt_loader_set {
1415
uint32_t magic;
@@ -175,7 +176,55 @@ struct prebuilt_loader {
175176
uint32_t overrideBindTargetRefsOffset;
176177
uint32_t overrideBindTargetRefsCount;
177178

178-
// struct section_locations sectionLocations;
179+
struct section_locations sectionLocations;
180+
};
181+
182+
// https://github.com/apple-oss-distributions/dyld/blob/65bbeed63cec73f313b1d636e63f243964725a9d/dyld/PrebuiltLoader.h#L344
183+
// Stores information about the layout of the objc sections in a binary, as well as other properties relating to
184+
// the objc information in there.
185+
struct objc_binary_info {
186+
// Offset to the __objc_imageinfo section
187+
uint64_t imageInfoRuntimeOffset;
188+
189+
// Offsets to sections containing objc pointers
190+
uint64_t selRefsRuntimeOffset;
191+
uint64_t classListRuntimeOffset;
192+
uint64_t categoryListRuntimeOffset;
193+
uint64_t protocolListRuntimeOffset;
194+
195+
// Counts of the above sections.
196+
uint32_t selRefsCount;
197+
uint32_t classListCount;
198+
uint32_t categoryCount;
199+
uint32_t protocolListCount;
200+
201+
// Do we have stable Swift fixups to apply to at least one class?
202+
bool hasClassStableSwiftFixups;
203+
204+
// Do we have any pointer-based method lists to set as uniqued?
205+
bool hasClassMethodListsToSetUniqued;
206+
bool hasCategoryMethodListsToSetUniqued;
207+
bool hasProtocolMethodListsToSetUniqued;
208+
209+
// Do we have any method lists in which to set selector references.
210+
// Note we only support visiting selector refernces in pointer based method lists
211+
// Relative method lists should have been verified to always point to __objc_selrefs
212+
bool hasClassMethodListsToUnique;
213+
bool hasCategoryMethodListsToUnique;
214+
bool hasProtocolMethodListsToUnique;
215+
216+
// Whwn serialized to the PrebuildLoader, these fields will encode other information about
217+
// the binary.
218+
219+
// Offset to an array of uint8_t's. One for each protocol.
220+
// Note this can be 0 (ie, have no fixups), even if we have protocols. That would be the case
221+
// if this binary contains no canonical protocol definitions, ie, all canonical defs are in other binaries
222+
// or the shared cache.
223+
uint32_t protocolFixupsOffset;
224+
// Offset to an array of BindTargetRef's. One for each selector reference to fix up
225+
// Note we only fix up selector refs in the __objc_selrefs section, and in pointer-based method lists
226+
uint32_t selectorReferencesFixupsOffset;
227+
uint32_t selectorReferencesFixupsCount;
179228
};
180229

181230
#endif /* dyld_cache_loader_h */

0 commit comments

Comments
 (0)