authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-10 00:21:34+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-13 23:55:37+01:00
logf0d7ec6f33634edb0ddb3ba5d5b306e9f2de5418
tree0e0d7082e8d828d9dcefc668634e2aba45059643
parent1b91a9f4c840741e77e5c7ce826c5f80c9f9ee80

macho: add x86_64 support


2 files changed, 93 insertions(+), 20 deletions(-)

src/codegen.zig+19-3
...@@ -1876,14 +1876,30 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1876,14 +1876,30 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1876 });1876 });
1877 break :blk index;1877 break :blk index;
1878 };1878 };
1879 const start = self.code.items.len;
1880 const len: usize = blk: {
1881 switch (arch) {
1882 .x86_64 => {
1883 // callq
1884 try self.code.ensureCapacity(self.code.items.len + 5);
1885 self.code.appendSliceAssumeCapacity(&[5]u8{ 0xe8, 0x0, 0x0, 0x0, 0x0 });
1886 break :blk 5;
1887 },
1888 .aarch64 => {
1889 // bl
1890 writeInt(u32, try self.code.addManyAsArray(4), 0);
1891 break :blk 4;
1892 },
1893 else => unreachable, // unsupported architecture on MachO
1894 }
1895 };
1879 try macho_file.stub_fixups.append(self.bin_file.allocator, .{1896 try macho_file.stub_fixups.append(self.bin_file.allocator, .{
1880 .symbol = symbol,1897 .symbol = symbol,
1881 .already_defined = already_defined,1898 .already_defined = already_defined,
1882 .start = self.code.items.len,1899 .start = start,
1883 .len = 4,1900 .len = len,
1884 });1901 });
1885 // We mark the space and fix it up later.1902 // We mark the space and fix it up later.
1886 writeInt(u32, try self.code.addManyAsArray(4), 0);
1887 } else {1903 } else {
1888 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});1904 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
1889 }1905 }
src/link/MachO.zig+74-17
...@@ -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 type1570 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.?];
24122444
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}
24462490
2447fn writeStubInStubHelper(self: *MachO, index: u32) !void {2491fn 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.?];
24502494
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}
24682525
2469fn relocateSymbolTable(self: *MachO) !void {2526fn relocateSymbolTable(self: *MachO) !void {