| ... | @@ -2079,62 +2079,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -2079,62 +2079,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2079 | self.binding_info_dirty = true; | 2079 | self.binding_info_dirty = true; |
| 2080 | } | 2080 | } |
| 2081 | if (self.stub_helper_stubs_start_off == null) { | 2081 | if (self.stub_helper_stubs_start_off == null) { |
| 2082 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2082 | try self.writeStubHelperPreamble(); |
| 2083 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | | |
| 2084 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | | |
| 2085 | const data = &data_segment.sections.items[self.data_section_index.?]; | | |
| 2086 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | | |
| 2087 | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; | | |
| 2088 | switch (self.base.options.target.cpu.arch) { | | |
| 2089 | .x86_64 => { | | |
| 2090 | const code_size = 15; | | |
| 2091 | var code: [code_size]u8 = undefined; | | |
| 2092 | // lea %r11, [rip + disp] | | |
| 2093 | code[0] = 0x4c; | | |
| 2094 | code[1] = 0x8d; | | |
| 2095 | code[2] = 0x1d; | | |
| 2096 | { | | |
| 2097 | const displacement = try math.cast(u32, data.addr - stub_helper.addr - 7); | | |
| 2098 | mem.writeIntLittle(u32, code[3..7], displacement); | | |
| 2099 | } | | |
| 2100 | // push %r11 | | |
| 2101 | code[7] = 0x41; | | |
| 2102 | code[8] = 0x53; | | |
| 2103 | // jmp [rip + disp] | | |
| 2104 | code[9] = 0xff; | | |
| 2105 | code[10] = 0x25; | | |
| 2106 | { | | |
| 2107 | const displacement = try math.cast(u32, got.addr - stub_helper.addr - code_size); | | |
| 2108 | mem.writeIntLittle(u32, code[11..], displacement); | | |
| 2109 | } | | |
| 2110 | self.stub_helper_stubs_start_off = stub_helper.offset + code_size; | | |
| 2111 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); | | |
| 2112 | }, | | |
| 2113 | .aarch64 => { | | |
| 2114 | var code: [4 * @sizeOf(u32)]u8 = undefined; | | |
| 2115 | { | | |
| 2116 | const displacement = try math.cast(i21, data.addr - stub_helper.addr); | | |
| 2117 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); | | |
| 2118 | } | | |
| 2119 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.stp( | | |
| 2120 | .x16, | | |
| 2121 | .x17, | | |
| 2122 | aarch64.Register.sp, | | |
| 2123 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), | | |
| 2124 | ).toU32()); | | |
| 2125 | { | | |
| 2126 | const displacement = try math.divExact(u64, got.addr - stub_helper.addr - 2 * @sizeOf(u32), 4); | | |
| 2127 | const literal = try math.cast(u19, displacement); | | |
| 2128 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.ldr(.x16, .{ | | |
| 2129 | .literal = literal, | | |
| 2130 | }).toU32()); | | |
| 2131 | } | | |
| 2132 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.br(.x16).toU32()); | | |
| 2133 | self.stub_helper_stubs_start_off = stub_helper.offset + 4 * @sizeOf(u32); | | |
| 2134 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); | | |
| 2135 | }, | | |
| 2136 | else => unreachable, | | |
| 2137 | } | | |
| 2138 | } | 2083 | } |
| 2139 | } | 2084 | } |
| 2140 | | 2085 | |
| ... | @@ -2516,6 +2461,133 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { | ... | @@ -2516,6 +2461,133 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| 2516 | try self.base.file.?.pwriteAll(&buf, off); | 2461 | try self.base.file.?.pwriteAll(&buf, off); |
| 2517 | } | 2462 | } |
| 2518 | | 2463 | |
| | 2464 | fn writeStubHelperPreamble(self: *MachO) !void { |
| | 2465 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 2466 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| | 2467 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| | 2468 | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; |
| | 2469 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 2470 | const data = &data_segment.sections.items[self.data_section_index.?]; |
| | 2471 | |
| | 2472 | switch (self.base.options.target.cpu.arch) { |
| | 2473 | .x86_64 => { |
| | 2474 | const code_size = 15; |
| | 2475 | var code: [code_size]u8 = undefined; |
| | 2476 | // lea %r11, [rip + disp] |
| | 2477 | code[0] = 0x4c; |
| | 2478 | code[1] = 0x8d; |
| | 2479 | code[2] = 0x1d; |
| | 2480 | { |
| | 2481 | const target_addr = data.addr; |
| | 2482 | const displacement = try math.cast(u32, target_addr - stub_helper.addr - 7); |
| | 2483 | mem.writeIntLittle(u32, code[3..7], displacement); |
| | 2484 | } |
| | 2485 | // push %r11 |
| | 2486 | code[7] = 0x41; |
| | 2487 | code[8] = 0x53; |
| | 2488 | // jmp [rip + disp] |
| | 2489 | code[9] = 0xff; |
| | 2490 | code[10] = 0x25; |
| | 2491 | { |
| | 2492 | const displacement = try math.cast(u32, got.addr - stub_helper.addr - code_size); |
| | 2493 | mem.writeIntLittle(u32, code[11..], displacement); |
| | 2494 | } |
| | 2495 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| | 2496 | self.stub_helper_stubs_start_off = stub_helper.offset + code_size; |
| | 2497 | }, |
| | 2498 | .aarch64 => { |
| | 2499 | var code: [6 * @sizeOf(u32)]u8 = undefined; |
| | 2500 | |
| | 2501 | data_blk_outer: { |
| | 2502 | const this_addr = stub_helper.addr; |
| | 2503 | const target_addr = data.addr; |
| | 2504 | data_blk: { |
| | 2505 | const displacement = math.cast(i21, target_addr - this_addr) catch |_| break :data_blk; |
| | 2506 | // adr x17, disp |
| | 2507 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| | 2508 | // nop |
| | 2509 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| | 2510 | break :data_blk_outer; |
| | 2511 | } |
| | 2512 | data_blk: { |
| | 2513 | const new_this_addr = this_addr + @sizeOf(u32); |
| | 2514 | const displacement = math.cast(i21, target_addr - new_this_addr) catch |_| break :data_blk; |
| | 2515 | // nop |
| | 2516 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| | 2517 | // adr x17, disp |
| | 2518 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| | 2519 | break :data_blk_outer; |
| | 2520 | } |
| | 2521 | // Jump is too big, replace adr with adrp and add. |
| | 2522 | const this_page = @intCast(i32, this_addr >> 12); |
| | 2523 | const target_page = @intCast(i32, target_addr >> 12); |
| | 2524 | const pages = @intCast(i21, target_page - this_page); |
| | 2525 | // adrp x17, pages |
| | 2526 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32()); |
| | 2527 | const narrowed = @truncate(u12, target_addr); |
| | 2528 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32()); |
| | 2529 | } |
| | 2530 | |
| | 2531 | // stp x16, x17, [sp, #-16]! |
| | 2532 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.stp( |
| | 2533 | .x16, |
| | 2534 | .x17, |
| | 2535 | aarch64.Register.sp, |
| | 2536 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), |
| | 2537 | ).toU32()); |
| | 2538 | |
| | 2539 | binder_blk_outer: { |
| | 2540 | const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| | 2541 | const target_addr = got.addr; |
| | 2542 | binder_blk: { |
| | 2543 | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :binder_blk; |
| | 2544 | const literal = math.cast(u18, displacement) catch |_| break :binder_blk; |
| | 2545 | // ldr x16, label |
| | 2546 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{ |
| | 2547 | .literal = literal, |
| | 2548 | }).toU32()); |
| | 2549 | // nop |
| | 2550 | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| | 2551 | break :binder_blk_outer; |
| | 2552 | } |
| | 2553 | binder_blk: { |
| | 2554 | const new_this_addr = this_addr + @sizeOf(u32); |
| | 2555 | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :binder_blk; |
| | 2556 | const literal = math.cast(u18, displacement) catch |_| break :binder_blk; |
| | 2557 | // nop |
| | 2558 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| | 2559 | // ldr x16, label |
| | 2560 | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| | 2561 | .literal = literal, |
| | 2562 | }).toU32()); |
| | 2563 | break :binder_blk_outer; |
| | 2564 | } |
| | 2565 | // Jump is too big, replace ldr with adrp and ldr(register). |
| | 2566 | const this_page = @intCast(i32, this_addr >> 12); |
| | 2567 | const target_page = @intCast(i32, target_addr >> 12); |
| | 2568 | const pages = @intCast(i21, target_page - this_page); |
| | 2569 | // adrp x16, pages |
| | 2570 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| | 2571 | const narrowed = @truncate(u12, target_addr); |
| | 2572 | const offset = try math.divExact(u12, narrowed, 8); |
| | 2573 | // ldr x16, x16, offset |
| | 2574 | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| | 2575 | .register = .{ |
| | 2576 | .rn = .x16, |
| | 2577 | .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| | 2578 | }, |
| | 2579 | }).toU32()); |
| | 2580 | } |
| | 2581 | |
| | 2582 | // br x16 |
| | 2583 | mem.writeIntLittle(u32, code[20..24], aarch64.Instruction.br(.x16).toU32()); |
| | 2584 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| | 2585 | self.stub_helper_stubs_start_off = stub_helper.offset + code.len; |
| | 2586 | }, |
| | 2587 | else => unreachable, |
| | 2588 | } |
| | 2589 | } |
| | 2590 | |
| 2519 | fn writeStub(self: *MachO, index: u32) !void { | 2591 | fn writeStub(self: *MachO, index: u32) !void { |
| 2520 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2592 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2521 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; | 2593 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |