diff options
| author | Jacob G-W <jacoblevgw@gmail.com> | 2023-06-14 15:43:46 -0400 |
|---|---|---|
| committer | Jacob G-W <jacoblevgw@gmail.com> | 2023-06-16 08:34:30 -0400 |
| commit | 5343a2f566a5c235055f4aebb4ab9c10773e57f0 (patch) | |
| tree | 308e605be58fb7f63a283fb13d1fd6691bbb4c23 /src | |
| parent | 4dac9f54ddfcd6036b8b2b0704d0b9aa3ed9bd6d (diff) | |
| download | zig-5343a2f566a5c235055f4aebb4ab9c10773e57f0.tar.gz zig-5343a2f566a5c235055f4aebb4ab9c10773e57f0.zip | |
plan9: revamp the relocation system to allow decl refs
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 5 | ||||
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 8 | ||||
| -rw-r--r-- | src/codegen.zig | 9 | ||||
| -rw-r--r-- | src/link/Plan9.zig | 195 |
4 files changed, 139 insertions, 78 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index e798d46f27..f1669256c8 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -130,6 +130,8 @@ const Owner = union(enum) { } 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().?; + } else if (ctx.bin_file.cast(link.File.Plan9)) |p9_file| { + return p9_file.seeDecl(decl_index); } else unreachable; }, .lazy_sym => |lazy_sym| { @@ -141,6 +143,9 @@ const Owner = union(enum) { const atom = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); return coff_file.getAtom(atom).getSymbolIndex().?; + } else if (ctx.bin_file.cast(link.File.Plan9)) |p9_file| { + return p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); } else unreachable; }, } diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 506092ff17..78ff918715 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -118,6 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void { .pcrel = true, .length = 2, }); + } else if (emit.bin_file.cast(link.File.Plan9)) |p9_file| { + const atom_index = symbol.atom_index; + try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct + .target = symbol.sym_index, // we set sym_index to just be the atom index + .offset = @intCast(u32, end_offset - 4), + .addend = 0, + .pcrel = true, + }); } else return emit.fail("TODO implement linker reloc for {s}", .{ @tagName(emit.bin_file.tag), }), diff --git a/src/codegen.zig b/src/codegen.zig index 7625fbe031..d446200a3b 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -879,12 +879,9 @@ fn genUnnamedConst( return GenResult.mcv(.{ .load_direct = local_sym_index }); } else if (bin_file.cast(link.File.Coff)) |_| { return GenResult.mcv(.{ .load_direct = local_sym_index }); - } else if (bin_file.cast(link.File.Plan9)) |p9| { - const ptr_bits = target.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_index = local_sym_index; // the plan9 backend returns the got_index - const got_addr = p9.bases.data + got_index * ptr_bytes; - return GenResult.mcv(.{ .memory = got_addr }); + } else if (bin_file.cast(link.File.Plan9)) |_| { + const atom_index = local_sym_index; // plan9 returns the atom_index + return GenResult.mcv(.{ .load_direct = atom_index }); } else { return GenResult.fail(bin_file.allocator, src_loc, "TODO genUnnamedConst for target {}", .{target}); } diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index dccfa1d6c0..6433fb2762 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -81,7 +81,7 @@ unnamed_const_atoms: UnnamedConstTable = .{}, lazy_syms: LazySymbolTable = .{}, -relocs: std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Reloc)) = .{}, +relocs: std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Reloc)) = .{}, hdr: aout.ExecHdr = undefined, // relocs: std. @@ -100,9 +100,10 @@ atoms: std.ArrayListUnmanaged(Atom) = .{}, decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, const Reloc = struct { - target: Module.Decl.Index, + target: Atom.Index, offset: u64, addend: u32, + pcrel: bool = false, }; const Bases = struct { @@ -111,7 +112,7 @@ const Bases = struct { data: u64, }; -const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: Atom, code: []const u8 })); +const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); @@ -140,12 +141,36 @@ pub const Atom = struct { sym_index: ?usize, /// offset into got got_index: ?usize, - /// We can optionally store code with the atom - /// It is still owned by whatever created it - /// This can be useful so that we don't need - /// to setup so much infrastructure just to store code - /// for stuff like LazySymbols. - code: ?[]const u8 = null, + /// We include the code here to be use in relocs + /// In the case of unnamed_const_atoms and lazy_syms, this atom owns the code. + /// But, in the case of function and data decls, they own the code and this field + /// is just a pointer for convience. + code: CodePtr, + + const CodePtr = struct { + code_ptr: ?[*]u8, + other: union { + code_len: usize, + decl_index: Module.Decl.Index, + }, + fn getCode(self: CodePtr, plan9: *const Plan9) []u8 { + const mod = plan9.base.options.module.?; + return if (self.code_ptr) |p| p[0..self.other.code_len] else blk: { + const decl_index = self.other.decl_index; + const decl = mod.declPtr(decl_index); + if (decl.ty.zigTypeTag(mod) == .Fn) { + const table = plan9.fn_decl_table.get(decl.getFileScope(mod)).?.functions; + const output = table.get(decl_index).?; + break :blk output.code; + } else { + break :blk plan9.data_decl_table.get(decl_index).?; + } + }; + } + fn getOwnedCode(self: CodePtr) ?[]u8 { + return if (self.code_ptr) |p| p[0..self.other.code_len] else null; + } + }; pub const Index = u32; @@ -329,7 +354,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air: const decl = mod.declPtr(decl_index); self.freeUnnamedConsts(decl_index); - _ = try self.seeDecl(decl_index); + const atom_idx = try self.seeDecl(decl_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -363,6 +388,10 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air: return; }, }; + self.getAtomPtr(atom_idx).code = .{ + .code_ptr = null, + .other = .{ .decl_index = decl_index }, + }; const out: FnDeclOutput = .{ .code = code, .lineinfo = try dbg_line_buffer.toOwnedSlice(), @@ -394,12 +423,13 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index }); const sym_index = try self.allocateSymbolIndex(); - - const info: Atom = .{ + const new_atom_idx = try self.createAtom(); + var info: Atom = .{ .type = .d, .offset = null, .sym_index = sym_index, .got_index = self.allocateGotIndex(), + .code = undefined, // filled in later }; const sym: aout.Sym = .{ .value = undefined, @@ -411,7 +441,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .{ .none = {}, }, .{ - .parent_atom_index = @enumToInt(decl_index), + .parent_atom_index = new_atom_idx, }); const code = switch (res) { .ok => code_buffer.items, @@ -425,9 +455,12 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I // duped_code is freed when the unnamed const is freed var duped_code = try self.base.allocator.dupe(u8, code); errdefer self.base.allocator.free(duped_code); - try unnamed_consts.append(self.base.allocator, .{ .info = info, .code = duped_code }); - // we return the got_index to codegen so that it can reference to the place of the data in the got - return @intCast(u32, info.got_index.?); + const new_atom = self.getAtomPtr(new_atom_idx); + new_atom.* = info; + new_atom.code = .{ .code_ptr = duped_code.ptr, .other = .{ .code_len = duped_code.len } }; + try unnamed_consts.append(self.base.allocator, new_atom_idx); + // we return the new_atom_idx to codegen + return new_atom_idx; } pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void { @@ -442,7 +475,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo } } - _ = try self.seeDecl(decl_index); + const atom_idx = try self.seeDecl(decl_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -452,7 +485,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo .ty = decl.ty, .val = decl_val, }, &code_buffer, .{ .none = {} }, .{ - .parent_atom_index = @enumToInt(decl_index), + .parent_atom_index = @intCast(Atom.Index, atom_idx), }); const code = switch (res) { .ok => code_buffer.items, @@ -464,6 +497,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo }; try self.data_decl_table.ensureUnusedCapacity(self.base.allocator, 1); const duped_code = try self.base.allocator.dupe(u8, code); + self.getAtomPtr(self.decls.get(decl_index).?.index).code = .{ .code_ptr = null, .other = .{ .decl_index = decl_index } }; if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| { self.base.allocator.free(old_entry.value); } @@ -636,6 +670,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No var it = fentry.value_ptr.functions.iterator(); while (it.next()) |entry| { const decl_index = entry.key_ptr.*; + const decl = mod.declPtr(decl_index); const atom = self.getAtomPtr(self.decls.get(decl_index).?.index); const out = entry.value_ptr.*; { @@ -655,6 +690,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No const off = self.getAddr(text_i, .t); text_i += out.code.len; atom.offset = off; + log.debug("write text decl {*} ({}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ decl, decl.name.fmt(&mod.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off }); if (!self.sixtyfour_bit) { mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); } else { @@ -677,7 +713,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No while (it.next()) |kv| { const meta = kv.value_ptr; const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue; - const code = text_atom.code.?; + const code = text_atom.code.getOwnedCode().?; foff += code.len; iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; iovecs_i += 1; @@ -725,21 +761,22 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No // write the unnamed constants after the other data decls var it_unc = self.unnamed_const_atoms.iterator(); while (it_unc.next()) |unnamed_consts| { - for (unnamed_consts.value_ptr.items) |*unnamed_const| { - const code = unnamed_const.code; - log.debug("write unnamed const: ({s})", .{self.syms.items[unnamed_const.info.sym_index.?].name}); + for (unnamed_consts.value_ptr.items) |atom_idx| { + const atom = self.getAtomPtr(atom_idx); + const code = atom.code.getOwnedCode().?; // unnamed consts must own their code + log.debug("write unnamed const: ({s})", .{self.syms.items[atom.sym_index.?].name}); foff += code.len; iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; iovecs_i += 1; const off = self.getAddr(data_i, .d); data_i += code.len; - unnamed_const.info.offset = off; + atom.offset = off; if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[unnamed_const.info.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); + mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); } else { - mem.writeInt(u64, got_table[unnamed_const.info.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); + mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); } - self.syms.items[unnamed_const.info.sym_index.?].value = off; + self.syms.items[atom.sym_index.?].value = off; } } // the lazy data symbols @@ -747,7 +784,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No while (it_lazy.next()) |kv| { const meta = kv.value_ptr; const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue; - const code = data_atom.code.?; + const code = data_atom.code.getOwnedCode().?; // lazy symbols must own their code foff += code.len; iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; iovecs_i += 1; @@ -795,35 +832,31 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No { var it = self.relocs.iterator(); while (it.next()) |kv| { - const source_decl_index = kv.key_ptr.*; - const source_decl = mod.declPtr(source_decl_index); + const source_atom_index = kv.key_ptr.*; + const source_atom = self.getAtom(source_atom_index); + const source_atom_symbol = self.syms.items[source_atom.sym_index.?]; for (kv.value_ptr.items) |reloc| { - const target_decl_index = reloc.target; - const target_decl = mod.declPtr(target_decl_index); - _ = target_decl; - const target_atom = self.getAtom(self.decls.get(target_decl_index).?.index); - const target_decl_offset = target_atom.offset.?; + const target_atom_index = reloc.target; + const target_atom = self.getAtomPtr(target_atom_index); + const target_symbol = self.syms.items[target_atom.sym_index.?]; + const target_offset = target_atom.offset.?; const offset = reloc.offset; const addend = reloc.addend; - const code = blk: { - const is_fn = source_decl.ty.zigTypeTag(mod) == .Fn; - if (is_fn) { - const table = self.fn_decl_table.get(source_decl.getFileScope(mod)).?.functions; - const output = table.get(source_decl_index).?; - break :blk output.code; - } else { - const code = self.data_decl_table.get(source_decl_index).?; - break :blk code; - } - }; + const code = source_atom.code.getCode(self); - if (!self.sixtyfour_bit) { - mem.writeInt(u32, code[@intCast(usize, offset)..][0..4], @intCast(u32, target_decl_offset + addend), self.base.options.target.cpu.arch.endian()); + if (reloc.pcrel) { + const disp = @intCast(i32, target_offset) - @intCast(i32, source_atom.offset.?) - 4 - @intCast(i32, offset); + mem.writeInt(i32, code[@intCast(usize, offset)..][0..4], @intCast(i32, disp), self.base.options.target.cpu.arch.endian()); } else { - mem.writeInt(u64, code[@intCast(usize, offset)..][0..8], target_decl_offset + addend, self.base.options.target.cpu.arch.endian()); + if (!self.sixtyfour_bit) { + mem.writeInt(u32, code[@intCast(usize, offset)..][0..4], @intCast(u32, target_offset + addend), self.base.options.target.cpu.arch.endian()); + } else { + mem.writeInt(u64, code[@intCast(usize, offset)..][0..8], target_offset + addend, self.base.options.target.cpu.arch.endian()); + } } + log.debug("relocating the address of '{s}' + {d} into '{s}' + {d} (({s}[{d}] = 0x{x} + 0x{x})", .{ target_symbol.name, addend, source_atom_symbol.name, offset, source_atom_symbol.name, offset, target_offset, addend }); } } } @@ -908,18 +941,19 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { } self.freeUnnamedConsts(decl_index); { - const relocs = self.relocs.getPtr(decl_index) orelse return; + const atom_index = self.decls.get(decl_index).?.index; + const relocs = self.relocs.getPtr(atom_index) orelse return; relocs.clearAndFree(self.base.allocator); - assert(self.relocs.remove(decl_index)); + assert(self.relocs.remove(atom_index)); } } fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void { const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; - for (unnamed_consts.items) |c| { - self.base.allocator.free(self.syms.items[c.info.sym_index.?].name); - self.base.allocator.free(c.code); - self.syms.items[c.info.sym_index.?] = aout.Sym.undefined_symbol; - self.syms_index_free_list.append(self.base.allocator, c.info.sym_index.?) catch {}; + for (unnamed_consts.items) |atom_idx| { + const atom = self.getAtom(atom_idx); + self.base.allocator.free(self.syms.items[atom.sym_index.?].name); + self.syms.items[atom.sym_index.?] = aout.Sym.undefined_symbol; + self.syms_index_free_list.append(self.base.allocator, atom.sym_index.?) catch {}; } unnamed_consts.clearAndFree(self.base.allocator); } @@ -933,6 +967,7 @@ fn createAtom(self: *Plan9) !Atom.Index { .offset = null, .sym_index = null, .got_index = null, + .code = undefined, }; return index; } @@ -992,9 +1027,6 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind const gpa = self.base.allocator; const mod = self.base.options.module.?; - const atom = self.getAtomPtr(atom_index); - const local_sym_index = atom.sym_index.?; - var required_alignment: u32 = undefined; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -1010,7 +1042,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind .type = if (sym.kind == .code) .t else .d, .name = name, }; - self.syms.items[atom.sym_index.?] = symbol; + self.syms.items[self.getAtomPtr(atom_index).sym_index.?] = symbol; // generate the code const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| @@ -1028,7 +1060,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind &required_alignment, &code_buffer, .none, - .{ .parent_atom_index = @intCast(u32, local_sym_index) }, + .{ .parent_atom_index = @intCast(Atom.Index, atom_index) }, ); const code = switch (res) { .ok => code_buffer.items, @@ -1040,8 +1072,10 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind // duped_code is freed when the atom is freed var duped_code = try self.base.allocator.dupe(u8, code); errdefer self.base.allocator.free(duped_code); - - atom.code = duped_code; + self.getAtomPtr(atom_index).code = .{ + .code_ptr = duped_code.ptr, + .other = .{ .code_len = duped_code.len }, + }; } pub fn deinit(self: *Plan9) void { @@ -1089,8 +1123,8 @@ pub fn deinit(self: *Plan9) void { self.syms_index_free_list.deinit(gpa); self.file_segments.deinit(gpa); self.path_arena.deinit(); - for (self.atoms.items) |atom| { - if (atom.code) |c| { + for (self.atoms.items) |a| { + if (a.code.getOwnedCode()) |c| { gpa.free(c); } } @@ -1151,7 +1185,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option } pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void { - log.debug("write sym{{name: {s}, value: {x}}}", .{ sym.name, sym.value }); + // log.debug("write sym{{name: {s}, value: {x}}}", .{ sym.name, sym.value }); if (sym.type == .bad) return; // we don't want to write free'd symbols if (!self.sixtyfour_bit) { try w.writeIntBig(u32, @intCast(u32, sym.value)); @@ -1210,6 +1244,17 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { try self.writeSym(writer, sym); } } + // unnamed consts + { + var it = self.unnamed_const_atoms.iterator(); + while (it.next()) |kv| { + const consts = kv.value_ptr; + for (consts.items) |atom_index| { + const sym = self.syms.items[self.getAtom(atom_index).sym_index.?]; + try self.writeSym(writer, sym); + } + } + } // text symbols are the hardest: // the file of a text symbol is the .z symbol before it // so we have to write everything in the right order @@ -1266,6 +1311,7 @@ pub fn getDeclVAddr( ) !u64 { const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); + // we might already know the vaddr if (decl.ty.zigTypeTag(mod) == .Fn) { var start = self.bases.text; var it_file = self.fn_decl_table.iterator(); @@ -1285,17 +1331,22 @@ pub fn getDeclVAddr( start += kv.value_ptr.len; } } + const atom_index = try self.seeDecl(decl_index); // the parent_atom_index in this case is just the decl_index of the parent - const gop = try self.relocs.getOrPut(self.base.allocator, @intToEnum(Module.Decl.Index, reloc_info.parent_atom_index)); - if (!gop.found_existing) { - gop.value_ptr.* = .{}; - } - try gop.value_ptr.append(self.base.allocator, .{ - .target = decl_index, + try self.addReloc(reloc_info.parent_atom_index, .{ + .target = atom_index, .offset = reloc_info.offset, .addend = reloc_info.addend, }); - return 0; + return 0xcafebabe; +} + +pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void { + const gop = try self.relocs.getOrPut(self.base.allocator, parent_index); + if (!gop.found_existing) { + gop.value_ptr.* = .{}; + } + try gop.value_ptr.append(self.base.allocator, reloc); } pub fn getAtom(self: *const Plan9, index: Atom.Index) Atom { |
