]> git.saurik.com Git - apple/xnu.git/blobdiff - libkern/kxld/kxld_reloc.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / libkern / kxld / kxld_reloc.c
index 41e899eac27dad3d8667d730ad499bff90dc177d..a2186be8fb26b672392bb3496dea27798e9c08a9 100644 (file)
 #include <mach-o/arm64/reloc.h>
 #endif
 
+extern uint32_t     kaslr_offsets_index;
+extern uint32_t     kaslr_offsets_count;
+extern uint32_t    *kaslr_offsets;
+
 #define KXLD_TARGET_NONE        (u_int) 0x0
 #define KXLD_TARGET_VALUE       (u_int) 0x1
 #define KXLD_TARGET_SECTNUM     (u_int) 0x2
@@ -389,9 +393,8 @@ kxld_reloc_create_macho(KXLDArray *relocarray, const KXLDRelocator *relocator,
                    reloc->pair_target_type = KXLD_TARGET_NONE;
                 }
             }
-        }
+       } // for...
     }
-
     rval = KERN_SUCCESS;
 
 finish:
@@ -405,7 +408,7 @@ finish:
 *   2) Don't reference N_ABS symbols
 *******************************************************************************/
 static u_int
-count_relocatable_relocs(const KXLDRelocator *relocator, 
+count_relocatable_relocs(const KXLDRelocator *relocator,
     const struct relocation_info *relocs, u_int nrelocs)
 {
     u_int num_nonpair_relocs = 0;
@@ -499,11 +502,11 @@ kxld_reloc_get_symbol(const KXLDRelocator *relocator, const KXLDReloc *reloc,
         sym = kxld_symtab_get_symbol_by_index(relocator->symtab, reloc->target);
         break;
     case KXLD_TARGET_SECTNUM:
-        if (data) { 
-            value = kxld_relocator_get_pointer_at_addr(relocator, data, 
-                reloc->address);
-            sym = kxld_symtab_get_cxx_symbol_by_value(relocator->symtab, value);           
-        }
+       if (data) {
+            value = kxld_relocator_get_pointer_at_addr(relocator, data,
+                                                       reloc->address);
+            sym = kxld_symtab_get_cxx_symbol_by_value(relocator->symtab, value);
+       }
         break;
     default:
         sym = NULL;
@@ -570,7 +573,8 @@ kxld_reloc_get_macho_header_size()
 /*******************************************************************************
 *******************************************************************************/
 u_long
-kxld_reloc_get_macho_data_size(const KXLDArray *locrelocs,
+kxld_reloc_get_macho_data_size(
+    const KXLDArray *locrelocs,
     const KXLDArray *extrelocs)
 {
     u_long    rval = 0;
@@ -608,9 +612,18 @@ kxld_reloc_export_macho(const KXLDRelocator *relocator,
 
     data_size = kxld_reloc_get_macho_data_size(locrelocs, extrelocs);
     require_action((*data_offset + data_size) <= size, finish, rval=KERN_FAILURE);
-    
+
     start = dst = (struct relocation_info *) ((void *) (buf + *data_offset));
 
+    if (kaslr_offsets == NULL) {
+        kaslr_offsets_index = 0;
+        kaslr_offsets_count = locrelocs->nitems + extrelocs->nitems;
+        kaslr_offsets = (uint32_t *)malloc(kaslr_offsets_count * sizeof(*kaslr_offsets));
+        bzero(kaslr_offsets, kaslr_offsets_count * sizeof(*kaslr_offsets));
+    }
+
+    // copies the reloc data into the __LINKEDIT segment
+    // data_offset is the new value for locreloff
     rval = export_macho_for_array(relocator, locrelocs, &dst);
     require_noerr(rval, finish);
     
@@ -618,7 +631,7 @@ kxld_reloc_export_macho(const KXLDRelocator *relocator,
     require_noerr(rval, finish);
 
     count = dst - start;
-
+    
     memset(dysymtabhdr, 0, sizeof(*dysymtabhdr));
     dysymtabhdr->cmd = LC_DYSYMTAB;
     dysymtabhdr->cmdsize = (uint32_t) sizeof(*dysymtabhdr);
@@ -626,10 +639,34 @@ kxld_reloc_export_macho(const KXLDRelocator *relocator,
     dysymtabhdr->nlocrel = (uint32_t) count;
     
     *data_offset += count * sizeof(struct relocation_info);
-
+    
+#if SPLIT_KEXTS_DEBUG
+    kxld_log(kKxldLogLinking, kKxldLogErr,
+             "%p >>> Start of dysymtabhdr (size %lu) <%s> ",
+             (void *) dysymtabhdr,
+             sizeof(*dysymtabhdr),
+             __func__);
+    kxld_log(kKxldLogLinking, kKxldLogErr,
+             "%p <<< End of dysymtabhdr <%s> ",
+             (void *) ((u_char *)dysymtabhdr + sizeof(*dysymtabhdr)),
+             __func__);
+
+    kxld_log(kKxldLogLinking, kKxldLogErr,
+             "dysymtabhdr at %p: cmdsize %u indirectsymoff %u nindirectsyms %u extreloff %u nextrel %u locreloff %u nlocrel %u <%s>",
+             (void *) dysymtabhdr,
+             dysymtabhdr->cmdsize,
+             dysymtabhdr->indirectsymoff,
+             dysymtabhdr->nindirectsyms,
+             dysymtabhdr->extreloff,
+             dysymtabhdr->nextrel,
+             dysymtabhdr->locreloff,
+             dysymtabhdr->nlocrel,
+             __func__);
+#endif
+    
     rval = KERN_SUCCESS;
 finish:
-    return rval;
+   return rval;
 }
 #endif /* KXLD_PIC_KEXTS */
 
@@ -659,7 +696,7 @@ get_pointer_at_addr_32(const KXLDRelocator *relocator,
     
     check(relocator);
 
-    addr = *(const uint32_t *) ((void *) (data + offset));
+    addr = *(const uint32_t *) ((const void *) (data + offset));
 #if !KERNEL
     if (relocator->swap) {
         addr = OSSwapInt32(addr);
@@ -681,7 +718,8 @@ get_pointer_at_addr_64(const KXLDRelocator *relocator,
     
     check(relocator);
 
-    addr = *(const uint64_t *) ((void *) (data + offset));
+    addr = *(const uint64_t *) ((const void *) (data + offset));
+    
 #if !KERNEL
     if (relocator->swap) {
         addr = OSSwapInt64(addr);
@@ -786,7 +824,9 @@ finish:
 *******************************************************************************/
 kern_return_t 
 kxld_relocator_process_table_reloc(KXLDRelocator *relocator,
-    const KXLDReloc *reloc, const KXLDSeg *seg, kxld_addr_t link_addr)
+                                   const KXLDReloc *reloc,
+                                   const KXLDSeg *seg,
+                                    kxld_addr_t link_addr)
 {
     kern_return_t rval = KERN_FAILURE;
     u_char *instruction = NULL;
@@ -799,7 +839,7 @@ kxld_relocator_process_table_reloc(KXLDRelocator *relocator,
     check(relocator);
     check(reloc);
 
-    /* Find the instruction */
+    /* Find the instruction in original kext file we are trying to link */
 
     offset = (u_long)(seg->fileoff + (reloc->address - seg->base_addr));
     instruction = relocator->file + offset;
@@ -811,10 +851,14 @@ kxld_relocator_process_table_reloc(KXLDRelocator *relocator,
 
     base_pc = reloc->address;
     link_pc = base_pc + link_addr;
+    if (kxld_seg_is_split_seg(seg)) {
+        // link_pc for split segment special case, do not add in the base_pc
+        link_pc = link_addr;
+    }
 
     /* Relocate */
 
-    rval = relocator->process_reloc(relocator, instruction, reloc->length, 
+    rval = relocator->process_reloc(relocator, instruction, reloc->length,
         reloc->pcrel, base_pc, link_pc, link_addr, reloc->reloc_type, target,
         pair_target, relocator->swap);
     require_noerr(rval, finish);
@@ -1040,7 +1084,7 @@ export_macho_for_array(const KXLDRelocator *relocator,
     struct relocation_info *dst = NULL;
     struct scattered_relocation_info *scatdst = NULL;
     u_int i = 0;
-
+    
     dst = *dstp;
 
     for (i = 0; i < relocs->nitems; ++i) {
@@ -1053,6 +1097,17 @@ export_macho_for_array(const KXLDRelocator *relocator,
 
         switch (reloc->target_type) {
         case KXLD_TARGET_LOOKUP:
+            if (kaslr_offsets) {
+                if (kaslr_offsets_index >= kaslr_offsets_count) {
+                    kxld_log(kKxldLogLinking, kKxldLogErr,
+                             "kaslr_offsets overflow %d > %d <%s> ",
+                             kaslr_offsets_index, kaslr_offsets_count,
+                             __func__);
+                    abort();
+                }
+                // reloc->address is really an offset from the start of the kext
+                *(kaslr_offsets + kaslr_offsets_index++) = reloc->address;
+            }
             scatdst->r_address = reloc->address;
             scatdst->r_pcrel = reloc->pcrel;
             scatdst->r_length = reloc->length;
@@ -1061,6 +1116,15 @@ export_macho_for_array(const KXLDRelocator *relocator,
             scatdst->r_scattered = 1;
             break;
         case KXLD_TARGET_SECTNUM:
+            if (kaslr_offsets) {
+                if (kaslr_offsets_index >= kaslr_offsets_count) {
+                    kxld_log(kKxldLogLinking, kKxldLogErr,
+                             "kaslr_offsets overflow <%s> ", __func__);
+                    abort();
+                }
+                // reloc->address is really an offset from the start of the kext
+                *(kaslr_offsets + kaslr_offsets_index++) = reloc->address;
+            }
             dst->r_address = reloc->address;
             dst->r_pcrel = reloc->pcrel;
             dst->r_length = reloc->length;
@@ -1072,6 +1136,15 @@ export_macho_for_array(const KXLDRelocator *relocator,
            /* Assume that everything will be slid together; otherwise,
             * there is no sensible value for the section number.
             */
+            if (kaslr_offsets) {
+                if (kaslr_offsets_index >= kaslr_offsets_count) {
+                    kxld_log(kKxldLogLinking, kKxldLogErr,
+                             "kaslr_offsets overflow <%s> ", __func__);
+                    abort();
+                }
+                // reloc->address is really an offset from the start of the kext
+                *(kaslr_offsets + kaslr_offsets_index++) = reloc->address;
+            }
             dst->r_address = reloc->address;
             dst->r_pcrel = reloc->pcrel;
             dst->r_length = reloc->length;
@@ -1372,7 +1445,7 @@ x86_64_process_reloc(const KXLDRelocator *relocator __unused, u_char *instructio
 #if !KERNEL
         if (swap) instr32 = OSSwapInt32(instr32);
 #endif
-
+        
         *instr32p = instr32;
     } else {
         instr64p = (uint64_t *) ((void *) instruction);
@@ -1411,7 +1484,6 @@ x86_64_process_reloc(const KXLDRelocator *relocator __unused, u_char *instructio
 #if !KERNEL
         if (swap) instr64 = OSSwapInt64(instr64);
 #endif
-
         *instr64p = instr64;
     }
 
@@ -1640,7 +1712,7 @@ arm64_process_reloc(const KXLDRelocator *relocator __unused, u_char *instruction
 #if !KERNEL
         if (swap) instr32 = OSSwapInt32(instr32);
 #endif
-
+        
         *instr32p = instr32;
     } else { /* length == 3 */
         uint64_t *instr64p = (uint64_t *) (void *) instruction;
@@ -1663,7 +1735,7 @@ arm64_process_reloc(const KXLDRelocator *relocator __unused, u_char *instruction
 #if !KERNEL
         if (swap) instr64 = OSSwapInt64(instr64);
 #endif
-
+        
         *instr64p = instr64;
     }
 
@@ -1672,4 +1744,5 @@ finish:
     return rval;
 }
 
+
 #endif /* KXLD_USER_OR_ARM64 */