@@ -227,95 +227,223 @@ extension MachOFile.DyldChainedFixups {
227
227
var chainEnd = false
228
228
229
229
while !stop && !chainEnd {
230
- data. withUnsafeBytes {
231
- guard let baseAddress = $0. baseAddress else { return }
232
- let ptr = baseAddress. advanced ( by: offset)
230
+ guard let fixupInfo = _fixupInfo (
231
+ at: offset,
232
+ in: data,
233
+ pointerFormat: pointerFormat
234
+ ) else {
235
+ stop = true
236
+ continue
237
+ }
233
238
234
- var fixupInfo : DyldChainedFixupPointerInfo ?
235
-
236
- if pointerFormat. is64Bit {
237
- let rawValue = ptr. load ( as: UInt64 . self)
238
- switch pointerFormat {
239
- case . arm64e, . arm64e_kernel, . arm64e_userland, . arm64e_firmware:
240
- let content = DyldChainedFixupPointerInfo . ARM64E ( rawValue: rawValue)
241
- switch pointerFormat {
242
- case . arm64e:
243
- fixupInfo = . arm64e( content)
244
- case . arm64e_kernel:
245
- fixupInfo = . arm64e_kernel( content)
246
- case . arm64e_userland:
247
- fixupInfo = . arm64e_userland( content)
248
- case . arm64e_firmware:
249
- fixupInfo = . arm64e_firmware( content)
250
- default : break
251
- }
252
-
253
- case . arm64e_userland24:
254
- let content = DyldChainedFixupPointerInfo . ARM64EUserland24 ( rawValue: rawValue)
255
- fixupInfo = . arm64e_userland24( content)
256
-
257
- case . _64, . _64_offset:
258
- let content = DyldChainedFixupPointerInfo . General64 ( rawValue: rawValue)
259
- switch pointerFormat {
260
- case . _64: fixupInfo = . _64( content)
261
- case . _64_offset: fixupInfo = . _64_offset( content)
262
- default : break
263
- }
264
-
265
- case . _64_kernel_cache, . x86_64_kernel_cache:
266
- let content = DyldChainedFixupPointerInfo . General64Cache ( rawValue: rawValue)
267
- switch pointerFormat {
268
- case . _64_kernel_cache:
269
- fixupInfo = . _64_kernel_cache( content)
270
- case . x86_64_kernel_cache:
271
- fixupInfo = . x86_64_kernel_cache( content)
272
- default : break
273
- }
274
-
275
- case . arm64e_shared_cache:
276
- let content = DyldChainedFixupPointerInfo . ARM64ESharedCache ( rawValue: rawValue)
277
- fixupInfo = . arm64e_shared_cache( content)
278
-
279
- default :
280
- // unknown format
281
- stop = true
282
- }
239
+ let pointerOffset = numericCast ( startsInSegment. segment_offset) + offset
240
+
241
+ pointers. append (
242
+ DyldChainedFixupPointer (
243
+ offset: pointerOffset,
244
+ fixupInfo: fixupInfo
245
+ )
246
+ )
247
+
248
+ if fixupInfo. next == 0 {
249
+ chainEnd = true
250
+ } else {
251
+ offset += stride * fixupInfo. next
252
+ }
253
+ }
254
+ }
255
+ }
256
+
257
+ extension MachOFile . DyldChainedFixups {
258
+ public func pointer( for offset: UInt64 , in machO: MachOFile ) -> DyldChainedFixupPointer ? {
259
+ guard let startsInImage = startsInImage else { return nil }
260
+ guard let startsInSegment = startsInSegments ( of: startsInImage)
261
+ . first ( where: {
262
+ let segmentSize = UInt64 ( $0. page_size) * UInt64( $0. page_count)
263
+ return $0. segment_offset <= offset && offset < $0. segment_offset + segmentSize
264
+ } ) else {
265
+ return nil
266
+ }
267
+
268
+ let pages = pages ( of: startsInSegment)
269
+ let pagesData = machO. fileHandle. readData (
270
+ offset: numericCast ( machO. headerStartOffset) + startsInSegment. segment_offset,
271
+ size: pages. count * numericCast( startsInSegment. page_size)
272
+ )
273
+
274
+ for (index, page) in pages. enumerated ( ) {
275
+ var offsetInPage = page. offset
276
+
277
+ if page. isNone { continue }
278
+ if page. isMulti {
279
+ var overflowIndex = Int ( offsetInPage & ~ UInt16( DYLD_CHAINED_PTR_START_MULTI) )
280
+ var chainEnd = false
281
+ while !chainEnd {
282
+ chainEnd = pages [ overflowIndex] . offset & UInt16 ( DYLD_CHAINED_PTR_START_LAST) != 0
283
+ offsetInPage = pages [ overflowIndex] . offset & ~ UInt16( DYLD_CHAINED_PTR_START_LAST)
284
+ let pageContentStart : Int = index * numericCast( startsInSegment. page_size)
285
+ let chainOffset = pageContentStart + numericCast( offsetInPage)
283
286
284
- } else {
285
- let rawValue = ptr. load ( as: UInt32 . self)
286
- switch pointerFormat {
287
- case . _32:
288
- let content = DyldChainedFixupPointerInfo . General32 ( rawValue: rawValue)
289
- fixupInfo = . _32( content)
290
- case . _32_cache:
291
- let content = DyldChainedFixupPointerInfo . General32Cache ( rawValue: rawValue)
292
- fixupInfo = . _32_cache( content)
293
- case . _32_firmware:
294
- let content = DyldChainedFixupPointerInfo . General32Firmware ( rawValue: rawValue)
295
- fixupInfo = . _32_firmware( content)
296
- default :
297
- // unknown format
298
- stop = true
287
+ if let pointer = walkChainAndFindPointer (
288
+ for: offset,
289
+ chainOffset: chainOffset,
290
+ data: pagesData,
291
+ of: startsInSegment
292
+ ) {
293
+ return pointer
299
294
}
295
+
296
+ overflowIndex += 1
297
+ }
298
+ } else {
299
+ let pageContentStart : Int = index * numericCast( startsInSegment. page_size)
300
+ let chainOffset = pageContentStart + numericCast( offsetInPage)
301
+
302
+ if let pointer = walkChainAndFindPointer (
303
+ for: offset,
304
+ chainOffset: chainOffset,
305
+ data: pagesData,
306
+ of: startsInSegment
307
+ ) {
308
+ return pointer
300
309
}
301
310
302
- if let fixupInfo {
303
- let pointerOffset = numericCast ( startsInSegment . segment_offset ) + offset
311
+ }
312
+ }
304
313
305
- pointers. append (
306
- DyldChainedFixupPointer (
307
- offset: pointerOffset,
308
- fixupInfo: fixupInfo
309
- )
310
- )
314
+ return nil
315
+ }
316
+ private func walkChainAndFindPointer(
317
+ for targetOffset: UInt64 ,
318
+ chainOffset: Int ,
319
+ data: Data ,
320
+ of startsInSegment: DyldChainedStartsInSegment
321
+ ) -> DyldChainedFixupPointer ? {
322
+ guard let pointerFormat = startsInSegment. pointerFormat else {
323
+ return nil
324
+ }
325
+ var chainOffset = chainOffset
311
326
312
- if fixupInfo. next == 0 {
313
- chainEnd = true
314
- } else {
315
- offset += stride * fixupInfo. next
316
- }
327
+ let stride = pointerFormat. stride
328
+ var stop = false
329
+ var chainEnd = false
330
+
331
+ while !stop && !chainEnd {
332
+ guard let fixupInfo = _fixupInfo (
333
+ at: chainOffset,
334
+ in: data,
335
+ pointerFormat: pointerFormat
336
+ ) else {
337
+ stop = true
338
+ continue
339
+ }
340
+
341
+ let pointerOffset = numericCast ( startsInSegment. segment_offset) + chainOffset
342
+
343
+ if pointerOffset == targetOffset {
344
+ return DyldChainedFixupPointer (
345
+ offset: pointerOffset,
346
+ fixupInfo: fixupInfo
347
+ )
348
+ }
349
+
350
+ if fixupInfo. next == 0 {
351
+ chainEnd = true
352
+ } else {
353
+ chainOffset += stride * fixupInfo. next
354
+ }
355
+ }
356
+
357
+ return nil
358
+ }
359
+ }
360
+
361
+ extension MachOFile . DyldChainedFixups {
362
+ @inline ( __always)
363
+ private func _fixupInfo(
364
+ at offset: Int ,
365
+ in data: Data ,
366
+ pointerFormat: DyldChainedFixupPointerFormat
367
+ ) -> DyldChainedFixupPointerInfo ? {
368
+ var fixupInfo : DyldChainedFixupPointerInfo ?
369
+
370
+ if pointerFormat. is64Bit {
371
+ // faster than below code
372
+ // let rawValue = data.advanced(by: offset).withUnsafeBytes {
373
+ // $0.load(as: UInt64.self)
374
+ // }
375
+ guard let rawValue = data. withUnsafeBytes ( { bytes -> UInt64 ? in
376
+ guard let baseAddress = bytes. baseAddress else { return nil }
377
+ let ptr = baseAddress. advanced ( by: offset)
378
+ return ptr. load ( as: UInt64 . self)
379
+ } ) else { return nil }
380
+
381
+ switch pointerFormat {
382
+ case . arm64e, . arm64e_kernel, . arm64e_userland, . arm64e_firmware:
383
+ let content = DyldChainedFixupPointerInfo . ARM64E ( rawValue: rawValue)
384
+ switch pointerFormat {
385
+ case . arm64e:
386
+ fixupInfo = . arm64e( content)
387
+ case . arm64e_kernel:
388
+ fixupInfo = . arm64e_kernel( content)
389
+ case . arm64e_userland:
390
+ fixupInfo = . arm64e_userland( content)
391
+ case . arm64e_firmware:
392
+ fixupInfo = . arm64e_firmware( content)
393
+ default : break
317
394
}
395
+
396
+ case . arm64e_userland24:
397
+ let content = DyldChainedFixupPointerInfo . ARM64EUserland24 ( rawValue: rawValue)
398
+ fixupInfo = . arm64e_userland24( content)
399
+
400
+ case . _64, . _64_offset:
401
+ let content = DyldChainedFixupPointerInfo . General64 ( rawValue: rawValue)
402
+ switch pointerFormat {
403
+ case . _64: fixupInfo = . _64( content)
404
+ case . _64_offset: fixupInfo = . _64_offset( content)
405
+ default : break
406
+ }
407
+
408
+ case . _64_kernel_cache, . x86_64_kernel_cache:
409
+ let content = DyldChainedFixupPointerInfo . General64Cache ( rawValue: rawValue)
410
+ switch pointerFormat {
411
+ case . _64_kernel_cache:
412
+ fixupInfo = . _64_kernel_cache( content)
413
+ case . x86_64_kernel_cache:
414
+ fixupInfo = . x86_64_kernel_cache( content)
415
+ default : break
416
+ }
417
+
418
+ case . arm64e_shared_cache:
419
+ let content = DyldChainedFixupPointerInfo . ARM64ESharedCache ( rawValue: rawValue)
420
+ fixupInfo = . arm64e_shared_cache( content)
421
+
422
+ default :
423
+ break
424
+ }
425
+ } else {
426
+ guard let rawValue = data. withUnsafeBytes ( { bytes -> UInt32 ? in
427
+ guard let baseAddress = bytes. baseAddress else { return nil }
428
+ let ptr = baseAddress. advanced ( by: offset)
429
+ return ptr. load ( as: UInt32 . self)
430
+ } ) else { return nil }
431
+
432
+ switch pointerFormat {
433
+ case . _32:
434
+ let content = DyldChainedFixupPointerInfo . General32 ( rawValue: rawValue)
435
+ fixupInfo = . _32( content)
436
+ case . _32_cache:
437
+ let content = DyldChainedFixupPointerInfo . General32Cache ( rawValue: rawValue)
438
+ fixupInfo = . _32_cache( content)
439
+ case . _32_firmware:
440
+ let content = DyldChainedFixupPointerInfo . General32Firmware ( rawValue: rawValue)
441
+ fixupInfo = . _32_firmware( content)
442
+ default :
443
+ break
318
444
}
319
445
}
446
+
447
+ return fixupInfo
320
448
}
321
449
}
0 commit comments