* Refactor out the patched pages & restore the original pages. * For some programs/libraries, it is difficult to ensure the loader is * run before the code segment is executed. This is especially difficult * with some advanced uses of the dynamic linker. This refactoring provides * a simple solution: have the loader also patch the code. */
| 270 | * a simple solution: have the loader also patch the code. |
| 271 | */ |
| 272 | static size_t emitRefactoredPatch(const uint8_t *original, uint8_t *data, |
| 273 | size_t size, size_t mapping_size, const InstrSet &Is, |
| 274 | RefactorSet &refactors) |
| 275 | { |
| 276 | if (option_loader_static) |
| 277 | return 0; |
| 278 | |
| 279 | assert(size % PAGE_SIZE == 0); |
| 280 | |
| 281 | // Step #1: Find refactorings: |
| 282 | intptr_t curr_addr = INTPTR_MIN; |
| 283 | off_t curr_offset = -1; |
| 284 | size_t curr_size = 0; |
| 285 | for (off_t offset = 0; offset < (off_t)size; offset += PAGE_SIZE) |
| 286 | { |
| 287 | if (memcmp(original + offset, data + offset, PAGE_SIZE) == 0) |
| 288 | continue; |
| 289 | const Instr *I = Is.lower_bound(offset); |
| 290 | assert(I != nullptr); |
| 291 | intptr_t page_addr = I->addr - (I->addr % PAGE_SIZE); |
| 292 | off_t page_offset = I->offset - (I->offset % PAGE_SIZE); |
| 293 | assert(page_offset == offset); |
| 294 | |
| 295 | if (curr_addr < 0 || page_addr < curr_addr || |
| 296 | (intptr_t)(curr_addr + curr_size + mapping_size) < page_addr) |
| 297 | { |
| 298 | if (curr_addr >= 0) |
| 299 | { |
| 300 | Refactor r(curr_addr, curr_offset, curr_size); |
| 301 | refactors.push_back(r); |
| 302 | } |
| 303 | curr_addr = page_addr; |
| 304 | curr_offset = page_offset; |
| 305 | curr_size = PAGE_SIZE; |
| 306 | } |
| 307 | else |
| 308 | curr_size += (page_addr + PAGE_SIZE) - (curr_addr + curr_size); |
| 309 | } |
| 310 | if (curr_addr >= 0) |
| 311 | { |
| 312 | Refactor r(curr_addr, curr_offset, curr_size); |
| 313 | refactors.push_back(r); |
| 314 | } |
| 315 | |
| 316 | // Step #2: Write out a copy of the patched pages & restore original pages: |
| 317 | size_t size_0 = size; |
| 318 | for (auto &r: refactors) |
| 319 | { |
| 320 | r.patched.offset = (off_t)size; |
| 321 | memcpy(data + size, data + r.original.offset, r.size); |
| 322 | memcpy(data + r.original.offset, original + r.original.offset, r.size); |
| 323 | size += r.size; |
| 324 | } |
| 325 | |
| 326 | return size - size_0; |
| 327 | } |
| 328 | |
| 329 | /* |
no test coverage detected