From 041bc71bc8ff45dc2d4df11d48023e457b8b021e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 25 Jan 2023 23:17:13 +0100 Subject: [PATCH] self-hosted: clean up calling logic for x86_64 and aarch64 across linkers --- src/arch/aarch64/CodeGen.zig | 123 ++++++++--------------- src/arch/x86_64/CodeGen.zig | 189 ++++++++++++----------------------- 2 files changed, 105 insertions(+), 207 deletions(-) diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index b509e36f3a..93ac450bae 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4302,32 +4302,19 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier // on linking. const mod = self.bin_file.options.module.?; if (self.air.value(callee)) |func_value| { - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; + const fn_owner_decl = mod.declPtr(func.owner_decl); + + if (self.bin_file.cast(link.File.Elf)) |elf_file| { const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const fn_owner_decl = mod.declPtr(func.owner_decl); const got_addr = blk: { const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes); }; - try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); - - _ = try self.addInst(.{ - .tag = .blr, - .data = .{ .reg = .x30 }, - }); - } else if (func_value.castTag(.extern_fn)) |_| { - return self.fail("TODO implement calling extern functions", .{}); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { try fn_owner_decl.link.macho.ensureInitialized(macho_file); try self.genSetReg(Type.initTag(.u64), .x30, .{ .linker_load = .{ @@ -4335,22 +4322,39 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .sym_index = fn_owner_decl.link.macho.getSymbolIndex().?, }, }); - // blr x30 - _ = try self.addInst(.{ - .tag = .blr, - .data = .{ .reg = .x30 }, + } else if (self.bin_file.cast(link.File.Coff)) |_| { + try self.genSetReg(Type.initTag(.u64), .x30, .{ + .linker_load = .{ + .type = .got, + .sym_index = fn_owner_decl.link.coff.sym_index, + }, }); - } else if (func_value.castTag(.extern_fn)) |func_payload| { - const extern_fn = func_payload.data; - const decl_name = mod.declPtr(extern_fn.owner_decl).name; - if (extern_fn.lib_name) |lib_name| { - log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ - decl_name, - lib_name, - }); - } - const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); + } else if (self.bin_file.cast(link.File.Plan9)) |p9| { + try p9.seeDecl(func.owner_decl); + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_addr = p9.bases.data; + const got_index = fn_owner_decl.link.plan9.got_index.?; + const fn_got_addr = got_addr + got_index * ptr_bytes; + try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr }); + } else unreachable; + _ = try self.addInst(.{ + .tag = .blr, + .data = .{ .reg = .x30 }, + }); + } else if (func_value.castTag(.extern_fn)) |func_payload| { + const extern_fn = func_payload.data; + const decl_name = mod.declPtr(extern_fn.owner_decl).name; + if (extern_fn.lib_name) |lib_name| { + log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ + decl_name, + lib_name, + }); + } + + if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); _ = try self.addInst(.{ .tag = .call_extern, .data = .{ @@ -4360,33 +4364,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }, }, }); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); - try self.genSetReg(Type.initTag(.u64), .x30, .{ - .linker_load = .{ - .type = .got, - .sym_index = fn_owner_decl.link.coff.sym_index, - }, - }); - // blr x30 - _ = try self.addInst(.{ - .tag = .blr, - .data = .{ .reg = .x30 }, - }); - } else if (func_value.castTag(.extern_fn)) |func_payload| { - const extern_fn = func_payload.data; - const decl_name = mod.declPtr(extern_fn.owner_decl).name; - if (extern_fn.lib_name) |lib_name| { - log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ - decl_name, - lib_name, - }); - } + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); try self.genSetReg(Type.initTag(.u64), .x30, .{ .linker_load = .{ @@ -4394,35 +4372,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .sym_index = sym_index, }, }); - // blr x30 _ = try self.addInst(.{ .tag = .blr, .data = .{ .reg = .x30 }, }); } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - if (func_value.castTag(.function)) |func_payload| { - try p9.seeDecl(func_payload.data.owner_decl); - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_addr = p9.bases.data; - const got_index = mod.declPtr(func_payload.data.owner_decl).link.plan9.got_index.?; - const fn_got_addr = got_addr + got_index * ptr_bytes; - - try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr }); - - _ = try self.addInst(.{ - .tag = .blr, - .data = .{ .reg = .x30 }, - }); - } else if (func_value.castTag(.extern_fn)) |_| { return self.fail("TODO implement calling extern functions", .{}); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); } - } else unreachable; + } else { + return self.fail("TODO implement calling bitcasted functions", .{}); + } } else { assert(ty.zigTypeTag() == .Pointer); const mcv = try self.resolveInst(callee); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 635c5d8d32..4e8c20efa1 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -3992,13 +3992,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier // Due to incremental compilation, how function calls are generated depends // on linking. const mod = self.bin_file.options.module.?; - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; + if (self.air.value(callee)) |func_value| { + if (func_value.castTag(.function)) |func_payload| { + const func = func_payload.data; + const fn_owner_decl = mod.declPtr(func.owner_decl); + + if (self.bin_file.cast(link.File.Elf)) |elf_file| { const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const fn_owner_decl = mod.declPtr(func.owner_decl); const got_addr = blk: { const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes); @@ -4008,29 +4009,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), .data = .{ .imm = @truncate(u32, got_addr) }, }); - } else if (func_value.castTag(.extern_fn)) |_| { - return self.fail("TODO implement calling extern functions", .{}); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - try self.genSetReg(Type.initTag(.usize), .rax, mcv); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); - } - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); + } else if (self.bin_file.cast(link.File.Coff)) |_| { try self.genSetReg(Type.initTag(.usize), .rax, .{ .linker_load = .{ .type = .got, @@ -4045,15 +4024,47 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }), .data = undefined, }); - } else if (func_value.castTag(.extern_fn)) |func_payload| { - const extern_fn = func_payload.data; - const decl_name = mod.declPtr(extern_fn.owner_decl).name; - if (extern_fn.lib_name) |lib_name| { - log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ - decl_name, - lib_name, - }); - } + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + try fn_owner_decl.link.macho.ensureInitialized(macho_file); + const sym_index = fn_owner_decl.link.macho.getSymbolIndex().?; + try self.genSetReg(Type.initTag(.usize), .rax, .{ + .linker_load = .{ + .type = .got, + .sym_index = sym_index, + }, + }); + _ = try self.addInst(.{ + .tag = .call, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = .rax, + .flags = 0b01, + }), + .data = undefined, + }); + } else if (self.bin_file.cast(link.File.Plan9)) |p9| { + try p9.seeDecl(func.owner_decl); + const ptr_bits = self.target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_addr = p9.bases.data; + const got_index = fn_owner_decl.link.plan9.got_index.?; + const fn_got_addr = got_addr + got_index * ptr_bytes; + _ = try self.addInst(.{ + .tag = .call, + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), + .data = .{ .imm = @intCast(u32, fn_got_addr) }, + }); + } else unreachable; + } else if (func_value.castTag(.extern_fn)) |func_payload| { + const extern_fn = func_payload.data; + const decl_name = mod.declPtr(extern_fn.owner_decl).name; + if (extern_fn.lib_name) |lib_name| { + log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ + decl_name, + lib_name, + }); + } + + if (self.bin_file.cast(link.File.Coff)) |coff_file| { const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); try self.genSetReg(Type.initTag(.usize), .rax, .{ .linker_load = .{ @@ -4069,53 +4080,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }), .data = undefined, }); - } else { - return self.fail("TODO implement calling bitcasted functions", .{}); - } - } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - try self.genSetReg(Type.initTag(.usize), .rax, mcv); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); - } - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const fn_owner_decl = mod.declPtr(func.owner_decl); - try fn_owner_decl.link.macho.ensureInitialized(macho_file); - const sym_index = fn_owner_decl.link.macho.getSymbolIndex().?; - try self.genSetReg(Type.initTag(.usize), .rax, .{ - .linker_load = .{ - .type = .got, - .sym_index = sym_index, - }, - }); - // callq *%rax - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); - } else if (func_value.castTag(.extern_fn)) |func_payload| { - const extern_fn = func_payload.data; - const decl_name = mod.declPtr(extern_fn.owner_decl).name; - if (extern_fn.lib_name) |lib_name| { - log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ - decl_name, - lib_name, - }); - } + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); _ = try self.addInst(.{ .tag = .call_extern, @@ -4128,50 +4093,24 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier }, }); } else { - return self.fail("TODO implement calling bitcasted functions", .{}); + return self.fail("TODO implement calling extern functions", .{}); } } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - try self.genSetReg(Type.initTag(.usize), .rax, mcv); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); + return self.fail("TODO implement calling bitcasted functions", .{}); } - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - if (self.air.value(callee)) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - try p9.seeDecl(func_payload.data.owner_decl); - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_addr = p9.bases.data; - const got_index = mod.declPtr(func_payload.data.owner_decl).link.plan9.got_index.?; - const fn_got_addr = got_addr + got_index * ptr_bytes; - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), - .data = .{ .imm = @intCast(u32, fn_got_addr) }, - }); - } else return self.fail("TODO implement calling extern fn on plan9", .{}); - } else { - assert(ty.zigTypeTag() == .Pointer); - const mcv = try self.resolveInst(callee); - try self.genSetReg(Type.initTag(.usize), .rax, mcv); - _ = try self.addInst(.{ - .tag = .call, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = .rax, - .flags = 0b01, - }), - .data = undefined, - }); - } - } else unreachable; + } else { + assert(ty.zigTypeTag() == .Pointer); + const mcv = try self.resolveInst(callee); + try self.genSetReg(Type.initTag(.usize), .rax, mcv); + _ = try self.addInst(.{ + .tag = .call, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = .rax, + .flags = 0b01, + }), + .data = undefined, + }); + } if (info.stack_byte_count > 0) { // Readjust the stack