X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/7e41aa883dd258f888d0470250eead40a53ef1f5..3903760236c30e3b5ace7a4eefac3a269d68957c:/libkern/kxld/kxld_reloc.c diff --git a/libkern/kxld/kxld_reloc.c b/libkern/kxld/kxld_reloc.c index bb93003a8..a2186be8f 100644 --- a/libkern/kxld/kxld_reloc.c +++ b/libkern/kxld/kxld_reloc.c @@ -75,6 +75,10 @@ #include #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 */ @@ -682,6 +719,7 @@ get_pointer_at_addr_64(const KXLDRelocator *relocator, check(relocator); 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 */