- uint64_t delta = 0;
- uintptr_t address = chainStartAddress;
- do {
- uint64_t value = *(uint64_t*)address;
-
- bool isAuthenticated = (value & (1ULL << 63)) != 0;
- bool isRebase = (value & (1ULL << 62)) == 0;
- if (isRebase) {
- if (isAuthenticated) {
- // The new value for a rebase is the low 32-bits of the threaded value plus the slide.
- uint64_t newValue = (value & 0xFFFFFFFF) + slide;
- // Add in the offset from the mach_header
- newValue += baseAddress;
- *(uint64_t*)address = newValue;
- } else {
- // Regular pointer which needs to fit in 51-bits of value.
- // C++ RTTI uses the top bit, so we'll allow the whole top-byte
- // and the bottom 43-bits to be fit in to 51-bits.
- uint64_t top8Bits = value & 0x0007F80000000000ULL;
- uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
- uint64_t targetValue = (top8Bits << 13) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
- targetValue = targetValue + slide;
- *(uint64_t*)address = targetValue;
- }
+ kernel_mach_header_t *k_mh, *kc_mh = NULL;
+ kernel_segment_command_t *seg;
+ uintptr_t slide;
+
+ k_mh = &_mh_execute_header;
+ if (kernel_mach_header_is_in_fileset(k_mh)) {
+ /*
+ * The kernel is part of a MH_FILESET kernel collection, determine slide
+ * based on first segment's mach-o vmaddr (requires first kernel load
+ * command to be LC_SEGMENT_64 of the __TEXT segment)
+ */
+ seg = (kernel_segment_command_t *)((uintptr_t)k_mh + sizeof(*k_mh));
+ assert(seg->cmd == LC_SEGMENT_KERNEL);
+ slide = (uintptr_t)k_mh - seg->vmaddr;
+
+ /*
+ * The kernel collection linker guarantees that the boot collection mach
+ * header vmaddr is the hardcoded kernel link address (as specified to
+ * ld64 when linking the kernel).
+ */
+ kc_mh = (kernel_mach_header_t*)(VM_KERNEL_LINK_ADDRESS + slide);
+ assert(kc_mh->filetype == MH_FILESET);
+
+ /*
+ * rebase and sign jops
+ * Note that we can't call any functions before this point, so
+ * we have to hard-code the knowledge that the base of the KC
+ * is the KC's mach-o header. This would change if any
+ * segment's VA started *before* the text segment
+ * (as the HIB segment does on x86).
+ */
+ const void *collection_base_pointers[KCNumKinds] = {[0] = kc_mh, };
+ kernel_collection_slide((struct mach_header_64 *)kc_mh, collection_base_pointers);
+
+ PE_set_kc_header(KCKindPrimary, kc_mh, slide);
+
+ /*
+ * iBoot doesn't slide load command vmaddrs in an MH_FILESET kernel
+ * collection, so adjust them now, and determine the vmaddr range
+ * covered by read-only segments for the CTRR rorgn.
+ */
+ kernel_collection_adjust_mh_addrs((struct mach_header_64 *)kc_mh, slide, false,
+ (uintptr_t *)&segLOWESTKC, (uintptr_t *)&segHIGHESTKC,
+ (uintptr_t *)&segLOWESTROKC, (uintptr_t *)&segHIGHESTROKC,
+ NULL, NULL, NULL);
+#if defined(HAS_APPLE_PAC)
+ OSRuntimeSignStructorsInFileset(kc_mh);
+#endif /* defined(HAS_APPLE_PAC) */
+ } else {
+ /*
+ * Static kernelcache: iBoot slid kernel MachO vmaddrs, determine slide
+ * using hardcoded kernel link address
+ */
+ slide = (uintptr_t)k_mh - VM_KERNEL_LINK_ADDRESS;
+
+ /* rebase and sign jops */
+ static_kernelcache = &__thread_starts_sect_end[0] != &__thread_starts_sect_start[0];
+ if (static_kernelcache) {
+ rebase_threaded_starts( &__thread_starts_sect_start[0],
+ &__thread_starts_sect_end[0],
+ (uintptr_t)k_mh, (uintptr_t)k_mh - slide, slide);