| ... | ... | @@ -1241,14 +1241,18 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1241 | 1241 | for (self.stub_fixups.items) |fixup| { |
| 1242 | 1242 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; |
| 1243 | 1243 | const text_addr = symbol.n_value + fixup.start; |
| 1244 | | const displacement = @intCast(u32, stub_addr - text_addr); |
| 1245 | | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; |
| 1246 | 1244 | switch (self.base.options.target.cpu.arch) { |
| 1247 | | .x86_64 => return error.TODOImplementStubFixupsForx86_64, |
| 1245 | .x86_64 => { |
| 1246 | const displacement = @intCast(u32, stub_addr - text_addr - fixup.len); |
| 1247 | var placeholder = code_buffer.items[fixup.start + fixup.len - @sizeOf(u32) ..][0..@sizeOf(u32)]; |
| 1248 | mem.writeIntSliceLittle(u32, placeholder, displacement); |
| 1249 | }, |
| 1248 | 1250 | .aarch64 => { |
| 1251 | const displacement = @intCast(u32, stub_addr - text_addr); |
| 1252 | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; |
| 1249 | 1253 | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32()); |
| 1250 | 1254 | }, |
| 1251 | | else => unreachable, |
| 1255 | else => unreachable, // unsupported target architecture |
| 1252 | 1256 | } |
| 1253 | 1257 | if (!fixup.already_defined) { |
| 1254 | 1258 | try self.writeStub(fixup.symbol); |
| ... | ... | @@ -1565,6 +1569,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1565 | 1569 | .aarch64 => 2, |
| 1566 | 1570 | else => unreachable, // unhandled architecture type |
| 1567 | 1571 | }; |
| 1572 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 1573 | .x86_64 => 6, |
| 1574 | .aarch64 => 2 * @sizeOf(u32), |
| 1575 | else => unreachable, // unhandled architecture type |
| 1576 | }; |
| 1568 | 1577 | const flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 1569 | 1578 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1570 | 1579 | const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad); |
| ... | ... | @@ -1583,7 +1592,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1583 | 1592 | .nreloc = 0, |
| 1584 | 1593 | .flags = flags, |
| 1585 | 1594 | .reserved1 = 0, |
| 1586 | | .reserved2 = 2 * @sizeOf(u32), |
| 1595 | .reserved2 = stub_size, |
| 1587 | 1596 | .reserved3 = 0, |
| 1588 | 1597 | }); |
| 1589 | 1598 | self.header_dirty = true; |
| ... | ... | @@ -2044,7 +2053,30 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2044 | 2053 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2045 | 2054 | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; |
| 2046 | 2055 | switch (self.base.options.target.cpu.arch) { |
| 2047 | | .x86_64 => return error.TODOImplementStubHelperForX86_64, |
| 2056 | .x86_64 => { |
| 2057 | const code_size = 15; |
| 2058 | var code: [code_size]u8 = undefined; |
| 2059 | // lea %r11, [rip + disp] |
| 2060 | code[0] = 0x4c; |
| 2061 | code[1] = 0x8d; |
| 2062 | code[2] = 0x1d; |
| 2063 | { |
| 2064 | const displacement = @intCast(u32, data.addr - stub_helper.addr - 7); |
| 2065 | mem.writeIntLittle(u32, code[3..7], displacement); |
| 2066 | } |
| 2067 | // push %r11 |
| 2068 | code[7] = 0x41; |
| 2069 | code[8] = 0x53; |
| 2070 | // jmp [rip + disp] |
| 2071 | code[9] = 0xff; |
| 2072 | code[10] = 0x25; |
| 2073 | { |
| 2074 | const displacement = @intCast(u32, got.addr - stub_helper.addr - code_size); |
| 2075 | mem.writeIntLittle(u32, code[11..], displacement); |
| 2076 | } |
| 2077 | self.stub_helper_stubs_start_off = stub_helper.offset + code_size; |
| 2078 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| 2079 | }, |
| 2048 | 2080 | .aarch64 => { |
| 2049 | 2081 | var code: [4 * @sizeOf(u32)]u8 = undefined; |
| 2050 | 2082 | { |
| ... | ... | @@ -2410,7 +2442,12 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| 2410 | 2442 | const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2411 | 2443 | const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 2412 | 2444 | |
| 2413 | | const stub_off = self.stub_helper_stubs_start_off.? + index * 3 * @sizeOf(u32); |
| 2445 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 2446 | .x86_64 => 10, |
| 2447 | .aarch64 => 3 * @sizeOf(u32), |
| 2448 | else => unreachable, |
| 2449 | }; |
| 2450 | const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size; |
| 2414 | 2451 | const end = stub_helper.addr + stub_off - stub_helper.offset; |
| 2415 | 2452 | var buf: [@sizeOf(u64)]u8 = undefined; |
| 2416 | 2453 | mem.writeIntLittle(u64, &buf, end); |
| ... | ... | @@ -2428,42 +2465,62 @@ fn writeStub(self: *MachO, index: u32) !void { |
| 2428 | 2465 | const stub_off = stubs.offset + index * stubs.reserved2; |
| 2429 | 2466 | const stub_addr = stubs.addr + index * stubs.reserved2; |
| 2430 | 2467 | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); |
| 2431 | | const displacement = la_ptr_addr - stub_addr; |
| 2432 | 2468 | log.debug("writing stub at 0x{x}", .{stub_off}); |
| 2469 | var code = try self.base.allocator.alloc(u8, stubs.reserved2); |
| 2470 | defer self.base.allocator.free(code); |
| 2433 | 2471 | switch (self.base.options.target.cpu.arch) { |
| 2434 | | .x86_64 => return error.TODOImplementWritingStubsForx86_64, |
| 2472 | .x86_64 => { |
| 2473 | const displacement = @intCast(u32, la_ptr_addr - stub_addr - stubs.reserved2); |
| 2474 | // jmp |
| 2475 | code[0] = 0xff; |
| 2476 | code[1] = 0x25; |
| 2477 | mem.writeIntLittle(u32, code[2..][0..4], displacement); |
| 2478 | }, |
| 2435 | 2479 | .aarch64 => { |
| 2436 | | var code: [2 * @sizeOf(u32)]u8 = undefined; |
| 2480 | const displacement = la_ptr_addr - stub_addr; |
| 2437 | 2481 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ |
| 2438 | 2482 | .literal = @intCast(u19, displacement / 4), |
| 2439 | 2483 | }).toU32()); |
| 2440 | 2484 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.br(.x16).toU32()); |
| 2441 | | try self.base.file.?.pwriteAll(&code, stub_off); |
| 2442 | 2485 | }, |
| 2443 | 2486 | else => unreachable, |
| 2444 | 2487 | } |
| 2488 | try self.base.file.?.pwriteAll(code, stub_off); |
| 2445 | 2489 | } |
| 2446 | 2490 | |
| 2447 | 2491 | fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| 2448 | 2492 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2449 | 2493 | const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?]; |
| 2450 | 2494 | |
| 2451 | | const stub_off = self.stub_helper_stubs_start_off.? + index * 3 * @sizeOf(u32); |
| 2452 | | const end = stub_helper.addr + stub_off - stub_helper.offset; |
| 2453 | | const displacement = @intCast(i64, stub_helper.addr) - @intCast(i64, end + 4); |
| 2495 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 2496 | .x86_64 => 10, |
| 2497 | .aarch64 => 3 * @sizeOf(u32), |
| 2498 | else => unreachable, |
| 2499 | }; |
| 2500 | const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size; |
| 2501 | var code = try self.base.allocator.alloc(u8, stub_size); |
| 2502 | defer self.base.allocator.free(code); |
| 2454 | 2503 | switch (self.base.options.target.cpu.arch) { |
| 2455 | | .x86_64 => return error.TODOImplementWritingStubsInStubHelperForx86_64, |
| 2504 | .x86_64 => { |
| 2505 | const displacement = @intCast(i32, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - stub_size); |
| 2506 | // pushq |
| 2507 | code[0] = 0x68; |
| 2508 | mem.writeIntLittle(u32, code[1..][0..4], index * 0xd); // TODO |
| 2509 | // jmpq |
| 2510 | code[5] = 0xe9; |
| 2511 | mem.writeIntLittle(u32, code[6..][0..4], @bitCast(u32, displacement)); |
| 2512 | }, |
| 2456 | 2513 | .aarch64 => { |
| 2457 | | var code: [3 * @sizeOf(u32)]u8 = undefined; |
| 2514 | const displacement = @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - 4; |
| 2458 | 2515 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.w16, .{ |
| 2459 | 2516 | .literal = 0x2, |
| 2460 | 2517 | }).toU32()); |
| 2461 | 2518 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(@intCast(i28, displacement)).toU32()); |
| 2462 | 2519 | mem.writeIntLittle(u32, code[8..12], index * 0xd); // TODO This is the size of lazy binding opcode block. |
| 2463 | | try self.base.file.?.pwriteAll(&code, stub_off); |
| 2464 | 2520 | }, |
| 2465 | 2521 | else => unreachable, |
| 2466 | 2522 | } |
| 2523 | try self.base.file.?.pwriteAll(code, stub_off); |
| 2467 | 2524 | } |
| 2468 | 2525 | |
| 2469 | 2526 | fn relocateSymbolTable(self: *MachO) !void { |