authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-09-21 19:38:12+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-09-21 19:38:12+03:00
loga2dd0c387dd9e08c0147490b0667146758b6a43b
tree8891c006cb48c551361af4291925b90f6678b067
parentd722f0cc627c34f2c18681202a512d9aaa58fb18
parentf697e0a326b06b7dcf641fbd61110be756407dcf
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9652 from g-w1/p9d

plan9: emit debug info

4 files changed, 414 insertions(+), 70 deletions(-)

src/Module.zig+3-1
......@@ -3707,7 +3707,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
37073707 mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
37083708 },
37093709 .plan9 => {
3710 // TODO implement for plan9
3710 // TODO Look into detecting when this would be unnecessary by storing enough state
3711 // in `Decl` to notice that the line number did not change.
3712 mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
37113713 },
37123714 .c, .wasm, .spirv => {},
37133715 }
src/codegen.zig+62-5
......@@ -48,6 +48,28 @@ pub const DebugInfoOutput = union(enum) {
4848 dbg_info: *std.ArrayList(u8),
4949 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
5050 },
51 /// the plan9 debuginfo output is a bytecode with 4 opcodes
52 /// assume all numbers/variables are bytes
53 /// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset
54 /// x when x < 65 -> add x to line offset
55 /// x when x < 129 -> subtract 64 from x and subtract it from the line offset
56 /// x -> subtract 129 from x, multiply it by the quanta of the instruction size
57 /// (1 on x86_64), and add it to the pc
58 /// after every opcode, add the quanta of the instruction size to the pc
59 plan9: struct {
60 /// the actual opcodes
61 dbg_line: *std.ArrayList(u8),
62 /// what line the debuginfo starts on
63 /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl
64 start_line: *?u32,
65 /// what the line count ends on after codegen
66 /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl
67 end_line: *u32,
68 /// the last pc change op
69 /// This is very useful for adding quanta
70 /// to it if its not actually the last one.
71 pcop_change_index: *?u32,
72 },
5173 none,
5274};
5375
......@@ -915,6 +937,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
915937 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
916938 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
917939 },
940 .plan9 => {},
918941 .none => {},
919942 }
920943 }
......@@ -925,15 +948,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
925948 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
926949 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
927950 },
951 .plan9 => {},
928952 .none => {},
929953 }
930954 }
931955
932956 fn dbgAdvancePCAndLine(self: *Self, line: u32, column: u32) InnerError!void {
957 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
958 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
933959 switch (self.debug_output) {
934960 .dwarf => |dbg_out| {
935 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
936 const delta_pc = self.code.items.len - self.prev_di_pc;
937961 // TODO Look into using the DWARF special opcodes to compress this data.
938962 // It lets you emit single-byte opcodes that add different numbers to
939963 // both the PC and the line number at the same time.
......@@ -945,12 +969,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
945969 leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
946970 }
947971 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
972 self.prev_di_pc = self.code.items.len;
973 self.prev_di_line = line;
974 self.prev_di_column = column;
975 self.prev_di_pc = self.code.items.len;
976 },
977 .plan9 => |dbg_out| {
978 if (delta_pc <= 0) return; // only do this when the pc changes
979 // we have already checked the target in the linker to make sure it is compatable
980 const quant = @import("link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
981
982 // increasing the line number
983 try @import("link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
984 // increasing the pc
985 const d_pc_p9 = @intCast(i64, delta_pc) - quant;
986 if (d_pc_p9 > 0) {
987 // minus one becaue if its the last one, we want to leave space to change the line which is one quanta
988 try dbg_out.dbg_line.append(@intCast(u8, @divExact(d_pc_p9, quant) + 128) - quant);
989 if (dbg_out.pcop_change_index.*) |pci|
990 dbg_out.dbg_line.items[pci] += 1;
991 dbg_out.pcop_change_index.* = @intCast(u32, dbg_out.dbg_line.items.len - 1);
992 } else if (d_pc_p9 == 0) {
993 // we don't need to do anything, because adding the quant does it for us
994 } else unreachable;
995 if (dbg_out.start_line.* == null)
996 dbg_out.start_line.* = self.prev_di_line;
997 dbg_out.end_line.* = line;
998 // only do this if the pc changed
999 self.prev_di_line = line;
1000 self.prev_di_column = column;
1001 self.prev_di_pc = self.code.items.len;
9481002 },
9491003 .none => {},
9501004 }
951 self.prev_di_line = line;
952 self.prev_di_column = column;
953 self.prev_di_pc = self.code.items.len;
9541005 }
9551006
9561007 /// Asserts there is already capacity to insert into top branch inst_table.
......@@ -1034,6 +1085,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10341085 }
10351086 try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index));
10361087 },
1088 .plan9 => {},
10371089 .none => {},
10381090 }
10391091 }
......@@ -2459,6 +2511,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
24592511 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
24602512 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
24612513 },
2514 .plan9 => {},
24622515 .none => {},
24632516 }
24642517 },
......@@ -2493,6 +2546,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
24932546 else => {},
24942547 }
24952548 },
2549 .plan9 => {},
24962550 .none => {},
24972551 }
24982552 },
......@@ -2929,6 +2983,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29292983 }
29302984 if (self.air.value(callee)) |func_value| {
29312985 if (func_value.castTag(.function)) |func_payload| {
2986 try p9.seeDecl(func_payload.data.owner_decl);
29322987 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
29332988 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
29342989 const got_addr = p9.bases.data;
......@@ -2976,6 +3031,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29763031 }
29773032 if (self.air.value(callee)) |func_value| {
29783033 if (func_value.castTag(.function)) |func_payload| {
3034 try p9.seeDecl(func_payload.data.owner_decl);
29793035 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
29803036 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
29813037 const got_addr = p9.bases.data;
......@@ -4923,6 +4979,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
49234979 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
49244980 return MCValue{ .memory = got_addr };
49254981 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4982 try p9.seeDecl(decl);
49264983 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
49274984 return MCValue{ .memory = got_addr };
49284985 } else {
src/link/Plan9.zig+332-64
......@@ -20,6 +20,14 @@ const Allocator = std.mem.Allocator;
2020const log = std.log.scoped(.link);
2121const assert = std.debug.assert;
2222
23const FnDeclOutput = struct {
24 code: []const u8,
25 /// this might have to be modified in the linker, so thats why its mutable
26 lineinfo: []u8,
27 start_line: u32,
28 end_line: u32,
29};
30
2331base: link.File,
2432sixtyfour_bit: bool,
2533error_flags: File.ErrorFlags = File.ErrorFlags{},
......@@ -27,16 +35,45 @@ bases: Bases,
2735
2836/// A symbol's value is just casted down when compiling
2937/// for a 32 bit target.
38/// Does not represent the order or amount of symbols in the file
39/// it is just useful for storing symbols. Some other symbols are in
40/// file_segments.
3041syms: std.ArrayListUnmanaged(aout.Sym) = .{},
3142
32fn_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{},
43/// The plan9 a.out format requires segments of
44/// filenames to be deduplicated, so we use this map to
45/// de duplicate it. The value is the value of the path
46/// component
47file_segments: std.StringArrayHashMapUnmanaged(u16) = .{},
48/// The value of a 'f' symbol increments by 1 every time, so that no 2 'f'
49/// symbols have the same value.
50file_segments_i: u16 = 1,
51
52path_arena: std.heap.ArenaAllocator,
53
54/// maps a file scope to a hash map of decl to codegen output
55/// this is useful for line debuginfo, since it makes sense to sort by file
56/// The debugger looks for the first file (aout.Sym.Type.z) preceeding the text symbol
57/// of the function to know what file it came from.
58/// If we group the decls by file, it makes it really easy to do this (put the symbol in the correct place)
59fn_decl_table: std.AutoArrayHashMapUnmanaged(
60 *Module.Scope.File,
61 struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(*Module.Decl, FnDeclOutput) = .{} },
62) = .{},
3363data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{},
3464
3565hdr: aout.ExecHdr = undefined,
3666
67magic: u32,
68
3769entry_val: ?u64 = null,
3870
3971got_len: usize = 0,
72// A list of all the free got indexes, so when making a new decl
73// don't make a new one, just use one from here.
74got_index_free_list: std.ArrayListUnmanaged(u64) = .{},
75
76syms_index_free_list: std.ArrayListUnmanaged(u64) = .{},
4077
4178const Bases = struct {
4279 text: u64,
......@@ -103,8 +140,12 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
103140 33...64 => true,
104141 else => return error.UnsupportedP9Architecture,
105142 };
143
144 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
145
106146 const self = try gpa.create(Plan9);
107147 self.* = .{
148 .path_arena = arena_allocator,
108149 .base = .{
109150 .tag = .plan9,
110151 .options = options,
......@@ -113,21 +154,102 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
113154 },
114155 .sixtyfour_bit = sixtyfour_bit,
115156 .bases = undefined,
157 .magic = try aout.magicFromArch(self.base.options.target.cpu.arch),
116158 };
159 // a / will always be in a file path
160 try self.file_segments.put(self.base.allocator, "/", 1);
117161 return self;
118162}
119163
164fn putFn(self: *Plan9, decl: *Module.Decl, out: FnDeclOutput) !void {
165 const gpa = self.base.allocator;
166 const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.namespace.file_scope);
167 if (fn_map_res.found_existing) {
168 try fn_map_res.value_ptr.functions.put(gpa, decl, out);
169 } else {
170 const file = decl.namespace.file_scope;
171 const arena = &self.path_arena.allocator;
172 // each file gets a symbol
173 fn_map_res.value_ptr.* = .{
174 .sym_index = blk: {
175 try self.syms.append(gpa, undefined);
176 break :blk @intCast(u32, self.syms.items.len - 1);
177 },
178 };
179 try fn_map_res.value_ptr.functions.put(gpa, decl, out);
180
181 var a = std.ArrayList(u8).init(arena);
182 errdefer a.deinit();
183 // every 'z' starts with 0
184 try a.append(0);
185 // path component value of '/'
186 try a.writer().writeIntBig(u16, 1);
187
188 // getting the full file path
189 var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
190 const dir = file.pkg.root_src_directory.path orelse try std.os.getcwd(&buf);
191 const sub_path = try std.fs.path.join(arena, &.{ dir, file.sub_file_path });
192 try self.addPathComponents(sub_path, &a);
193
194 // null terminate
195 try a.append(0);
196 const final = a.toOwnedSlice();
197 self.syms.items[fn_map_res.value_ptr.sym_index] = .{
198 .type = .z,
199 .value = 1,
200 .name = final,
201 };
202 }
203}
204
205fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void {
206 const sep = std.fs.path.sep;
207 var it = std.mem.tokenize(u8, path, &.{sep});
208 while (it.next()) |component| {
209 if (self.file_segments.get(component)) |num| {
210 try a.writer().writeIntBig(u16, num);
211 } else {
212 self.file_segments_i += 1;
213 try self.file_segments.put(self.base.allocator, component, self.file_segments_i);
214 try a.writer().writeIntBig(u16, self.file_segments_i);
215 }
216 }
217}
218
120219pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
121220 if (build_options.skip_non_native and builtin.object_format != .plan9) {
122221 @panic("Attempted to compile for object format that was disabled by build configuration");
123222 }
124223
125224 const decl = func.owner_decl;
225
226 try self.seeDecl(decl);
126227 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });
127228
128229 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
129230 defer code_buffer.deinit();
130 const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ .none = .{} });
231 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
232 defer dbg_line_buffer.deinit();
233 var start_line: ?u32 = null;
234 var end_line: u32 = undefined;
235 var pcop_change_index: ?u32 = null;
236
237 const res = try codegen.generateFunction(
238 &self.base,
239 decl.srcLoc(),
240 func,
241 air,
242 liveness,
243 &code_buffer,
244 .{
245 .plan9 = .{
246 .dbg_line = &dbg_line_buffer,
247 .end_line = &end_line,
248 .start_line = &start_line,
249 .pcop_change_index = &pcop_change_index,
250 },
251 },
252 );
131253 const code = switch (res) {
132254 .appended => code_buffer.toOwnedSlice(),
133255 .fail => |em| {
......@@ -136,7 +258,13 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
136258 return;
137259 },
138260 };
139 try self.fn_decl_table.put(self.base.allocator, decl, code);
261 const out: FnDeclOutput = .{
262 .code = code,
263 .lineinfo = dbg_line_buffer.toOwnedSlice(),
264 .start_line = start_line.?,
265 .end_line = end_line,
266 };
267 try self.putFn(decl, out);
140268 return self.updateFinish(decl);
141269}
142270
......@@ -151,6 +279,8 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {
151279 }
152280 }
153281
282 try self.seeDecl(decl);
283
154284 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });
155285
156286 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
......@@ -192,8 +322,12 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void {
192322 if (decl.link.plan9.sym_index) |s| {
193323 self.syms.items[s] = sym;
194324 } else {
195 try self.syms.append(self.base.allocator, sym);
196 decl.link.plan9.sym_index = self.syms.items.len - 1;
325 if (self.syms_index_free_list.popOrNull()) |i| {
326 decl.link.plan9.sym_index = i;
327 } else {
328 try self.syms.append(self.base.allocator, sym);
329 decl.link.plan9.sym_index = self.syms.items.len - 1;
330 }
197331 }
198332}
199333
......@@ -209,6 +343,30 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void {
209343 return self.flushModule(comp);
210344}
211345
346pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void {
347 if (delta_line > 0 and delta_line < 65) {
348 const toappend = @intCast(u8, delta_line);
349 try l.append(toappend);
350 } else if (delta_line < 0 and delta_line > -65) {
351 const toadd: u8 = @intCast(u8, -delta_line + 64);
352 try l.append(toadd);
353 } else if (delta_line != 0) {
354 try l.append(0);
355 try l.writer().writeIntBig(i32, delta_line);
356 }
357}
358
359fn declCount(self: *Plan9) u64 {
360 var fn_decl_count: u64 = 0;
361 var itf_files = self.fn_decl_table.iterator();
362 while (itf_files.next()) |ent| {
363 // get the submap
364 var submap = ent.value_ptr.functions;
365 fn_decl_count += submap.count();
366 }
367 return self.data_decl_table.count() + fn_decl_count;
368}
369
212370pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
213371 if (build_options.skip_non_native and builtin.object_format != .plan9) {
214372 @panic("Attempted to compile for object format that was disabled by build configuration");
......@@ -224,15 +382,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
224382
225383 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
226384
227 // TODO I changed this assert from == to >= but this code all needs to be audited; see
228 // the comment in `freeDecl`.
229 assert(self.got_len >= self.fn_decl_table.count() + self.data_decl_table.count());
385 assert(self.got_len == self.declCount() + self.got_index_free_list.items.len);
230386 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
231387 var got_table = try self.base.allocator.alloc(u8, got_size);
232388 defer self.base.allocator.free(got_table);
233389
234 // + 2 for header, got, symbols
235 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.fn_decl_table.count() + self.data_decl_table.count() + 3);
390 // + 4 for header, got, symbols, linecountinfo
391 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.declCount() + 4);
236392 defer self.base.allocator.free(iovecs);
237393
238394 const file = self.base.file.?;
......@@ -245,30 +401,52 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
245401 iovecs[0] = .{ .iov_base = hdr_slice.ptr, .iov_len = hdr_slice.len };
246402 var iovecs_i: usize = 1;
247403 var text_i: u64 = 0;
404
405 var linecountinfo = std.ArrayList(u8).init(self.base.allocator);
406 defer linecountinfo.deinit();
248407 // text
249408 {
250 var it = self.fn_decl_table.iterator();
251 while (it.next()) |entry| {
252 const decl = entry.key_ptr.*;
253 const code = entry.value_ptr.*;
254 log.debug("write text decl {*} ({s})", .{ decl, decl.name });
255 foff += code.len;
256 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
257 iovecs_i += 1;
258 const off = self.getAddr(text_i, .t);
259 text_i += code.len;
260 decl.link.plan9.offset = off;
261 if (!self.sixtyfour_bit) {
262 mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off));
263 mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
264 } else {
265 mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
266 }
267 self.syms.items[decl.link.plan9.sym_index.?].value = off;
268 if (mod.decl_exports.get(decl)) |exports| {
269 try self.addDeclExports(mod, decl, exports);
409 var linecount: u32 = 0;
410 var it_file = self.fn_decl_table.iterator();
411 while (it_file.next()) |fentry| {
412 var it = fentry.value_ptr.functions.iterator();
413 while (it.next()) |entry| {
414 const decl = entry.key_ptr.*;
415 const out = entry.value_ptr.*;
416 log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line, out.end_line });
417 {
418 // connect the previous decl to the next
419 const delta_line = @intCast(i32, out.start_line) - @intCast(i32, linecount);
420
421 try changeLine(&linecountinfo, delta_line);
422 // TODO change the pc too (maybe?)
423
424 // write out the actual info that was generated in codegen now
425 try linecountinfo.appendSlice(out.lineinfo);
426 linecount = out.end_line;
427 }
428 foff += out.code.len;
429 iovecs[iovecs_i] = .{ .iov_base = out.code.ptr, .iov_len = out.code.len };
430 iovecs_i += 1;
431 const off = self.getAddr(text_i, .t);
432 text_i += out.code.len;
433 decl.link.plan9.offset = off;
434 if (!self.sixtyfour_bit) {
435 mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off));
436 mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
437 } else {
438 mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
439 }
440 self.syms.items[decl.link.plan9.sym_index.?].value = off;
441 if (mod.decl_exports.get(decl)) |exports| {
442 try self.addDeclExports(mod, decl, exports);
443 }
270444 }
271445 }
446 if (linecountinfo.items.len & 1 == 1) {
447 // just a nop to make it even, the plan9 linker does this
448 try linecountinfo.append(129);
449 }
272450 // etext symbol
273451 self.syms.items[2].value = self.getAddr(text_i, .t);
274452 }
......@@ -306,20 +484,23 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
306484 // edata
307485 self.syms.items[1].value = self.getAddr(0x0, .b);
308486 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
309 defer sym_buf.deinit();
310487 try self.writeSyms(&sym_buf);
311 assert(2 + self.fn_decl_table.count() + self.data_decl_table.count() == iovecs_i); // we didn't write all the decls
312 iovecs[iovecs_i] = .{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len };
488 const syms = sym_buf.toOwnedSlice();
489 defer self.base.allocator.free(syms);
490 assert(2 + self.declCount() == iovecs_i); // we didn't write all the decls
491 iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };
492 iovecs_i += 1;
493 iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len };
313494 iovecs_i += 1;
314495 // generate the header
315496 self.hdr = .{
316 .magic = try aout.magicFromArch(self.base.options.target.cpu.arch),
497 .magic = self.magic,
317498 .text = @intCast(u32, text_i),
318499 .data = @intCast(u32, data_i),
319 .syms = @intCast(u32, sym_buf.items.len),
500 .syms = @intCast(u32, syms.len),
320501 .bss = 0,
321 .pcsz = 0,
322502 .spsz = 0,
503 .pcsz = @intCast(u32, linecountinfo.items.len),
323504 .entry = @intCast(u32, self.entry_val.?),
324505 };
325506 std.mem.copy(u8, hdr_slice, self.hdr.toU8s()[0..hdr_size]);
......@@ -360,18 +541,43 @@ fn addDeclExports(
360541}
361542
362543pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {
363 // TODO this is not the correct check for being function body,
364 // it could just be a function pointer.
365544 // TODO audit the lifetimes of decls table entries. It's possible to get
366545 // allocateDeclIndexes and then freeDecl without any updateDecl in between.
367546 // However that is planned to change, see the TODO comment in Module.zig
368547 // in the deleteUnusedDecl function.
369 const is_fn = (decl.ty.zigTypeTag() == .Fn);
548 const is_fn = (decl.val.tag() == .function);
370549 if (is_fn) {
371 _ = self.fn_decl_table.swapRemove(decl);
550 var symidx_and_submap =
551 self.fn_decl_table.get(decl.namespace.file_scope).?;
552 var submap = symidx_and_submap.functions;
553 _ = submap.swapRemove(decl);
554 if (submap.count() == 0) {
555 self.syms.items[symidx_and_submap.sym_index] = aout.Sym.undefined_symbol;
556 self.syms_index_free_list.append(self.base.allocator, symidx_and_submap.sym_index) catch {};
557 submap.deinit(self.base.allocator);
558 }
372559 } else {
373560 _ = self.data_decl_table.swapRemove(decl);
374561 }
562 if (decl.link.plan9.got_index) |i| {
563 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length
564 self.got_index_free_list.append(self.base.allocator, i) catch {};
565 }
566 if (decl.link.plan9.sym_index) |i| {
567 self.syms_index_free_list.append(self.base.allocator, i) catch {};
568 self.syms.items[i] = aout.Sym.undefined_symbol;
569 }
570}
571
572pub fn seeDecl(self: *Plan9, decl: *Module.Decl) !void {
573 if (decl.link.plan9.got_index == null) {
574 if (self.got_index_free_list.popOrNull()) |i| {
575 decl.link.plan9.got_index = i;
576 } else {
577 self.got_len += 1;
578 decl.link.plan9.got_index = self.got_len - 1;
579 }
580 }
375581}
376582
377583pub fn updateDeclExports(
......@@ -380,6 +586,7 @@ pub fn updateDeclExports(
380586 decl: *Module.Decl,
381587 exports: []const *Module.Export,
382588) !void {
589 try self.seeDecl(decl);
383590 // we do all the things in flush
384591 _ = self;
385592 _ = module;
......@@ -387,17 +594,29 @@ pub fn updateDeclExports(
387594 _ = exports;
388595}
389596pub fn deinit(self: *Plan9) void {
390 var itf = self.fn_decl_table.iterator();
391 while (itf.next()) |entry| {
392 self.base.allocator.free(entry.value_ptr.*);
597 const gpa = self.base.allocator;
598 var itf_files = self.fn_decl_table.iterator();
599 while (itf_files.next()) |ent| {
600 // get the submap
601 var submap = ent.value_ptr.functions;
602 defer submap.deinit(gpa);
603 var itf = submap.iterator();
604 while (itf.next()) |entry| {
605 gpa.free(entry.value_ptr.code);
606 gpa.free(entry.value_ptr.lineinfo);
607 }
393608 }
394 self.fn_decl_table.deinit(self.base.allocator);
609 self.fn_decl_table.deinit(gpa);
395610 var itd = self.data_decl_table.iterator();
396611 while (itd.next()) |entry| {
397 self.base.allocator.free(entry.value_ptr.*);
612 gpa.free(entry.value_ptr.*);
398613 }
399 self.data_decl_table.deinit(self.base.allocator);
400 self.syms.deinit(self.base.allocator);
614 self.data_decl_table.deinit(gpa);
615 self.syms.deinit(gpa);
616 self.got_index_free_list.deinit(gpa);
617 self.syms_index_free_list.deinit(gpa);
618 self.file_segments.deinit(gpa);
619 self.path_arena.deinit();
401620}
402621
403622pub const Export = ?usize;
......@@ -407,7 +626,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
407626 return error.LLVMBackendDoesNotSupportPlan9;
408627 assert(options.object_format == .plan9);
409628 const file = try options.emit.?.directory.handle.createFile(sub_path, .{
410 .truncate = false,
411629 .read = true,
412630 .mode = link.determineMode(options),
413631 });
......@@ -441,27 +659,77 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
441659 return self;
442660}
443661
662pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void {
663 log.debug("write sym.name: {s}", .{sym.name});
664 log.debug("write sym.value: {x}", .{sym.value});
665 if (sym.type == .bad) return; // we don't want to write free'd symbols
666 if (!self.sixtyfour_bit) {
667 try w.writeIntBig(u32, @intCast(u32, sym.value));
668 } else {
669 try w.writeIntBig(u64, sym.value);
670 }
671 try w.writeByte(@enumToInt(sym.type));
672 try w.writeAll(sym.name);
673 try w.writeByte(0);
674}
444675pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
445676 const writer = buf.writer();
446 for (self.syms.items) |sym| {
447 log.debug("sym.name: {s}", .{sym.name});
448 log.debug("sym.value: {x}", .{sym.value});
449 if (mem.eql(u8, sym.name, "_start"))
450 self.entry_val = sym.value;
451 if (!self.sixtyfour_bit) {
452 try writer.writeIntBig(u32, @intCast(u32, sym.value));
453 } else {
454 try writer.writeIntBig(u64, sym.value);
677 // write the f symbols
678 {
679 var it = self.file_segments.iterator();
680 while (it.next()) |entry| {
681 try self.writeSym(writer, .{
682 .type = .f,
683 .value = entry.value_ptr.*,
684 .name = entry.key_ptr.*,
685 });
686 }
687 }
688 // write the data symbols
689 {
690 var it = self.data_decl_table.iterator();
691 while (it.next()) |entry| {
692 const decl = entry.key_ptr.*;
693 const sym = self.syms.items[decl.link.plan9.sym_index.?];
694 try self.writeSym(writer, sym);
695 if (self.base.options.module.?.decl_exports.get(decl)) |exports| {
696 for (exports) |e| {
697 try self.writeSym(writer, self.syms.items[e.link.plan9.?]);
698 }
699 }
700 }
701 }
702 // text symbols are the hardest:
703 // the file of a text symbol is the .z symbol before it
704 // so we have to write everything in the right order
705 {
706 var it_file = self.fn_decl_table.iterator();
707 while (it_file.next()) |fentry| {
708 var symidx_and_submap = fentry.value_ptr;
709 // write the z symbol
710 try self.writeSym(writer, self.syms.items[symidx_and_submap.sym_index]);
711
712 // write all the decls come from the file of the z symbol
713 var submap_it = symidx_and_submap.functions.iterator();
714 while (submap_it.next()) |entry| {
715 const decl = entry.key_ptr.*;
716 const sym = self.syms.items[decl.link.plan9.sym_index.?];
717 try self.writeSym(writer, sym);
718 if (self.base.options.module.?.decl_exports.get(decl)) |exports| {
719 for (exports) |e| {
720 const s = self.syms.items[e.link.plan9.?];
721 if (mem.eql(u8, s.name, "_start"))
722 self.entry_val = s.value;
723 try self.writeSym(writer, s);
724 }
725 }
726 }
455727 }
456 try writer.writeByte(@enumToInt(sym.type));
457 try writer.writeAll(sym.name);
458 try writer.writeByte(0);
459728 }
460729}
461730
731/// this will be removed, moved to updateFinish
462732pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {
463 if (decl.link.plan9.got_index == null) {
464 self.got_len += 1;
465 decl.link.plan9.got_index = self.got_len - 1;
466 }
733 _ = self;
734 _ = decl;
467735}
src/link/Plan9/aout.zig+17
......@@ -34,6 +34,12 @@ pub const Sym = struct {
3434 type: Type,
3535 name: []const u8,
3636
37 pub const undefined_symbol: Sym = .{
38 .value = undefined,
39 .type = .bad,
40 .name = "undefined_symbol",
41 };
42
3743 /// The type field is one of the following characters with the
3844 /// high bit set:
3945 /// T text segment symbol
......@@ -65,6 +71,8 @@ pub const Sym = struct {
6571 z = 0x80 | 'z',
6672 Z = 0x80 | 'Z',
6773 m = 0x80 | 'm',
74 /// represents an undefined symbol, to be removed in flush
75 bad = 0,
6876
6977 pub fn toGlobal(self: Type) Type {
7078 return switch (self) {
......@@ -112,3 +120,12 @@ pub fn magicFromArch(arch: std.Target.Cpu.Arch) !u32 {
112120 else => error.ArchNotSupportedByPlan9,
113121 };
114122}
123
124/// gets the quantization of pc for the arch
125pub fn getPCQuant(arch: std.Target.Cpu.Arch) !u8 {
126 return switch (arch) {
127 .i386, .x86_64 => 1,
128 .powerpc, .powerpc64, .mips, .sparc, .arm, .aarch64 => 4,
129 else => error.ArchNotSupportedByPlan9,
130 };
131}