aboutsummaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2024-01-18 18:58:29 +0100
committerJakub Konka <kubkon@jakubkonka.com>2024-01-24 12:34:41 +0100
commit96cc9fafbf0a382c0ed0b6142986cd8373cffaa3 (patch)
treeec6cf83208e30a54f263807cf4e72f07b90457cd /src/arch
parent76dc305d4e71a9a4c9de92e6dde40a53eac1e328 (diff)
downloadzig-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.zig90
-rw-r--r--src/arch/x86_64/Emit.zig86
-rw-r--r--src/arch/x86_64/Lower.zig169
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,
+ };
+ }
},
},
};