| ... | @@ -1241,14 +1241,18 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1241,14 +1241,18 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1241 | for (self.stub_fixups.items) |fixup| { | 1241 | for (self.stub_fixups.items) |fixup| { |
| 1242 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; | 1242 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; |
| 1243 | const text_addr = symbol.n_value + fixup.start; | 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 | switch (self.base.options.target.cpu.arch) { | 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 | .aarch64 => { | 1250 | .aarch64 => { |
| | 1251 | const displacement = @intCast(u32, stub_addr - text_addr); |
| | 1252 | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; |
| 1249 | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32()); | 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 | if (!fixup.already_defined) { | 1257 | if (!fixup.already_defined) { |
| 1254 | try self.writeStub(fixup.symbol); | 1258 | try self.writeStub(fixup.symbol); |
| ... | @@ -1565,6 +1569,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1565,6 +1569,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1565 | .aarch64 => 2, | 1569 | .aarch64 => 2, |
| 1566 | else => unreachable, // unhandled architecture type | 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 | const flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; | 1577 | const flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 1569 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | 1578 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1570 | const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad); | 1579 | const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad); |
| ... | @@ -1583,7 +1592,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1583,7 +1592,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1583 | .nreloc = 0, | 1592 | .nreloc = 0, |
| 1584 | .flags = flags, | 1593 | .flags = flags, |
| 1585 | .reserved1 = 0, | 1594 | .reserved1 = 0, |
| 1586 | .reserved2 = 2 * @sizeOf(u32), | 1595 | .reserved2 = stub_size, |
| 1587 | .reserved3 = 0, | 1596 | .reserved3 = 0, |
| 1588 | }); | 1597 | }); |
| 1589 | self.header_dirty = true; | 1598 | self.header_dirty = true; |
| ... | @@ -2044,7 +2053,30 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -2044,7 +2053,30 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2044 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 2053 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2045 | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; | 2054 | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; |
| 2046 | switch (self.base.options.target.cpu.arch) { | 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 | .aarch64 => { | 2080 | .aarch64 => { |
| 2049 | var code: [4 * @sizeOf(u32)]u8 = undefined; | 2081 | var code: [4 * @sizeOf(u32)]u8 = undefined; |
| 2050 | { | 2082 | { |
| ... | @@ -2410,7 +2442,12 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { | ... | @@ -2410,7 +2442,12 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| 2410 | const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 2442 | const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2411 | const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?]; | 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 | const end = stub_helper.addr + stub_off - stub_helper.offset; | 2451 | const end = stub_helper.addr + stub_off - stub_helper.offset; |
| 2415 | var buf: [@sizeOf(u64)]u8 = undefined; | 2452 | var buf: [@sizeOf(u64)]u8 = undefined; |
| 2416 | mem.writeIntLittle(u64, &buf, end); | 2453 | mem.writeIntLittle(u64, &buf, end); |
| ... | @@ -2428,42 +2465,62 @@ fn writeStub(self: *MachO, index: u32) !void { | ... | @@ -2428,42 +2465,62 @@ fn writeStub(self: *MachO, index: u32) !void { |
| 2428 | const stub_off = stubs.offset + index * stubs.reserved2; | 2465 | const stub_off = stubs.offset + index * stubs.reserved2; |
| 2429 | const stub_addr = stubs.addr + index * stubs.reserved2; | 2466 | const stub_addr = stubs.addr + index * stubs.reserved2; |
| 2430 | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); | 2467 | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); |
| 2431 | const displacement = la_ptr_addr - stub_addr; | | |
| 2432 | log.debug("writing stub at 0x{x}", .{stub_off}); | 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 | switch (self.base.options.target.cpu.arch) { | 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 | .aarch64 => { | 2479 | .aarch64 => { |
| 2436 | var code: [2 * @sizeOf(u32)]u8 = undefined; | 2480 | const displacement = la_ptr_addr - stub_addr; |
| 2437 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ | 2481 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ |
| 2438 | .literal = @intCast(u19, displacement / 4), | 2482 | .literal = @intCast(u19, displacement / 4), |
| 2439 | }).toU32()); | 2483 | }).toU32()); |
| 2440 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.br(.x16).toU32()); | 2484 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.br(.x16).toU32()); |
| 2441 | try self.base.file.?.pwriteAll(&code, stub_off); | | |
| 2442 | }, | 2485 | }, |
| 2443 | else => unreachable, | 2486 | else => unreachable, |
| 2444 | } | 2487 | } |
| | 2488 | try self.base.file.?.pwriteAll(code, stub_off); |
| 2445 | } | 2489 | } |
| 2446 | | 2490 | |
| 2447 | fn writeStubInStubHelper(self: *MachO, index: u32) !void { | 2491 | fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| 2448 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2492 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2449 | const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?]; | 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); | 2495 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 2452 | const end = stub_helper.addr + stub_off - stub_helper.offset; | 2496 | .x86_64 => 10, |
| 2453 | const displacement = @intCast(i64, stub_helper.addr) - @intCast(i64, end + 4); | 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 | switch (self.base.options.target.cpu.arch) { | 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 | .aarch64 => { | 2513 | .aarch64 => { |
| 2457 | var code: [3 * @sizeOf(u32)]u8 = undefined; | 2514 | const displacement = @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - 4; |
| 2458 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.w16, .{ | 2515 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.w16, .{ |
| 2459 | .literal = 0x2, | 2516 | .literal = 0x2, |
| 2460 | }).toU32()); | 2517 | }).toU32()); |
| 2461 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(@intCast(i28, displacement)).toU32()); | 2518 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(@intCast(i28, displacement)).toU32()); |
| 2462 | mem.writeIntLittle(u32, code[8..12], index * 0xd); // TODO This is the size of lazy binding opcode block. | 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 | else => unreachable, | 2521 | else => unreachable, |
| 2466 | } | 2522 | } |
| | 2523 | try self.base.file.?.pwriteAll(code, stub_off); |
| 2467 | } | 2524 | } |
| 2468 | | 2525 | |
| 2469 | fn relocateSymbolTable(self: *MachO) !void { | 2526 | fn relocateSymbolTable(self: *MachO) !void { |