authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-29 17:45:00-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-29 17:45:00-04:00
log28dc208f65c0a3feca4d6018fb316d7c219d29a7
tree80b19479b1a50431e138e138cb8eaaf750905db6
parente036cc48d59e5f7c025df7bbd9923a13e30c6ec9
parent5aef54cbc83cce5c1afe9aededfc505d89559741
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13082 from g-w1/unnamed-decls-and-relocs-p9

Plan9: Fix The Backend

7 files changed, 284 insertions(+), 37 deletions(-)

src/Compilation.zig+3-3
...@@ -1091,10 +1091,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1091,10 +1091,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1091 // Once they are capable this condition could be removed. When removing this condition,1091 // Once they are capable this condition could be removed. When removing this condition,
1092 // also test the use case of `build-obj -fcompiler-rt` with the native backends1092 // also test the use case of `build-obj -fcompiler-rt` with the native backends
1093 // and make sure the compiler-rt symbols are emitted.1093 // and make sure the compiler-rt symbols are emitted.
1094 const capable_of_building_compiler_rt = build_options.have_llvm;1094 const capable_of_building_compiler_rt = build_options.have_llvm and options.target.os.tag != .plan9;
10951095
1096 const capable_of_building_zig_libc = build_options.have_llvm;1096 const capable_of_building_zig_libc = build_options.have_llvm and options.target.os.tag != .plan9;
1097 const capable_of_building_ssp = build_options.have_llvm;1097 const capable_of_building_ssp = build_options.have_llvm and options.target.os.tag != .plan9;
10981098
1099 const comp: *Compilation = comp: {1099 const comp: *Compilation = comp: {
1100 // For allocations that have the same lifetime as Compilation. This arena is used only during this1100 // For allocations that have the same lifetime as Compilation. This arena is used only during this
src/arch/x86_64/CodeGen.zig+6-2
...@@ -6953,8 +6953,12 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -6953,8 +6953,12 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
6953 .@"type" = .direct,6953 .@"type" = .direct,
6954 .sym_index = local_sym_index,6954 .sym_index = local_sym_index,
6955 } };6955 } };
6956 } else if (self.bin_file.cast(link.File.Plan9)) |_| {6956 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6957 return self.fail("TODO lower unnamed const in Plan9", .{});6957 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
6958 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
6959 const got_index = local_sym_index; // the plan9 backend returns the got_index
6960 const got_addr = p9.bases.data + got_index * ptr_bytes;
6961 return MCValue{ .memory = got_addr };
6958 } else {6962 } else {
6959 return self.fail("TODO lower unnamed const", .{});6963 return self.fail("TODO lower unnamed const", .{});
6960 }6964 }
src/link.zig+1-1
...@@ -581,7 +581,7 @@ pub const File = struct {...@@ -581,7 +581,7 @@ pub const File = struct {
581 .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl),581 .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl),
582 .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl),582 .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl),
583 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl),583 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl),
584 .plan9 => @panic("TODO: implement updateDeclLineNumber for plan9"),584 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl),
585 .spirv, .nvptx => {},585 .spirv, .nvptx => {},
586 }586 }
587 }587 }
src/link/Plan9.zig+231-31
...@@ -22,7 +22,8 @@ const log = std.log.scoped(.link);...@@ -22,7 +22,8 @@ const log = std.log.scoped(.link);
22const assert = std.debug.assert;22const assert = std.debug.assert;
2323
24const FnDeclOutput = struct {24const FnDeclOutput = struct {
25 code: []const u8,25 /// this code is modified when relocated so it is mutable
26 code: []u8,
26 /// this might have to be modified in the linker, so thats why its mutable27 /// this might have to be modified in the linker, so thats why its mutable
27 lineinfo: []u8,28 lineinfo: []u8,
28 start_line: u32,29 start_line: u32,
...@@ -61,10 +62,34 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged(...@@ -61,10 +62,34 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged(
61 *Module.File,62 *Module.File,
62 struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, FnDeclOutput) = .{} },63 struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, FnDeclOutput) = .{} },
63) = .{},64) = .{},
64data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []const u8) = .{},65/// the code is modified when relocated, so that is why it is mutable
6566data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []u8) = .{},
67
68/// Table of unnamed constants associated with a parent `Decl`.
69/// We store them here so that we can free the constants whenever the `Decl`
70/// needs updating or is freed.
71///
72/// For example,
73///
74/// ```zig
75/// const Foo = struct{
76/// a: u8,
77/// };
78///
79/// pub fn main() void {
80/// var foo = Foo{ .a = 1 };
81/// _ = foo;
82/// }
83/// ```
84///
85/// value assigned to label `foo` is an unnamed constant belonging/associated
86/// with `Decl` `main`, and lives as long as that `Decl`.
87unnamed_const_atoms: UnnamedConstTable = .{},
88
89relocs: std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Reloc)) = .{},
66hdr: aout.ExecHdr = undefined,90hdr: aout.ExecHdr = undefined,
6791
92// relocs: std.
68magic: u32,93magic: u32,
6994
70entry_val: ?u64 = null,95entry_val: ?u64 = null,
...@@ -76,12 +101,20 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},...@@ -76,12 +101,20 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},
76101
77syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},102syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},
78103
104const Reloc = struct {
105 target: Module.Decl.Index,
106 offset: u64,
107 addend: u32,
108};
109
79const Bases = struct {110const Bases = struct {
80 text: u64,111 text: u64,
81 /// the Global Offset Table starts at the beginning of the data section112 /// the Global Offset Table starts at the beginning of the data section
82 data: u64,113 data: u64,
83};114};
84115
116const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 }));
117
85fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 {118fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 {
86 return addr + switch (t) {119 return addr + switch (t) {
87 .T, .t, .l, .L => self.bases.text,120 .T, .t, .l, .L => self.bases.text,
...@@ -233,6 +266,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv...@@ -233,6 +266,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
233266
234 const decl_index = func.owner_decl;267 const decl_index = func.owner_decl;
235 const decl = module.declPtr(decl_index);268 const decl = module.declPtr(decl_index);
269 self.freeUnnamedConsts(decl_index);
236270
237 try self.seeDecl(decl_index);271 try self.seeDecl(decl_index);
238 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });272 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });
...@@ -280,11 +314,62 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv...@@ -280,11 +314,62 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
280}314}
281315
282pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {316pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {
283 _ = self;317 try self.seeDecl(decl_index);
284 _ = tv;318 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
285 _ = decl_index;319 defer code_buffer.deinit();
286 log.debug("TODO lowerUnnamedConst for Plan9", .{});320
287 return error.AnalysisFail;321 const mod = self.base.options.module.?;
322 const decl = mod.declPtr(decl_index);
323
324 const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index);
325 if (!gop.found_existing) {
326 gop.value_ptr.* = .{};
327 }
328 const unnamed_consts = gop.value_ptr;
329
330 const decl_name = try decl.getFullyQualifiedName(mod);
331 defer self.base.allocator.free(decl_name);
332
333 const index = unnamed_consts.items.len;
334 // name is freed when the unnamed const is freed
335 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index });
336
337 const sym_index = try self.allocateSymbolIndex();
338
339 const info: DeclBlock = .{
340 .type = .d,
341 .offset = null,
342 .sym_index = sym_index,
343 .got_index = self.allocateGotIndex(),
344 };
345 const sym: aout.Sym = .{
346 .value = undefined,
347 .type = info.type,
348 .name = name,
349 };
350 self.syms.items[info.sym_index.?] = sym;
351
352 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .{
353 .none = {},
354 }, .{
355 .parent_atom_index = @enumToInt(decl_index),
356 });
357 const code = switch (res) {
358 .externally_managed => |x| x,
359 .appended => code_buffer.items,
360 .fail => |em| {
361 decl.analysis = .codegen_failure;
362 try mod.failed_decls.put(mod.gpa, decl_index, em);
363 log.err("{s}", .{em.msg});
364 return error.AnalysisFail;
365 },
366 };
367 // duped_code is freed when the unnamed const is freed
368 var duped_code = try self.base.allocator.dupe(u8, code);
369 errdefer self.base.allocator.free(duped_code);
370 try unnamed_consts.append(self.base.allocator, .{ .info = info, .code = duped_code });
371 // we return the got_index to codegen so that it can reference to the place of the data in the got
372 return @intCast(u32, info.got_index.?);
288}373}
289374
290pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) !void {375pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) !void {
...@@ -302,18 +387,17 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index)...@@ -302,18 +387,17 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index)
302387
303 try self.seeDecl(decl_index);388 try self.seeDecl(decl_index);
304389
305 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });390 log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index });
306391
307 var code_buffer = std.ArrayList(u8).init(self.base.allocator);392 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
308 defer code_buffer.deinit();393 defer code_buffer.deinit();
309 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;394 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
310 // TODO we need the symbol index for symbol in the table of locals for the containing atom395 // TODO we need the symbol index for symbol in the table of locals for the containing atom
311 const sym_index = decl.link.plan9.sym_index orelse 0;
312 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{396 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
313 .ty = decl.ty,397 .ty = decl.ty,
314 .val = decl_val,398 .val = decl_val,
315 }, &code_buffer, .{ .none = {} }, .{399 }, &code_buffer, .{ .none = {} }, .{
316 .parent_atom_index = @intCast(u32, sym_index),400 .parent_atom_index = @enumToInt(decl_index),
317 });401 });
318 const code = switch (res) {402 const code = switch (res) {
319 .externally_managed => |x| x,403 .externally_managed => |x| x,
...@@ -347,12 +431,26 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void {...@@ -347,12 +431,26 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void {
347 if (decl.link.plan9.sym_index) |s| {431 if (decl.link.plan9.sym_index) |s| {
348 self.syms.items[s] = sym;432 self.syms.items[s] = sym;
349 } else {433 } else {
350 if (self.syms_index_free_list.popOrNull()) |i| {434 const s = try self.allocateSymbolIndex();
351 decl.link.plan9.sym_index = i;435 decl.link.plan9.sym_index = s;
352 } else {436 self.syms.items[s] = sym;
353 try self.syms.append(self.base.allocator, sym);437 }
354 decl.link.plan9.sym_index = self.syms.items.len - 1;438}
355 }439
440fn allocateSymbolIndex(self: *Plan9) !usize {
441 if (self.syms_index_free_list.popOrNull()) |i| {
442 return i;
443 } else {
444 _ = try self.syms.addOne(self.base.allocator);
445 return self.syms.items.len - 1;
446 }
447}
448fn allocateGotIndex(self: *Plan9) usize {
449 if (self.got_index_free_list.popOrNull()) |i| {
450 return i;
451 } else {
452 self.got_len += 1;
453 return self.got_len - 1;
356 }454 }
357}455}
358456
...@@ -381,7 +479,8 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void {...@@ -381,7 +479,8 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void {
381 }479 }
382}480}
383481
384fn declCount(self: *Plan9) usize {482// counts decls and unnamed consts
483fn atomCount(self: *Plan9) usize {
385 var fn_decl_count: usize = 0;484 var fn_decl_count: usize = 0;
386 var itf_files = self.fn_decl_table.iterator();485 var itf_files = self.fn_decl_table.iterator();
387 while (itf_files.next()) |ent| {486 while (itf_files.next()) |ent| {
...@@ -389,7 +488,13 @@ fn declCount(self: *Plan9) usize {...@@ -389,7 +488,13 @@ fn declCount(self: *Plan9) usize {
389 var submap = ent.value_ptr.functions;488 var submap = ent.value_ptr.functions;
390 fn_decl_count += submap.count();489 fn_decl_count += submap.count();
391 }490 }
392 return self.data_decl_table.count() + fn_decl_count;491 const data_decl_count = self.data_decl_table.count();
492 var unnamed_const_count: usize = 0;
493 var it_unc = self.unnamed_const_atoms.iterator();
494 while (it_unc.next()) |unnamed_consts| {
495 unnamed_const_count += unnamed_consts.value_ptr.items.len;
496 }
497 return data_decl_count + fn_decl_count + unnamed_const_count;
393}498}
394499
395pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {500pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
...@@ -411,13 +516,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -411,13 +516,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
411516
412 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;517 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
413518
414 assert(self.got_len == self.declCount() + self.got_index_free_list.items.len);519 assert(self.got_len == self.atomCount() + self.got_index_free_list.items.len);
415 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;520 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
416 var got_table = try self.base.allocator.alloc(u8, got_size);521 var got_table = try self.base.allocator.alloc(u8, got_size);
417 defer self.base.allocator.free(got_table);522 defer self.base.allocator.free(got_table);
418523
419 // + 4 for header, got, symbols, linecountinfo524 // + 4 for header, got, symbols, linecountinfo
420 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.declCount() + 4);525 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4);
421 defer self.base.allocator.free(iovecs);526 defer self.base.allocator.free(iovecs);
422527
423 const file = self.base.file.?;528 const file = self.base.file.?;
...@@ -509,6 +614,26 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -509,6 +614,26 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
509 try self.addDeclExports(mod, decl, exports);614 try self.addDeclExports(mod, decl, exports);
510 }615 }
511 }616 }
617 // write the unnamed constants after the other data decls
618 var it_unc = self.unnamed_const_atoms.iterator();
619 while (it_unc.next()) |unnamed_consts| {
620 for (unnamed_consts.value_ptr.items) |*unnamed_const| {
621 const code = unnamed_const.code;
622 log.debug("write unnamed const: ({s})", .{self.syms.items[unnamed_const.info.sym_index.?].name});
623 foff += code.len;
624 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
625 iovecs_i += 1;
626 const off = self.getAddr(data_i, .d);
627 data_i += code.len;
628 unnamed_const.info.offset = off;
629 if (!self.sixtyfour_bit) {
630 mem.writeInt(u32, got_table[unnamed_const.info.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
631 } else {
632 mem.writeInt(u64, got_table[unnamed_const.info.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
633 }
634 self.syms.items[unnamed_const.info.sym_index.?].value = off;
635 }
636 }
512 // edata symbol637 // edata symbol
513 self.syms.items[0].value = self.getAddr(data_i, .b);638 self.syms.items[0].value = self.getAddr(data_i, .b);
514 }639 }
...@@ -518,7 +643,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -518,7 +643,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
518 try self.writeSyms(&sym_buf);643 try self.writeSyms(&sym_buf);
519 const syms = sym_buf.toOwnedSlice();644 const syms = sym_buf.toOwnedSlice();
520 defer self.base.allocator.free(syms);645 defer self.base.allocator.free(syms);
521 assert(2 + self.declCount() == iovecs_i); // we didn't write all the decls646 assert(2 + self.atomCount() == iovecs_i); // we didn't write all the decls
522 iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };647 iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };
523 iovecs_i += 1;648 iovecs_i += 1;
524 iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len };649 iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len };
...@@ -539,6 +664,42 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -539,6 +664,42 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
539 if (self.sixtyfour_bit) {664 if (self.sixtyfour_bit) {
540 mem.writeIntSliceBig(u64, hdr_buf[32..40], self.entry_val.?);665 mem.writeIntSliceBig(u64, hdr_buf[32..40], self.entry_val.?);
541 }666 }
667 // perform the relocs
668 {
669 var it = self.relocs.iterator();
670 while (it.next()) |kv| {
671 const source_decl_index = kv.key_ptr.*;
672 const source_decl = mod.declPtr(source_decl_index);
673 for (kv.value_ptr.items) |reloc| {
674 const target_decl_index = reloc.target;
675 const target_decl = mod.declPtr(target_decl_index);
676 const target_decl_offset = target_decl.link.plan9.offset.?;
677
678 const offset = reloc.offset;
679 const addend = reloc.addend;
680
681 log.debug("relocating the address of '{s}' + {d} into '{s}' + {d}", .{ target_decl.name, addend, source_decl.name, offset });
682
683 const code = blk: {
684 const is_fn = source_decl.ty.zigTypeTag() == .Fn;
685 if (is_fn) {
686 const table = self.fn_decl_table.get(source_decl.getFileScope()).?.functions;
687 const output = table.get(source_decl_index).?;
688 break :blk output.code;
689 } else {
690 const code = self.data_decl_table.get(source_decl_index).?;
691 break :blk code;
692 }
693 };
694
695 if (!self.sixtyfour_bit) {
696 mem.writeInt(u32, code[@intCast(usize, offset)..][0..4], @intCast(u32, target_decl_offset + addend), self.base.options.target.cpu.arch.endian());
697 } else {
698 mem.writeInt(u64, code[@intCast(usize, offset)..][0..8], target_decl_offset + addend, self.base.options.target.cpu.arch.endian());
699 }
700 }
701 }
702 }
542 // write it all!703 // write it all!
543 try file.pwritevAll(iovecs, 0);704 try file.pwritevAll(iovecs, 0);
544}705}
...@@ -599,18 +760,29 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {...@@ -599,18 +760,29 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {
599 self.syms_index_free_list.append(self.base.allocator, i) catch {};760 self.syms_index_free_list.append(self.base.allocator, i) catch {};
600 self.syms.items[i] = aout.Sym.undefined_symbol;761 self.syms.items[i] = aout.Sym.undefined_symbol;
601 }762 }
763 self.freeUnnamedConsts(decl_index);
764 {
765 const relocs = self.relocs.getPtr(decl_index) orelse return;
766 relocs.clearAndFree(self.base.allocator);
767 assert(self.relocs.remove(decl_index));
768 }
769}
770fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void {
771 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
772 for (unnamed_consts.items) |c| {
773 self.base.allocator.free(self.syms.items[c.info.sym_index.?].name);
774 self.base.allocator.free(c.code);
775 self.syms.items[c.info.sym_index.?] = aout.Sym.undefined_symbol;
776 self.syms_index_free_list.append(self.base.allocator, c.info.sym_index.?) catch {};
777 }
778 unnamed_consts.clearAndFree(self.base.allocator);
602}779}
603780
604pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void {781pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void {
605 const mod = self.base.options.module.?;782 const mod = self.base.options.module.?;
606 const decl = mod.declPtr(decl_index);783 const decl = mod.declPtr(decl_index);
607 if (decl.link.plan9.got_index == null) {784 if (decl.link.plan9.got_index == null) {
608 if (self.got_index_free_list.popOrNull()) |i| {785 decl.link.plan9.got_index = self.allocateGotIndex();
609 decl.link.plan9.got_index = i;
610 } else {
611 self.got_len += 1;
612 decl.link.plan9.got_index = self.got_len - 1;
613 }
614 }786 }
615}787}
616788
...@@ -627,6 +799,19 @@ pub fn updateDeclExports(...@@ -627,6 +799,19 @@ pub fn updateDeclExports(
627}799}
628pub fn deinit(self: *Plan9) void {800pub fn deinit(self: *Plan9) void {
629 const gpa = self.base.allocator;801 const gpa = self.base.allocator;
802 {
803 var it = self.relocs.valueIterator();
804 while (it.next()) |relocs| {
805 relocs.deinit(self.base.allocator);
806 }
807 self.relocs.deinit(self.base.allocator);
808 }
809 // free the unnamed consts
810 var it_unc = self.unnamed_const_atoms.iterator();
811 while (it_unc.next()) |kv| {
812 self.freeUnnamedConsts(kv.key_ptr.*);
813 }
814 self.unnamed_const_atoms.deinit(gpa);
630 var itf_files = self.fn_decl_table.iterator();815 var itf_files = self.fn_decl_table.iterator();
631 while (itf_files.next()) |ent| {816 while (itf_files.next()) |ent| {
632 // get the submap817 // get the submap
...@@ -771,12 +956,18 @@ pub fn allocateDeclIndexes(self: *Plan9, decl_index: Module.Decl.Index) !void {...@@ -771,12 +956,18 @@ pub fn allocateDeclIndexes(self: *Plan9, decl_index: Module.Decl.Index) !void {
771 _ = self;956 _ = self;
772 _ = decl_index;957 _ = decl_index;
773}958}
959/// Must be called only after a successful call to `updateDecl`.
960pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl: *const Module.Decl) !void {
961 _ = self;
962 _ = mod;
963 _ = decl;
964}
965
774pub fn getDeclVAddr(966pub fn getDeclVAddr(
775 self: *Plan9,967 self: *Plan9,
776 decl_index: Module.Decl.Index,968 decl_index: Module.Decl.Index,
777 reloc_info: link.File.RelocInfo,969 reloc_info: link.File.RelocInfo,
778) !u64 {970) !u64 {
779 _ = reloc_info;
780 const mod = self.base.options.module.?;971 const mod = self.base.options.module.?;
781 const decl = mod.declPtr(decl_index);972 const decl = mod.declPtr(decl_index);
782 if (decl.ty.zigTypeTag() == .Fn) {973 if (decl.ty.zigTypeTag() == .Fn) {
...@@ -790,7 +981,6 @@ pub fn getDeclVAddr(...@@ -790,7 +981,6 @@ pub fn getDeclVAddr(
790 start += entry.value_ptr.code.len;981 start += entry.value_ptr.code.len;
791 }982 }
792 }983 }
793 unreachable;
794 } else {984 } else {
795 var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;985 var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
796 var it = self.data_decl_table.iterator();986 var it = self.data_decl_table.iterator();
...@@ -798,6 +988,16 @@ pub fn getDeclVAddr(...@@ -798,6 +988,16 @@ pub fn getDeclVAddr(
798 if (decl_index == kv.key_ptr.*) return start;988 if (decl_index == kv.key_ptr.*) return start;
799 start += kv.value_ptr.len;989 start += kv.value_ptr.len;
800 }990 }
801 unreachable;
802 }991 }
992 // the parent_atom_index in this case is just the decl_index of the parent
993 const gop = try self.relocs.getOrPut(self.base.allocator, @intToEnum(Module.Decl.Index, reloc_info.parent_atom_index));
994 if (!gop.found_existing) {
995 gop.value_ptr.* = .{};
996 }
997 try gop.value_ptr.append(self.base.allocator, .{
998 .target = decl_index,
999 .offset = reloc_info.offset,
1000 .addend = reloc_info.addend,
1001 });
1002 return undefined;
803}1003}
test/cases/plan9/exit.zig created+5
...@@ -0,0 +1,5 @@
1pub fn main() void {}
2
3// run
4// target=x86_64-plan9
5//
test/cases/plan9/hello_world_with_updates.0.zig created+28
...@@ -0,0 +1,28 @@
1pub fn main() void {
2 const str = "Hello World!\n";
3 asm volatile (
4 \\push $0
5 \\push %%r10
6 \\push %%r11
7 \\push $1
8 \\push $0
9 \\syscall
10 \\pop %%r11
11 \\pop %%r11
12 \\pop %%r11
13 \\pop %%r11
14 \\pop %%r11
15 :
16 // pwrite
17 : [syscall_number] "{rbp}" (51),
18 [hey] "{r11}" (@ptrToInt(str)),
19 [strlen] "{r10}" (str.len),
20 : "rcx", "rbp", "r11", "memory"
21 );
22}
23
24// run
25// target=x86_64-plan9
26//
27// Hello World
28//
test/cases/plan9/hello_world_with_updates.1.zig created+10
...@@ -0,0 +1,10 @@
1const std = @import("std");
2pub fn main() void {
3 const str = "Hello World!\n";
4 _ = std.os.plan9.pwrite(1, str, str.len, 0);
5}
6
7// run
8//
9// Hello World
10//