diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-02-03 12:49:40 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-02-03 12:49:40 -0700 |
| commit | fab9b7110ed1fa7bb082aad5e095047441db2b24 (patch) | |
| tree | 81fef60aa45e7980dab8f3e23e5b5e92b40ee0a9 /src/link/Plan9.zig | |
| parent | d20d69b59e6b65a99f45cb6a45c14e887034dd18 (diff) | |
| parent | 60935decd318498529a016eeb1379d943a7e830d (diff) | |
| download | zig-fab9b7110ed1fa7bb082aad5e095047441db2b24.tar.gz zig-fab9b7110ed1fa7bb082aad5e095047441db2b24.zip | |
Merge remote-tracking branch 'origin/master' into llvm16
Diffstat (limited to 'src/link/Plan9.zig')
| -rw-r--r-- | src/link/Plan9.zig | 249 |
1 files changed, 154 insertions, 95 deletions
diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 5423269bf0..87e3ca5c22 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -21,14 +21,7 @@ const Allocator = std.mem.Allocator; const log = std.log.scoped(.link); const assert = std.debug.assert; -const FnDeclOutput = struct { - /// this code is modified when relocated so it is mutable - code: []u8, - /// this might have to be modified in the linker, so thats why its mutable - lineinfo: []u8, - start_line: u32, - end_line: u32, -}; +pub const base_tag = .plan9; base: link.File, sixtyfour_bit: bool, @@ -101,6 +94,9 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{}, syms_index_free_list: std.ArrayListUnmanaged(usize) = .{}, +decl_blocks: std.ArrayListUnmanaged(DeclBlock) = .{}, +decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, + const Reloc = struct { target: Module.Decl.Index, offset: u64, @@ -115,6 +111,42 @@ const Bases = struct { const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 })); +pub const PtrWidth = enum { p32, p64 }; + +pub const DeclBlock = struct { + type: aout.Sym.Type, + /// offset in the text or data sects + offset: ?u64, + /// offset into syms + sym_index: ?usize, + /// offset into got + got_index: ?usize, + + pub const Index = u32; +}; + +const DeclMetadata = struct { + index: DeclBlock.Index, + exports: std.ArrayListUnmanaged(usize) = .{}, + + fn getExport(m: DeclMetadata, p9: *const Plan9, name: []const u8) ?usize { + for (m.exports.items) |exp| { + const sym = p9.syms.items[exp]; + if (mem.eql(u8, name, sym.name)) return exp; + } + return null; + } +}; + +const FnDeclOutput = struct { + /// this code is modified when relocated so it is mutable + code: []u8, + /// this might have to be modified in the linker, so thats why its mutable + lineinfo: []u8, + start_line: u32, + end_line: u32, +}; + fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { return addr + switch (t) { .T, .t, .l, .L => self.bases.text, @@ -127,22 +159,6 @@ fn getSymAddr(self: Plan9, s: aout.Sym) u64 { return self.getAddr(s.value, s.type); } -pub const DeclBlock = struct { - type: aout.Sym.Type, - /// offset in the text or data sects - offset: ?u64, - /// offset into syms - sym_index: ?usize, - /// offset into got - got_index: ?usize, - pub const empty = DeclBlock{ - .type = .t, - .offset = null, - .sym_index = null, - .got_index = null, - }; -}; - pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { return switch (arch) { .x86_64 => .{ @@ -164,8 +180,6 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { }; } -pub const PtrWidth = enum { p32, p64 }; - pub fn createEmpty(gpa: Allocator, options: link.Options) !*Plan9 { if (options.use_llvm) return error.LLVMBackendDoesNotSupportPlan9; @@ -271,7 +285,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv const decl = module.declPtr(decl_index); self.freeUnnamedConsts(decl_index); - try self.seeDecl(decl_index); + _ = try self.seeDecl(decl_index); log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); var code_buffer = std.ArrayList(u8).init(self.base.allocator); @@ -299,7 +313,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv }, ); const code = switch (res) { - .appended => try code_buffer.toOwnedSlice(), + .ok => try code_buffer.toOwnedSlice(), .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -313,11 +327,11 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv .end_line = end_line, }; try self.putFn(decl_index, out); - return self.updateFinish(decl); + return self.updateFinish(decl_index); } pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { - try self.seeDecl(decl_index); + _ = try self.seeDecl(decl_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -358,8 +372,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I .parent_atom_index = @enumToInt(decl_index), }); const code = switch (res) { - .externally_managed => |x| x, - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); @@ -388,7 +401,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) } } - try self.seeDecl(decl_index); + _ = try self.seeDecl(decl_index); log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index }); @@ -403,8 +416,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) .parent_atom_index = @enumToInt(decl_index), }); const code = switch (res) { - .externally_managed => |x| x, - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -416,28 +428,31 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| { self.base.allocator.free(old_entry.value); } - return self.updateFinish(decl); + return self.updateFinish(decl_index); } /// called at the end of update{Decl,Func} -fn updateFinish(self: *Plan9, decl: *Module.Decl) !void { +fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { + const decl = self.base.options.module.?.declPtr(decl_index); const is_fn = (decl.ty.zigTypeTag() == .Fn); log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name }); const sym_t: aout.Sym.Type = if (is_fn) .t else .d; + + const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); // write the internal linker metadata - decl.link.plan9.type = sym_t; + decl_block.type = sym_t; // write the symbol - // we already have the got index because that got allocated in allocateDeclIndexes + // we already have the got index const sym: aout.Sym = .{ .value = undefined, // the value of stuff gets filled in in flushModule - .type = decl.link.plan9.type, + .type = decl_block.type, .name = mem.span(decl.name), }; - if (decl.link.plan9.sym_index) |s| { + if (decl_block.sym_index) |s| { self.syms.items[s] = sym; } else { const s = try self.allocateSymbolIndex(); - decl.link.plan9.sym_index = s; + decl_block.sym_index = s; self.syms.items[s] = sym; } } @@ -552,6 +567,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No while (it.next()) |entry| { const decl_index = entry.key_ptr.*; const decl = mod.declPtr(decl_index); + const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); const out = entry.value_ptr.*; log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line + 1, out.end_line }); { @@ -570,16 +586,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No iovecs_i += 1; const off = self.getAddr(text_i, .t); text_i += out.code.len; - decl.link.plan9.offset = off; + decl_block.offset = off; if (!self.sixtyfour_bit) { - mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off)); - mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); + mem.writeIntNative(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off)); + mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); } else { - mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); + mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); } - self.syms.items[decl.link.plan9.sym_index.?].value = off; + self.syms.items[decl_block.sym_index.?].value = off; if (mod.decl_exports.get(decl_index)) |exports| { - try self.addDeclExports(mod, decl, exports.items); + try self.addDeclExports(mod, decl_index, exports.items); } } } @@ -600,6 +616,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No while (it.next()) |entry| { const decl_index = entry.key_ptr.*; const decl = mod.declPtr(decl_index); + const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); const code = entry.value_ptr.*; log.debug("write data decl {*} ({s})", .{ decl, decl.name }); @@ -608,15 +625,15 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No iovecs_i += 1; const off = self.getAddr(data_i, .d); data_i += code.len; - decl.link.plan9.offset = off; + decl_block.offset = off; if (!self.sixtyfour_bit) { - mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); + mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); } else { - mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); + mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); } - self.syms.items[decl.link.plan9.sym_index.?].value = off; + self.syms.items[decl_block.sym_index.?].value = off; if (mod.decl_exports.get(decl_index)) |exports| { - try self.addDeclExports(mod, decl, exports.items); + try self.addDeclExports(mod, decl_index, exports.items); } } // write the unnamed constants after the other data decls @@ -678,7 +695,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No for (kv.value_ptr.items) |reloc| { const target_decl_index = reloc.target; const target_decl = mod.declPtr(target_decl_index); - const target_decl_offset = target_decl.link.plan9.offset.?; + const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index); + const target_decl_offset = target_decl_block.offset.?; const offset = reloc.offset; const addend = reloc.addend; @@ -711,35 +729,43 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No fn addDeclExports( self: *Plan9, module: *Module, - decl: *Module.Decl, + decl_index: Module.Decl.Index, exports: []const *Module.Export, ) !void { + const metadata = self.decls.getPtr(decl_index).?; + const decl_block = self.getDeclBlock(metadata.index); + for (exports) |exp| { // plan9 does not support custom sections if (exp.options.section) |section_name| { if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) { - try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{})); + try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create( + self.base.allocator, + module.declPtr(decl_index).srcLoc(), + "plan9 does not support extra sections", + .{}, + )); break; } } const sym = .{ - .value = decl.link.plan9.offset.?, - .type = decl.link.plan9.type.toGlobal(), + .value = decl_block.offset.?, + .type = decl_block.type.toGlobal(), .name = exp.options.name, }; - if (exp.link.plan9) |i| { + if (metadata.getExport(self, exp.options.name)) |i| { self.syms.items[i] = sym; } else { try self.syms.append(self.base.allocator, sym); - exp.link.plan9 = self.syms.items.len - 1; + try metadata.exports.append(self.base.allocator, self.syms.items.len - 1); } } } pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { // TODO audit the lifetimes of decls table entries. It's possible to get - // allocateDeclIndexes and then freeDecl without any updateDecl in between. + // freeDecl without any updateDecl in between. // However that is planned to change, see the TODO comment in Module.zig // in the deleteUnusedDecl function. const mod = self.base.options.module.?; @@ -762,13 +788,18 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { self.base.allocator.free(removed_entry.value); } } - if (decl.link.plan9.got_index) |i| { - // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length - self.got_index_free_list.append(self.base.allocator, i) catch {}; - } - if (decl.link.plan9.sym_index) |i| { - self.syms_index_free_list.append(self.base.allocator, i) catch {}; - self.syms.items[i] = aout.Sym.undefined_symbol; + if (self.decls.fetchRemove(decl_index)) |const_kv| { + var kv = const_kv; + const decl_block = self.getDeclBlock(kv.value.index); + if (decl_block.got_index) |i| { + // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length + self.got_index_free_list.append(self.base.allocator, i) catch {}; + } + if (decl_block.sym_index) |i| { + self.syms_index_free_list.append(self.base.allocator, i) catch {}; + self.syms.items[i] = aout.Sym.undefined_symbol; + } + kv.value.exports.deinit(self.base.allocator); } self.freeUnnamedConsts(decl_index); { @@ -788,12 +819,30 @@ fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void { unnamed_consts.clearAndFree(self.base.allocator); } -pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void { - const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - if (decl.link.plan9.got_index == null) { - decl.link.plan9.got_index = self.allocateGotIndex(); +fn createDeclBlock(self: *Plan9) !DeclBlock.Index { + const gpa = self.base.allocator; + const index = @intCast(DeclBlock.Index, self.decl_blocks.items.len); + const decl_block = try self.decl_blocks.addOne(gpa); + decl_block.* = .{ + .type = .t, + .offset = null, + .sym_index = null, + .got_index = null, + }; + return index; +} + +pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !DeclBlock.Index { + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (!gop.found_existing) { + const index = try self.createDeclBlock(); + self.getDeclBlockPtr(index).got_index = self.allocateGotIndex(); + gop.value_ptr.* = .{ + .index = index, + .exports = .{}, + }; } + return gop.value_ptr.index; } pub fn updateDeclExports( @@ -802,7 +851,7 @@ pub fn updateDeclExports( decl_index: Module.Decl.Index, exports: []const *Module.Export, ) !void { - try self.seeDecl(decl_index); + _ = try self.seeDecl(decl_index); // we do all the things in flush _ = module; _ = exports; @@ -844,10 +893,17 @@ pub fn deinit(self: *Plan9) void { self.syms_index_free_list.deinit(gpa); self.file_segments.deinit(gpa); self.path_arena.deinit(); + self.decl_blocks.deinit(gpa); + + { + var it = self.decls.iterator(); + while (it.next()) |entry| { + entry.value_ptr.exports.deinit(gpa); + } + self.decls.deinit(gpa); + } } -pub const Export = ?usize; -pub const base_tag = .plan9; pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 { if (options.use_llvm) return error.LLVMBackendDoesNotSupportPlan9; @@ -913,20 +969,19 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { } } - const mod = self.base.options.module.?; - // write the data symbols { var it = self.data_decl_table.iterator(); while (it.next()) |entry| { const decl_index = entry.key_ptr.*; - const decl = mod.declPtr(decl_index); - const sym = self.syms.items[decl.link.plan9.sym_index.?]; + const decl_metadata = self.decls.get(decl_index).?; + const decl_block = self.getDeclBlock(decl_metadata.index); + const sym = self.syms.items[decl_block.sym_index.?]; try self.writeSym(writer, sym); if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { - for (exports.items) |e| { - try self.writeSym(writer, self.syms.items[e.link.plan9.?]); - } + for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| { + try self.writeSym(writer, self.syms.items[exp_i]); + }; } } } @@ -945,32 +1000,28 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { var submap_it = symidx_and_submap.functions.iterator(); while (submap_it.next()) |entry| { const decl_index = entry.key_ptr.*; - const decl = mod.declPtr(decl_index); - const sym = self.syms.items[decl.link.plan9.sym_index.?]; + const decl_metadata = self.decls.get(decl_index).?; + const decl_block = self.getDeclBlock(decl_metadata.index); + const sym = self.syms.items[decl_block.sym_index.?]; try self.writeSym(writer, sym); if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { - for (exports.items) |e| { - const s = self.syms.items[e.link.plan9.?]; + for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| { + const s = self.syms.items[exp_i]; if (mem.eql(u8, s.name, "_start")) self.entry_val = s.value; try self.writeSym(writer, s); - } + }; } } } } } -/// this will be removed, moved to updateFinish -pub fn allocateDeclIndexes(self: *Plan9, decl_index: Module.Decl.Index) !void { - _ = self; - _ = decl_index; -} /// Must be called only after a successful call to `updateDecl`. -pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl: *const Module.Decl) !void { +pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void { _ = self; _ = mod; - _ = decl; + _ = decl_index; } pub fn getDeclVAddr( @@ -1011,3 +1062,11 @@ pub fn getDeclVAddr( }); return undefined; } + +pub fn getDeclBlock(self: *const Plan9, index: DeclBlock.Index) DeclBlock { + return self.decl_blocks.items[index]; +} + +fn getDeclBlockPtr(self: *Plan9, index: DeclBlock.Index) *DeclBlock { + return &self.decl_blocks.items[index]; +} |
