/* * This is used by the sliding function to read and execute * the compressed reloc table. */ static void rebaseCompressed(struct dyld_info_command* dyldInfo, macho_segment_command* linkEdit, uintptr_t slide, macho_segment_command** segments, int segCount) { /* * HARD MODE!!! */ const uint8_t* base = (uint8_t*)((linkEdit->vmaddr + slide) - linkEdit->fileoff); const uint8_t* start = addUintPtr2(dyldInfo->rebase_off, base); const uint8_t* end = addUintPtr3(dyldInfo->rebase_size, dyldInfo->rebase_off, base); const uint8_t* p = start; /* * If you want a better documented version of this code, see 'MachObject.cpp' */ uint8_t type = 0; int segmentIndex = 0; uintptr_t address = (segments[0]->vmaddr + slide); uintptr_t segmentEndAddress = (segments[0]->vmaddr + slide + segments[0]->vmsize); uint32_t count; uint32_t skip; bool done = false; while ( !done && (p < end) ) { uint8_t immediate = *p & REBASE_IMMEDIATE_MASK; uint8_t opcode = *p & REBASE_OPCODE_MASK; ++p; switch (opcode) { case REBASE_OPCODE_DONE: done = true; break; case REBASE_OPCODE_SET_TYPE_IMM: type = immediate; break; case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: segmentIndex = immediate; if (segmentIndex > segCount) lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad whatever \n"); address = (segments[segmentIndex]->vmaddr + slide) + read_uleb128(p, end); segmentEndAddress = (segments[segmentIndex]->vmaddr + segments[segmentIndex]->vmsize + slide); break; case REBASE_OPCODE_ADD_ADDR_ULEB: address += read_uleb128(p, end); break; case REBASE_OPCODE_ADD_ADDR_IMM_SCALED: address += immediate*sizeof(uintptr_t); break; case REBASE_OPCODE_DO_REBASE_IMM_TIMES: for (int i=0; i < immediate; ++i) { if ( address >= segmentEndAddress ) lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad REBASE_OPCODE_DO_REBASE_IMM_TIMES \n"); rebaseAt(address, slide, type); address += sizeof(uintptr_t); } break; case REBASE_OPCODE_DO_REBASE_ULEB_TIMES: count = read_uleb128(p, end); for (uint32_t i=0; i < count; ++i) { if ( address >= segmentEndAddress ) lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad REBASE_OPCODE_DO_REBASE_ULEB_TIMES \n"); rebaseAt(address, slide, type); address += sizeof(uintptr_t); } break; case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: if ( address >= segmentEndAddress ) lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB \n"); rebaseAt(address, slide, type); address += read_uleb128(p, end) + sizeof(uintptr_t); break; case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: count = read_uleb128(p, end); skip = read_uleb128(p, end); for (uint32_t i=0; i < count; ++i) { if ( address >= segmentEndAddress ) lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB \n"); rebaseAt(address, slide, type); address += skip + sizeof(uintptr_t); } break; default: _printAbrt(); } } }
void MachObject::readRebase(const uint8_t* start, const uint8_t* end) { /* aaaa!!!! */; uint8_t type = 0; int segmentIndex = 0; uintptr_t address = segActualLoadAddr(0); uintptr_t segmentEndAddress = segActualEndAddr(0); uint32_t count; uint32_t skip; const uint8_t* p = start; bool done = false; while ( !done && (p < end) ) { uint8_t immediate = *p & REBASE_IMMEDIATE_MASK; uint8_t opcode = *p & REBASE_OPCODE_MASK; ++p; switch (opcode) { case REBASE_OPCODE_DONE: done = true; break; case REBASE_OPCODE_SET_TYPE_IMM: type = immediate; break; case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: segmentIndex = immediate; if (segmentIndex > fSegmentsCount) lnk::halt("baaaad seg count for rebase!"); address = segActualLoadAddr(segmentIndex) + read_uleb128(p, end); segmentEndAddress = segActualEndAddr(segmentIndex); break; case REBASE_OPCODE_ADD_ADDR_ULEB: address += read_uleb128(p, end); break; case REBASE_OPCODE_ADD_ADDR_IMM_SCALED: address += immediate*sizeof(uintptr_t); break; case REBASE_OPCODE_DO_REBASE_IMM_TIMES: for (int i=0; i < immediate; ++i) { if ( address >= segmentEndAddress ) throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p); this->rebaseAt(address, fSlide, type); address += sizeof(uintptr_t); } break; case REBASE_OPCODE_DO_REBASE_ULEB_TIMES: count = read_uleb128(p, end); for (uint32_t i=0; i < count; ++i) { if ( address >= segmentEndAddress ) throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p); this->rebaseAt(address, fSlide, type); address += sizeof(uintptr_t); } break; case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: if ( address >= segmentEndAddress ) throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p); this->rebaseAt(address, fSlide, type); address += read_uleb128(p, end) + sizeof(uintptr_t); break; case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: count = read_uleb128(p, end); skip = read_uleb128(p, end); for (uint32_t i=0; i < count; ++i) { if ( address >= segmentEndAddress ) throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p); rebaseAt(address, fSlide, type); address += skip + sizeof(uintptr_t); } break; default: lnk::halt("invalid opcode %d for rebase", *p); break; } } }