diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-18 18:58:29 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-24 12:34:41 +0100 |
| commit | 96cc9fafbf0a382c0ed0b6142986cd8373cffaa3 (patch) | |
| tree | ec6cf83208e30a54f263807cf4e72f07b90457cd /src/arch | |
| parent | 76dc305d4e71a9a4c9de92e6dde40a53eac1e328 (diff) | |
| download | zig-96cc9fafbf0a382c0ed0b6142986cd8373cffaa3.tar.gz zig-96cc9fafbf0a382c0ed0b6142986cd8373cffaa3.zip | |
codegen: re-implement enough of codegen to error out instead panic
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 90 | ||||
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 86 | ||||
| -rw-r--r-- | src/arch/x86_64/Lower.zig | 169 |
3 files changed, 163 insertions, 182 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 870b6a2472..2b4932c5c2 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -139,10 +139,7 @@ const Owner = union(enum) { if (ctx.bin_file.cast(link.File.Elf)) |elf_file| { return elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| { - _ = macho_file; - // const atom = try macho_file.getOrCreateAtomForDecl(decl_index); - // return macho_file.getAtom(atom).getSymbolIndex().?; - @panic("TODO getSymbolIndex"); + return macho_file.getZigObject().?.getOrCreateMetadataForDecl(macho_file, decl_index); } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| { const atom = try coff_file.getOrCreateAtomForDecl(decl_index); return coff_file.getAtom(atom).getSymbolIndex().?; @@ -155,11 +152,8 @@ const Owner = union(enum) { return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err| ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| { - _ = macho_file; - // const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - // return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); - // return macho_file.getAtom(atom).getSymbolIndex().?; - @panic("TODO getSymbolIndex"); + return macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, lazy_sym) catch |err| + ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| { const atom = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); @@ -10955,12 +10949,10 @@ fn genCall(self: *Self, info: union(enum) { try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); try self.asmRegister(.{ ._, .call }, .rax); } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - _ = macho_file; - @panic("TODO genCall"); - // const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); - // const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; - // try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); - // try self.asmRegister(.{ ._, .call }, .rax); + const sym_index = try macho_file.getZigObject().?.getOrCreateMetadataForDecl(macho_file, func.owner_decl); + const sym = macho_file.getSymbol(sym_index); + try self.genSetReg(.rax, Type.usize, .{ .load_symbol = .{ .sym = sym.nlist_idx } }); + try self.asmRegister(.{ ._, .call }, .rax); } else if (self.bin_file.cast(link.File.Plan9)) |p9| { const atom_index = try p9.seeDecl(func.owner_decl); const atom = p9.getAtom(atom_index); @@ -13556,30 +13548,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr } }, }); }, - .lea_tlv => |sym_index| { - const atom_index = try self.owner.getSymbolIndex(self); - if (self.bin_file.cast(link.File.MachO)) |_| { - _ = try self.addInst(.{ - .tag = .lea, - .ops = .tlv_reloc, - .data = .{ .rx = .{ - .r1 = .rdi, - .payload = try self.addExtra(bits.Symbol{ - .atom_index = atom_index, - .sym_index = sym_index, - }), - } }, - }); - // TODO: spill registers before calling - try self.asmMemory(.{ ._, .call }, .{ - .base = .{ .reg = .rdi }, - .mod = .{ .rm = .{ .size = .qword } }, - }); - try self.genSetReg(dst_reg.to64(), Type.usize, .{ .register = .rax }); - } else return self.fail("TODO emit ptr to TLV sequence on {s}", .{ - @tagName(self.bin_file.tag), - }); - }, + .lea_tlv => unreachable, // TODO: remove this .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref)), } } @@ -13816,19 +13785,14 @@ fn genExternSymbolRef( else => unreachable, } } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const global_index = try macho_file.getGlobalSymbol(callee, lib); _ = try self.addInst(.{ .tag = .call, .ops = .extern_fn_reloc, - .data = .{ - .reloc = .{ - .atom_index = atom_index, - // .sym_index = link.File.MachO.global_symbol_bit | global_index, - .sym_index = global_index, - }, - }, + .data = .{ .reloc = .{ + .atom_index = atom_index, + .sym_index = try macho_file.getGlobalSymbol(callee, lib), + } }, }); - @panic("TODO genExternSymbolRef"); } else return self.fail("TODO implement calling extern functions", .{}); } @@ -13916,21 +13880,19 @@ fn genLazySymbolRef( else => unreachable, } } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - _ = macho_file; - @panic("TODO genLazySymbolRef"); - // const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - // return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - // const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - // switch (tag) { - // .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }), - // .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }), - // else => unreachable, - // } - // switch (tag) { - // .lea, .mov => {}, - // .call => try self.asmRegister(.{ ._, .call }, reg), - // else => unreachable, - // } + const sym_index = macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym = macho_file.getSymbol(sym_index); + switch (tag) { + .lea, .call => try self.genSetReg(reg, Type.usize, .{ .load_symbol = .{ .sym = sym.nlist_idx } }), + .mov => try self.genSetReg(reg, Type.usize, .{ .load_symbol = .{ .sym = sym.nlist_idx } }), + else => unreachable, + } + switch (tag) { + .lea, .mov => {}, + .call => try self.asmRegister(.{ ._, .call }, reg), + else => unreachable, + } } else { return self.fail("TODO implement genLazySymbol for x86_64 {s}", .{@tagName(self.bin_file.tag)}); } @@ -16103,6 +16065,8 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { .{ .lea_symbol = .{ .sym = tlv_sym } }, ); break :init .{ .load_frame = .{ .index = frame_index } }; + } else if (self.bin_file.cast(link.File.MachO)) |_| { + return self.fail("TODO implement lowering TLV variable to stack", .{}); } else break :init const_mcv, else => break :init const_mcv, } diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 97c6cdfc1b..9cadef1ef6 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -49,23 +49,21 @@ pub fn emitMir(emit: *Emit) Error!void { .r_addend = -4, }); } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| { - _ = macho_file; - @panic("TODO emitMir"); - // // Add relocation to the decl. - // const atom_index = - // macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?; - // const target = if (link.File.MachO.global_symbol_bit & symbol.sym_index != 0) - // macho_file.getGlobalByIndex(link.File.MachO.global_symbol_mask & symbol.sym_index) - // else - // link.File.MachO.SymbolWithLoc{ .sym_index = symbol.sym_index }; - // try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ - // .type = .branch, - // .target = target, - // .offset = end_offset - 4, - // .addend = 0, - // .pcrel = true, - // .length = 2, - // }); + // Add relocation to the decl. + const atom = macho_file.getSymbol(symbol.atom_index).getAtom(macho_file).?; + try atom.addReloc(macho_file, .{ + .tag = .@"extern", + .offset = end_offset - 4, + .target = symbol.sym_index, + .addend = 0, + .type = .branch, + .meta = .{ + .pcrel = true, + .has_subtractor = false, + .length = 2, + .symbolnum = 0, + }, + }); } else if (emit.lower.bin_file.cast(link.File.Coff)) |coff_file| { // Add relocation to the decl. const atom_index = coff_file.getAtomIndexForSymbol( @@ -151,6 +149,36 @@ pub fn emitMir(emit: *Emit) Error!void { }); } } + } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| { + const is_obj_or_static_lib = switch (emit.lower.output_mode) { + .Exe => false, + .Obj => true, + .Lib => emit.lower.link_mode == .Static, + }; + const atom = macho_file.getSymbol(data.atom_index).getAtom(macho_file).?; + const sym = macho_file.getSymbol(data.sym_index); + if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { + _ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file); + } + const @"type": link.File.MachO.Relocation.Type = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) + .zig_got_load + else if (sym.flags.needs_got) + .got_load + else + .signed; + try atom.addReloc(macho_file, .{ + .tag = .@"extern", + .offset = @intCast(end_offset - 4), + .target = data.sym_index, + .addend = 0, + .type = @"type", + .meta = .{ + .pcrel = true, + .has_subtractor = false, + .length = 2, + .symbolnum = 0, + }, + }); } else unreachable, .linker_got, .linker_direct, @@ -158,28 +186,8 @@ pub fn emitMir(emit: *Emit) Error!void { .linker_tlv, => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |_| { unreachable; - } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| { - _ = macho_file; - @panic("TODO emitMir"); - // const atom_index = - // macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?; - // const target = if (link.File.MachO.global_symbol_bit & symbol.sym_index != 0) - // macho_file.getGlobalByIndex(link.File.MachO.global_symbol_mask & symbol.sym_index) - // else - // link.File.MachO.SymbolWithLoc{ .sym_index = symbol.sym_index }; - // try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ - // .type = switch (lowered_relocs[0].target) { - // .linker_got => .got, - // .linker_direct => .signed, - // .linker_tlv => .tlv, - // else => unreachable, - // }, - // .target = target, - // .offset = @intCast(end_offset - 4), - // .addend = 0, - // .pcrel = true, - // .length = 2, - // }); + } else if (emit.lower.bin_file.cast(link.File.MachO)) |_| { + unreachable; } else if (emit.lower.bin_file.cast(link.File.Coff)) |coff_file| { const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index, diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index cc5ae7712b..eb3ed88b37 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -14,7 +14,7 @@ result_relocs_len: u8 = undefined, result_insts: [ std.mem.max(usize, &.{ 1, // non-pseudo instructions - 3, // TLS local dynamic (LD) sequence in PIC mode + 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode 2, // cmovcc: cmovcc \ cmovcc 3, // setcc: setcc \ setcc \ logicop 2, // jcc: jcc \ jcc @@ -32,7 +32,7 @@ result_relocs: [ 2, // jcc: jcc \ jcc 2, // test \ jcc \ probe \ sub \ jmp 1, // probe \ sub \ jcc - 3, // TLS local dynamic (LD) sequence in PIC mode + 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode }) ]Reloc = undefined, @@ -326,18 +326,6 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate { return Immediate.s(0); } -fn needsZigGot(sym: bits.Symbol, ctx: *link.File) bool { - const elf_file = ctx.cast(link.File.Elf).?; - const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); - return elf_file.symbol(sym_index).flags.needs_zig_got; -} - -fn isTls(sym: bits.Symbol, ctx: *link.File) bool { - const elf_file = ctx.cast(link.File.Elf).?; - const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); - return elf_file.symbol(sym_index).flags.is_tls; -} - fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void { const is_obj_or_static_lib = switch (lower.output_mode) { .Exe => false, @@ -359,80 +347,101 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) assert(mem_op.sib.disp == 0); assert(mem_op.sib.scale_index.scale == 0); - if (isTls(sym, lower.bin_file)) { - // TODO handle extern TLS vars, i.e., emit GD model - if (lower.pic) { - // Here, we currently assume local dynamic TLS vars, and so - // we emit LD model. - _ = lower.reloc(.{ .linker_tlsld = sym }); - lower.result_insts[lower.result_insts_len] = - try Instruction.new(.none, .lea, &[_]Operand{ - .{ .reg = .rdi }, - .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, - }); - lower.result_insts_len += 1; - if (lower.bin_file.cast(link.File.Elf)) |elf_file| { + if (lower.bin_file.cast(link.File.Elf)) |elf_file| { + const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); + const elf_sym = elf_file.symbol(sym_index); + + if (elf_sym.flags.is_tls) { + // TODO handle extern TLS vars, i.e., emit GD model + if (lower.pic) { + // Here, we currently assume local dynamic TLS vars, and so + // we emit LD model. + _ = lower.reloc(.{ .linker_tlsld = sym }); + lower.result_insts[lower.result_insts_len] = + try Instruction.new(.none, .lea, &[_]Operand{ + .{ .reg = .rdi }, + .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, + }); + lower.result_insts_len += 1; _ = lower.reloc(.{ .linker_extern_fn = .{ .atom_index = sym.atom_index, .sym_index = try elf_file.getGlobalSymbol("__tls_get_addr", null), } }); + lower.result_insts[lower.result_insts_len] = + try Instruction.new(.none, .call, &[_]Operand{ + .{ .imm = Immediate.s(0) }, + }); + lower.result_insts_len += 1; + _ = lower.reloc(.{ .linker_dtpoff = sym }); + emit_mnemonic = .lea; + break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ + .base = .{ .reg = .rax }, + .disp = std.math.minInt(i32), + }) }; + } else { + // Since we are linking statically, we emit LE model directly. + lower.result_insts[lower.result_insts_len] = + try Instruction.new(.none, .mov, &[_]Operand{ + .{ .reg = .rax }, + .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, + }); + lower.result_insts_len += 1; + _ = lower.reloc(.{ .linker_reloc = sym }); + emit_mnemonic = .lea; + break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ + .base = .{ .reg = .rax }, + .disp = std.math.minInt(i32), + }) }; } - lower.result_insts[lower.result_insts_len] = - try Instruction.new(.none, .call, &[_]Operand{ - .{ .imm = Immediate.s(0) }, - }); - lower.result_insts_len += 1; - _ = lower.reloc(.{ .linker_dtpoff = sym }); - emit_mnemonic = .lea; - break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ - .base = .{ .reg = .rax }, - .disp = std.math.minInt(i32), - }) }; - } else { - // Since we are linking statically, we emit LE model directly. - lower.result_insts[lower.result_insts_len] = - try Instruction.new(.none, .mov, &[_]Operand{ - .{ .reg = .rax }, - .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, - }); - lower.result_insts_len += 1; - _ = lower.reloc(.{ .linker_reloc = sym }); - emit_mnemonic = .lea; - break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ - .base = .{ .reg = .rax }, - .disp = std.math.minInt(i32), - }) }; } - } - _ = lower.reloc(.{ .linker_reloc = sym }); - break :op if (lower.pic) switch (mnemonic) { - .lea => { - break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; - }, - .mov => { - if (is_obj_or_static_lib and needsZigGot(sym, lower.bin_file)) emit_mnemonic = .lea; - break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; - }, - else => unreachable, - } else switch (mnemonic) { - .call => break :op if (is_obj_or_static_lib and needsZigGot(sym, lower.bin_file)) .{ - .imm = Immediate.s(0), - } else .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ - .base = .{ .reg = .ds }, - }) }, - .lea => { - emit_mnemonic = .mov; - break :op .{ .imm = Immediate.s(0) }; - }, - .mov => { - if (is_obj_or_static_lib and needsZigGot(sym, lower.bin_file)) emit_mnemonic = .lea; - break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ + _ = lower.reloc(.{ .linker_reloc = sym }); + break :op if (lower.pic) switch (mnemonic) { + .lea => { + break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; + }, + .mov => { + if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea; + break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; + }, + else => unreachable, + } else switch (mnemonic) { + .call => break :op if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) .{ + .imm = Immediate.s(0), + } else .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ .reg = .ds }, - }) }; - }, - else => unreachable, - }; + }) }, + .lea => { + emit_mnemonic = .mov; + break :op .{ .imm = Immediate.s(0) }; + }, + .mov => { + if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea; + break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ + .base = .{ .reg = .ds }, + }) }; + }, + else => unreachable, + }; + } else if (lower.bin_file.cast(link.File.MachO)) |macho_file| { + const macho_sym = macho_file.getSymbol(sym.sym_index); + + if (macho_sym.flags.tlv) { + @panic("TODO lower TLS access on macOS"); + } + + _ = lower.reloc(.{ .linker_reloc = sym }); + break :op switch (mnemonic) { + .lea => { + break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; + }, + .mov => { + if (is_obj_or_static_lib and macho_sym.flags.needs_zig_got) emit_mnemonic = .lea; + break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; + }, + else => unreachable, + }; + } }, }, }; |
