authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2023-06-10 19:27:54-04:00
committergravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2023-06-16 08:34:30-04:00
log9e8c7b104e6bfa2821b79ee05c5583776749f136
tree99744503fdd24de3765f0f6b0f7899b10df11390
parent5d9e8f27d0dc131e0b4154c5f65376f2fb9f3500

Plan9: Add support for lazy symbols

This includes a renaming from DeclBlock to Atom.

4 files changed, 326 insertions(+), 73 deletions(-)

src/arch/aarch64/CodeGen.zig+3-8
......@@ -4335,14 +4335,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
43354335 },
43364336 });
43374337 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4338 const decl_block_index = try p9.seeDecl(func.owner_decl);
4339 const decl_block = p9.getDeclBlock(decl_block_index);
4340 const ptr_bits = self.target.ptrBitWidth();
4341 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4342 const got_addr = p9.bases.data;
4343 const got_index = decl_block.got_index.?;
4344 const fn_got_addr = got_addr + got_index * ptr_bytes;
4345 try self.genSetReg(Type.usize, .x30, .{ .memory = fn_got_addr });
4338 const atom_index = try p9.seeDecl(func.owner_decl);
4339 const atom = p9.getAtom(atom_index);
4340 try self.genSetReg(Type.usize, .x30, .{ .memory = atom.getOffsetTableAddress(p9) });
43464341 } else unreachable;
43474342
43484343 _ = try self.addInst(.{
src/arch/x86_64/CodeGen.zig+25-8
......@@ -8115,16 +8115,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
81158115 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
81168116 try self.asmRegister(.{ ._, .call }, .rax);
81178117 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
8118 const decl_block_index = try p9.seeDecl(owner_decl);
8119 const decl_block = p9.getDeclBlock(decl_block_index);
8120 const ptr_bits = self.target.ptrBitWidth();
8121 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
8122 const got_addr = p9.bases.data;
8123 const got_index = decl_block.got_index.?;
8124 const fn_got_addr = got_addr + got_index * ptr_bytes;
8118 const atom_index = try p9.seeDecl(owner_decl);
8119 const atom = p9.getAtom(atom_index);
81258120 try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
81268121 .base = .{ .reg = .ds },
8127 .disp = @intCast(i32, fn_got_addr),
8122 .disp = @intCast(i32, atom.getOffsetTableAddress(p9)),
81288123 }));
81298124 } else unreachable;
81308125 } else if (func_value.getExternFunc(mod)) |extern_func| {
......@@ -10092,6 +10087,28 @@ fn genLazySymbolRef(
1009210087 ),
1009310088 else => unreachable,
1009410089 }
10090 } else if (self.bin_file.cast(link.File.Plan9)) |p9_file| {
10091 const atom_index = p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
10092 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
10093 var atom = p9_file.getAtom(atom_index);
10094 _ = atom.getOrCreateOffsetTableEntry(p9_file);
10095 const got_addr = atom.getOffsetTableAddress(p9_file);
10096 const got_mem =
10097 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) });
10098 switch (tag) {
10099 .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), got_mem),
10100 .call => try self.asmMemory(.{ ._, .call }, got_mem),
10101 else => unreachable,
10102 }
10103 switch (tag) {
10104 .lea, .call => {},
10105 .mov => try self.asmRegisterMemory(
10106 .{ ._, tag },
10107 reg.to64(),
10108 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),
10109 ),
10110 else => unreachable,
10111 }
1009510112 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
1009610113 const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
1009710114 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
src/codegen.zig+3-4
......@@ -852,10 +852,9 @@ fn genDeclRef(
852852 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
853853 return GenResult.mcv(.{ .load_got = sym_index });
854854 } else if (bin_file.cast(link.File.Plan9)) |p9| {
855 const decl_block_index = try p9.seeDecl(decl_index);
856 const decl_block = p9.getDeclBlock(decl_block_index);
857 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
858 return GenResult.mcv(.{ .memory = got_addr });
855 const atom_index = try p9.seeDecl(decl_index);
856 const atom = p9.getAtom(atom_index);
857 return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(p9) });
859858 } else {
860859 return GenResult.fail(bin_file.allocator, src_loc, "TODO genDeclRef for target {}", .{target});
861860 }
src/link/Plan9.zig+295-53
......@@ -79,6 +79,8 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []u8) = .{},
7979/// with `Decl` `main`, and lives as long as that `Decl`.
8080unnamed_const_atoms: UnnamedConstTable = .{},
8181
82lazy_syms: LazySymbolTable = .{},
83
8284relocs: std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Reloc)) = .{},
8385hdr: aout.ExecHdr = undefined,
8486
......@@ -94,7 +96,7 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},
9496
9597syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},
9698
97decl_blocks: std.ArrayListUnmanaged(DeclBlock) = .{},
99atoms: std.ArrayListUnmanaged(Atom) = .{},
98100decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
99101
100102const Reloc = struct {
......@@ -109,11 +111,28 @@ const Bases = struct {
109111 data: u64,
110112};
111113
112const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 }));
114const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: Atom, code: []const u8 }));
115
116const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
117
118const LazySymbolMetadata = struct {
119 const State = enum { unused, pending_flush, flushed };
120 text_atom: Atom.Index = undefined,
121 rodata_atom: Atom.Index = undefined,
122 text_state: State = .unused,
123 rodata_state: State = .unused,
124
125 fn numberOfAtoms(self: LazySymbolMetadata) u32 {
126 var n: u32 = 0;
127 if (self.text_state != .unused) n += 1;
128 if (self.rodata_state != .unused) n += 1;
129 return n;
130 }
131};
113132
114133pub const PtrWidth = enum { p32, p64 };
115134
116pub const DeclBlock = struct {
135pub const Atom = struct {
117136 type: aout.Sym.Type,
118137 /// offset in the text or data sects
119138 offset: ?u64,
......@@ -121,12 +140,36 @@ pub const DeclBlock = struct {
121140 sym_index: ?usize,
122141 /// offset into got
123142 got_index: ?usize,
143 /// We can optionally store code with the atom
144 /// It is still owned by whatever created it
145 /// This can be useful so that we don't need
146 /// to setup so much infrastructure just to store code
147 /// for stuff like LazySymbols.
148 code: ?[]const u8 = null,
124149
125150 pub const Index = u32;
151
152 pub fn getOrCreateOffsetTableEntry(self: *Atom, plan9: *Plan9) usize {
153 if (self.got_index == null) self.got_index = plan9.allocateGotIndex();
154 return self.got_index.?;
155 }
156
157 pub fn getOrCreateSymbolTableEntry(self: *Atom, plan9: *Plan9) !usize {
158 if (self.sym_index == null) self.sym_index = try plan9.allocateSymbolIndex();
159 return self.sym_index.?;
160 }
161
162 // asserts that self.got_index != null
163 pub fn getOffsetTableAddress(self: Atom, plan9: *Plan9) u64 {
164 const ptr_bytes = @divExact(plan9.base.options.target.ptrBitWidth(), 8);
165 const got_addr = plan9.bases.data;
166 const got_index = self.got_index.?;
167 return got_addr + got_index * ptr_bytes;
168 }
126169};
127170
128171const DeclMetadata = struct {
129 index: DeclBlock.Index,
172 index: Atom.Index,
130173 exports: std.ArrayListUnmanaged(usize) = .{},
131174
132175 fn getExport(m: DeclMetadata, p9: *const Plan9, name: []const u8) ?usize {
......@@ -352,7 +395,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I
352395
353396 const sym_index = try self.allocateSymbolIndex();
354397
355 const info: DeclBlock = .{
398 const info: Atom = .{
356399 .type = .d,
357400 .offset = null,
358401 .sym_index = sym_index,
......@@ -433,22 +476,22 @@ fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void {
433476 const is_fn = (decl.ty.zigTypeTag(mod) == .Fn);
434477 const sym_t: aout.Sym.Type = if (is_fn) .t else .d;
435478
436 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);
479 const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
437480 // write the internal linker metadata
438 decl_block.type = sym_t;
481 atom.type = sym_t;
439482 // write the symbol
440483 // we already have the got index
441484 const sym: aout.Sym = .{
442485 .value = undefined, // the value of stuff gets filled in in flushModule
443 .type = decl_block.type,
486 .type = atom.type,
444487 .name = try self.base.allocator.dupe(u8, mod.intern_pool.stringToSlice(decl.name)),
445488 };
446489
447 if (decl_block.sym_index) |s| {
490 if (atom.sym_index) |s| {
448491 self.syms.items[s] = sym;
449492 } else {
450493 const s = try self.allocateSymbolIndex();
451 decl_block.sym_index = s;
494 atom.sym_index = s;
452495 self.syms.items[s] = sym;
453496 }
454497}
......@@ -461,6 +504,7 @@ fn allocateSymbolIndex(self: *Plan9) !usize {
461504 return self.syms.items.len - 1;
462505 }
463506}
507
464508fn allocateGotIndex(self: *Plan9) usize {
465509 if (self.got_index_free_list.popOrNull()) |i| {
466510 return i;
......@@ -495,7 +539,7 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void {
495539 }
496540}
497541
498// counts decls and unnamed consts
542// counts decls, unnamed consts, and lazy syms
499543fn atomCount(self: *Plan9) usize {
500544 var fn_decl_count: usize = 0;
501545 var itf_files = self.fn_decl_table.iterator();
......@@ -510,7 +554,12 @@ fn atomCount(self: *Plan9) usize {
510554 while (it_unc.next()) |unnamed_consts| {
511555 unnamed_const_count += unnamed_consts.value_ptr.items.len;
512556 }
513 return data_decl_count + fn_decl_count + unnamed_const_count;
557 var lazy_atom_count: usize = 0;
558 var it_lazy = self.lazy_syms.iterator();
559 while (it_lazy.next()) |kv| {
560 lazy_atom_count += kv.value_ptr.numberOfAtoms();
561 }
562 return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count;
514563}
515564
516565pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
......@@ -532,7 +581,32 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
532581
533582 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
534583
535 assert(self.got_len == self.atomCount() + self.got_index_free_list.items.len);
584 // finish up the lazy syms
585 if (self.lazy_syms.getPtr(.none)) |metadata| {
586 // Most lazy symbols can be updated on first use, but
587 // anyerror needs to wait for everything to be flushed.
588 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
589 File.LazySymbol.initDecl(.code, null, mod),
590 metadata.text_atom,
591 ) catch |err| return switch (err) {
592 error.CodegenFail => error.FlushFailure,
593 else => |e| e,
594 };
595 if (metadata.rodata_state != .unused) self.updateLazySymbolAtom(
596 File.LazySymbol.initDecl(.const_data, null, mod),
597 metadata.rodata_atom,
598 ) catch |err| return switch (err) {
599 error.CodegenFail => error.FlushFailure,
600 else => |e| e,
601 };
602 }
603 for (self.lazy_syms.values()) |*metadata| {
604 if (metadata.text_state != .unused) metadata.text_state = .flushed;
605 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
606 }
607 // make sure the got table is good
608 const atom_count = self.atomCount();
609 assert(self.got_len == atom_count + self.got_index_free_list.items.len);
536610 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
537611 var got_table = try self.base.allocator.alloc(u8, got_size);
538612 defer self.base.allocator.free(got_table);
......@@ -562,7 +636,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
562636 var it = fentry.value_ptr.functions.iterator();
563637 while (it.next()) |entry| {
564638 const decl_index = entry.key_ptr.*;
565 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);
639 const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
566640 const out = entry.value_ptr.*;
567641 {
568642 // connect the previous decl to the next
......@@ -580,14 +654,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
580654 iovecs_i += 1;
581655 const off = self.getAddr(text_i, .t);
582656 text_i += out.code.len;
583 decl_block.offset = off;
657 atom.offset = off;
584658 if (!self.sixtyfour_bit) {
585 mem.writeIntNative(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off));
586 mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
659 mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
587660 } else {
588 mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
661 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
589662 }
590 self.syms.items[decl_block.sym_index.?].value = off;
663 self.syms.items[atom.sym_index.?].value = off;
591664 if (mod.decl_exports.get(decl_index)) |exports| {
592665 try self.addDeclExports(mod, decl_index, exports.items);
593666 }
......@@ -597,9 +670,30 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
597670 // just a nop to make it even, the plan9 linker does this
598671 try linecountinfo.append(129);
599672 }
600 // etext symbol
601 self.syms.items[2].value = self.getAddr(text_i, .t);
602673 }
674 // the text lazy symbols
675 {
676 var it = self.lazy_syms.iterator();
677 while (it.next()) |kv| {
678 const meta = kv.value_ptr;
679 const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue;
680 const code = text_atom.code.?;
681 foff += code.len;
682 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
683 iovecs_i += 1;
684 const off = self.getAddr(text_i, .t);
685 text_i += code.len;
686 text_atom.offset = off;
687 if (!self.sixtyfour_bit) {
688 mem.writeInt(u32, got_table[text_atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
689 } else {
690 mem.writeInt(u64, got_table[text_atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
691 }
692 self.syms.items[text_atom.sym_index.?].value = off;
693 }
694 }
695 // etext symbol
696 self.syms.items[2].value = self.getAddr(text_i, .t);
603697 // global offset table is in data
604698 iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len };
605699 iovecs_i += 1;
......@@ -609,7 +703,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
609703 var it = self.data_decl_table.iterator();
610704 while (it.next()) |entry| {
611705 const decl_index = entry.key_ptr.*;
612 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);
706 const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
613707 const code = entry.value_ptr.*;
614708
615709 foff += code.len;
......@@ -617,13 +711,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
617711 iovecs_i += 1;
618712 const off = self.getAddr(data_i, .d);
619713 data_i += code.len;
620 decl_block.offset = off;
714 atom.offset = off;
621715 if (!self.sixtyfour_bit) {
622 mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
716 mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
623717 } else {
624 mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
718 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
625719 }
626 self.syms.items[decl_block.sym_index.?].value = off;
720 self.syms.items[atom.sym_index.?].value = off;
627721 if (mod.decl_exports.get(decl_index)) |exports| {
628722 try self.addDeclExports(mod, decl_index, exports.items);
629723 }
......@@ -648,11 +742,30 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
648742 self.syms.items[unnamed_const.info.sym_index.?].value = off;
649743 }
650744 }
745 // the lazy data symbols
746 var it_lazy = self.lazy_syms.iterator();
747 while (it_lazy.next()) |kv| {
748 const meta = kv.value_ptr;
749 const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue;
750 const code = data_atom.code.?;
751 foff += code.len;
752 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
753 iovecs_i += 1;
754 const off = self.getAddr(data_i, .d);
755 data_i += code.len;
756 data_atom.offset = off;
757 if (!self.sixtyfour_bit) {
758 mem.writeInt(u32, got_table[data_atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
759 } else {
760 mem.writeInt(u64, got_table[data_atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
761 }
762 self.syms.items[data_atom.sym_index.?].value = off;
763 }
651764 // edata symbol
652765 self.syms.items[0].value = self.getAddr(data_i, .b);
766 // end
767 self.syms.items[1].value = self.getAddr(data_i, .b);
653768 }
654 // edata
655 self.syms.items[1].value = self.getAddr(0x0, .b);
656769 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
657770 try self.writeSyms(&sym_buf);
658771 const syms = try sym_buf.toOwnedSlice();
......@@ -686,8 +799,10 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
686799 const source_decl = mod.declPtr(source_decl_index);
687800 for (kv.value_ptr.items) |reloc| {
688801 const target_decl_index = reloc.target;
689 const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index);
690 const target_decl_offset = target_decl_block.offset.?;
802 const target_decl = mod.declPtr(target_decl_index);
803 _ = target_decl;
804 const target_atom = self.getAtom(self.decls.get(target_decl_index).?.index);
805 const target_decl_offset = target_atom.offset.?;
691806
692807 const offset = reloc.offset;
693808 const addend = reloc.addend;
......@@ -722,7 +837,7 @@ fn addDeclExports(
722837 exports: []const *Module.Export,
723838) !void {
724839 const metadata = self.decls.getPtr(decl_index).?;
725 const decl_block = self.getDeclBlock(metadata.index);
840 const atom = self.getAtom(metadata.index);
726841
727842 for (exports) |exp| {
728843 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
......@@ -739,8 +854,8 @@ fn addDeclExports(
739854 }
740855 }
741856 const sym = .{
742 .value = decl_block.offset.?,
743 .type = decl_block.type.toGlobal(),
857 .value = atom.offset.?,
858 .type = atom.type.toGlobal(),
744859 .name = try self.base.allocator.dupe(u8, exp_name),
745860 };
746861
......@@ -780,12 +895,12 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {
780895 }
781896 if (self.decls.fetchRemove(decl_index)) |const_kv| {
782897 var kv = const_kv;
783 const decl_block = self.getDeclBlock(kv.value.index);
784 if (decl_block.got_index) |i| {
898 const atom = self.getAtom(kv.value.index);
899 if (atom.got_index) |i| {
785900 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length
786901 self.got_index_free_list.append(self.base.allocator, i) catch {};
787902 }
788 if (decl_block.sym_index) |i| {
903 if (atom.sym_index) |i| {
789904 self.syms_index_free_list.append(self.base.allocator, i) catch {};
790905 self.syms.items[i] = aout.Sym.undefined_symbol;
791906 }
......@@ -809,11 +924,11 @@ fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void {
809924 unnamed_consts.clearAndFree(self.base.allocator);
810925}
811926
812fn createDeclBlock(self: *Plan9) !DeclBlock.Index {
927fn createAtom(self: *Plan9) !Atom.Index {
813928 const gpa = self.base.allocator;
814 const index = @intCast(DeclBlock.Index, self.decl_blocks.items.len);
815 const decl_block = try self.decl_blocks.addOne(gpa);
816 decl_block.* = .{
929 const index = @intCast(Atom.Index, self.atoms.items.len);
930 const atom = try self.atoms.addOne(gpa);
931 atom.* = .{
817932 .type = .t,
818933 .offset = null,
819934 .sym_index = null,
......@@ -822,11 +937,11 @@ fn createDeclBlock(self: *Plan9) !DeclBlock.Index {
822937 return index;
823938}
824939
825pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !DeclBlock.Index {
940pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !Atom.Index {
826941 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
827942 if (!gop.found_existing) {
828 const index = try self.createDeclBlock();
829 self.getDeclBlockPtr(index).got_index = self.allocateGotIndex();
943 const index = try self.createAtom();
944 self.getAtomPtr(index).got_index = self.allocateGotIndex();
830945 gop.value_ptr.* = .{
831946 .index = index,
832947 .exports = .{},
......@@ -846,6 +961,89 @@ pub fn updateDeclExports(
846961 _ = module;
847962 _ = exports;
848963}
964
965pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {
966 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(self.base.options.module.?));
967 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
968
969 if (!gop.found_existing) gop.value_ptr.* = .{};
970
971 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
972 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
973 .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state },
974 };
975 switch (metadata.state.*) {
976 .unused => metadata.atom.* = try self.createAtom(),
977 .pending_flush => return metadata.atom.*,
978 .flushed => {},
979 }
980 metadata.state.* = .pending_flush;
981 const atom = metadata.atom.*;
982 _ = try self.getAtomPtr(atom).getOrCreateSymbolTableEntry(self);
983 _ = self.getAtomPtr(atom).getOrCreateOffsetTableEntry(self);
984 // anyerror needs to be deferred until flushModule
985 if (sym.getDecl(self.base.options.module.?) != .none) {
986 try self.updateLazySymbolAtom(sym, atom);
987 }
988 return atom;
989}
990
991fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Index) !void {
992 const gpa = self.base.allocator;
993 const mod = self.base.options.module.?;
994
995 const atom = self.getAtomPtr(atom_index);
996 const local_sym_index = atom.sym_index.?;
997
998 var required_alignment: u32 = undefined;
999 var code_buffer = std.ArrayList(u8).init(gpa);
1000 defer code_buffer.deinit();
1001
1002 // create the symbol for the name
1003 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1004 @tagName(sym.kind),
1005 sym.ty.fmt(mod),
1006 });
1007
1008 const symbol: aout.Sym = .{
1009 .value = undefined,
1010 .type = if (sym.kind == .code) .t else .d,
1011 .name = name,
1012 };
1013 self.syms.items[atom.sym_index.?] = symbol;
1014
1015 // generate the code
1016 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
1017 mod.declPtr(owner_decl).srcLoc(mod)
1018 else
1019 Module.SrcLoc{
1020 .file_scope = undefined,
1021 .parent_decl_node = undefined,
1022 .lazy = .unneeded,
1023 };
1024 const res = try codegen.generateLazySymbol(
1025 &self.base,
1026 src,
1027 sym,
1028 &required_alignment,
1029 &code_buffer,
1030 .none,
1031 .{ .parent_atom_index = @intCast(u32, local_sym_index) },
1032 );
1033 const code = switch (res) {
1034 .ok => code_buffer.items,
1035 .fail => |em| {
1036 log.err("{s}", .{em.msg});
1037 return error.CodegenFail;
1038 },
1039 };
1040 // duped_code is freed when the atom is freed
1041 var duped_code = try self.base.allocator.dupe(u8, code);
1042 errdefer self.base.allocator.free(duped_code);
1043
1044 atom.code = duped_code;
1045}
1046
8491047pub fn deinit(self: *Plan9) void {
8501048 const gpa = self.base.allocator;
8511049 {
......@@ -861,6 +1059,14 @@ pub fn deinit(self: *Plan9) void {
8611059 self.freeUnnamedConsts(kv.key_ptr.*);
8621060 }
8631061 self.unnamed_const_atoms.deinit(gpa);
1062 var it_lzc = self.lazy_syms.iterator();
1063 while (it_lzc.next()) |kv| {
1064 if (kv.value_ptr.text_state != .unused)
1065 gpa.free(self.syms.items[self.getAtom(kv.value_ptr.text_atom).sym_index.?].name);
1066 if (kv.value_ptr.rodata_state != .unused)
1067 gpa.free(self.syms.items[self.getAtom(kv.value_ptr.rodata_atom).sym_index.?].name);
1068 }
1069 self.lazy_syms.deinit(gpa);
8641070 var itf_files = self.fn_decl_table.iterator();
8651071 while (itf_files.next()) |ent| {
8661072 // get the submap
......@@ -883,7 +1089,12 @@ pub fn deinit(self: *Plan9) void {
8831089 self.syms_index_free_list.deinit(gpa);
8841090 self.file_segments.deinit(gpa);
8851091 self.path_arena.deinit();
886 self.decl_blocks.deinit(gpa);
1092 for (self.atoms.items) |atom| {
1093 if (atom.code) |c| {
1094 gpa.free(c);
1095 }
1096 }
1097 self.atoms.deinit(gpa);
8871098
8881099 {
8891100 var it = self.decls.iterator();
......@@ -911,7 +1122,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
9111122
9121123 self.bases = defaultBaseAddrs(options.target.cpu.arch);
9131124
914 // first 3 symbols in our table are edata, end, etext
1125 // first 4 symbols in our table are edata, end, etext, and got
9151126 try self.syms.appendSlice(self.base.allocator, &.{
9161127 .{
9171128 .value = 0xcafebabe,
......@@ -928,6 +1139,12 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
9281139 .type = .T,
9291140 .name = "etext",
9301141 },
1142 // we include the global offset table to make it easier for debugging
1143 .{
1144 .value = self.getAddr(0, .d), // the global offset table starts at 0
1145 .type = .d,
1146 .name = "__GOT",
1147 },
9311148 });
9321149
9331150 return self;
......@@ -950,6 +1167,11 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
9501167 const mod = self.base.options.module.?;
9511168 const ip = &mod.intern_pool;
9521169 const writer = buf.writer();
1170 // write the first four symbols (edata, etext, end, __GOT)
1171 try self.writeSym(writer, self.syms.items[0]);
1172 try self.writeSym(writer, self.syms.items[1]);
1173 try self.writeSym(writer, self.syms.items[2]);
1174 try self.writeSym(writer, self.syms.items[3]);
9531175 // write the f symbols
9541176 {
9551177 var it = self.file_segments.iterator();
......@@ -968,8 +1190,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
9681190 while (it.next()) |entry| {
9691191 const decl_index = entry.key_ptr.*;
9701192 const decl_metadata = self.decls.get(decl_index).?;
971 const decl_block = self.getDeclBlock(decl_metadata.index);
972 const sym = self.syms.items[decl_block.sym_index.?];
1193 const atom = self.getAtom(decl_metadata.index);
1194 const sym = self.syms.items[atom.sym_index.?];
9731195 try self.writeSym(writer, sym);
9741196 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
9751197 for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| {
......@@ -978,6 +1200,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
9781200 }
9791201 }
9801202 }
1203 // the data lazy symbols
1204 {
1205 var it = self.lazy_syms.iterator();
1206 while (it.next()) |kv| {
1207 const meta = kv.value_ptr;
1208 const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue;
1209 const sym = self.syms.items[data_atom.sym_index.?];
1210 try self.writeSym(writer, sym);
1211 }
1212 }
9811213 // text symbols are the hardest:
9821214 // the file of a text symbol is the .z symbol before it
9831215 // so we have to write everything in the right order
......@@ -994,8 +1226,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
9941226 while (submap_it.next()) |entry| {
9951227 const decl_index = entry.key_ptr.*;
9961228 const decl_metadata = self.decls.get(decl_index).?;
997 const decl_block = self.getDeclBlock(decl_metadata.index);
998 const sym = self.syms.items[decl_block.sym_index.?];
1229 const atom = self.getAtom(decl_metadata.index);
1230 const sym = self.syms.items[atom.sym_index.?];
9991231 try self.writeSym(writer, sym);
10001232 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
10011233 for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| {
......@@ -1007,6 +1239,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
10071239 }
10081240 }
10091241 }
1242 // the text lazy symbols
1243 {
1244 var it = self.lazy_syms.iterator();
1245 while (it.next()) |kv| {
1246 const meta = kv.value_ptr;
1247 const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue;
1248 const sym = self.syms.items[text_atom.sym_index.?];
1249 try self.writeSym(writer, sym);
1250 }
1251 }
10101252 }
10111253}
10121254
......@@ -1056,10 +1298,10 @@ pub fn getDeclVAddr(
10561298 return 0;
10571299}
10581300
1059pub fn getDeclBlock(self: *const Plan9, index: DeclBlock.Index) DeclBlock {
1060 return self.decl_blocks.items[index];
1301pub fn getAtom(self: *const Plan9, index: Atom.Index) Atom {
1302 return self.atoms.items[index];
10611303}
10621304
1063fn getDeclBlockPtr(self: *Plan9, index: DeclBlock.Index) *DeclBlock {
1064 return &self.decl_blocks.items[index];
1305fn getAtomPtr(self: *Plan9, index: Atom.Index) *Atom {
1306 return &self.atoms.items[index];
10651307}