authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-16 23:37:31+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-17 12:10:39+01:00
log1181543dadc48e296f0de88673a46ba37841ae24
tree3ba154d675d2bac507f60c66b5c3dd9c987024f0
parent3df2ae1f9da3655462d668ec16088f43a4a11ce4

macho: extract writing stub helper preamble into fn


1 files changed, 128 insertions(+), 56 deletions(-)

src/link/MachO.zig+128-56
...@@ -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}
21402085
...@@ -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}
25182463
2464fn 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
2519fn writeStub(self: *MachO, index: u32) !void {2591fn 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.?];