authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-16 21:57:33-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-06-16 21:57:33-07:00
log78c8cb4225c3c3d429764151ad703a4bfa67d75a
tree8352b61ff54c133f78e4b8d1e05714561ee105bb
parent0f5aff34414bcb024443540fe905039f3783803a
parent5343a2f566a5c235055f4aebb4ab9c10773e57f0
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16003 from g-w1/plan9-lazy-syms

Plan9: lots of fixes

11 files changed, 609 insertions(+), 131 deletions(-)

lib/std/os.zig+1
...@@ -67,6 +67,7 @@ else if (builtin.link_libc or is_windows)...@@ -67,6 +67,7 @@ else if (builtin.link_libc or is_windows)
67 std.c67 std.c
68else switch (builtin.os.tag) {68else switch (builtin.os.tag) {
69 .linux => linux,69 .linux => linux,
70 .plan9 => plan9,
70 .wasi => wasi,71 .wasi => wasi,
71 .uefi => uefi,72 .uefi => uefi,
72 else => struct {},73 else => struct {},
lib/std/os/plan9.zig+88-1
...@@ -5,6 +5,78 @@ pub const syscall_bits = switch (builtin.cpu.arch) {...@@ -5,6 +5,78 @@ pub const syscall_bits = switch (builtin.cpu.arch) {
5 .x86_64 => @import("plan9/x86_64.zig"),5 .x86_64 => @import("plan9/x86_64.zig"),
6 else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),6 else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
7};7};
8pub const E = @import("plan9/errno.zig").E;
9/// Get the errno from a syscall return value, or 0 for no error.
10pub fn getErrno(r: usize) E {
11 const signed_r = @bitCast(isize, r);
12 const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
13 return @intToEnum(E, int);
14}
15pub const SIG = struct {
16 /// hangup
17 pub const HUP = 1;
18 /// interrupt
19 pub const INT = 2;
20 /// quit
21 pub const QUIT = 3;
22 /// illegal instruction (not reset when caught)
23 pub const ILL = 4;
24 /// used by abort
25 pub const ABRT = 5;
26 /// floating point exception
27 pub const FPE = 6;
28 /// kill (cannot be caught or ignored)
29 pub const KILL = 7;
30 /// segmentation violation
31 pub const SEGV = 8;
32 /// write on a pipe with no one to read it
33 pub const PIPE = 9;
34 /// alarm clock
35 pub const ALRM = 10;
36 /// software termination signal from kill
37 pub const TERM = 11;
38 /// user defined signal 1
39 pub const USR1 = 12;
40 /// user defined signal 2
41 pub const USR2 = 13;
42 /// bus error
43 pub const BUS = 14;
44 // The following symbols must be defined, but the signals needn't be supported
45 /// child process terminated or stopped
46 pub const CHLD = 15;
47 /// continue if stopped
48 pub const CONT = 16;
49 /// stop
50 pub const STOP = 17;
51 /// interactive stop
52 pub const TSTP = 18;
53 /// read from ctl tty by member of background
54 pub const TTIN = 19;
55 /// write to ctl tty by member of background
56 pub const TTOU = 20;
57};
58pub const sigset_t = c_long;
59pub const empty_sigset = 0;
60pub const siginfo_t = c_long; // TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible.
61pub const Sigaction = extern struct {
62 pub const handler_fn = *const fn (c_int) callconv(.C) void;
63 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
64
65 handler: extern union {
66 handler: ?handler_fn,
67 sigaction: ?sigaction_fn,
68 },
69 mask: sigset_t,
70 flags: c_int,
71};
72// TODO implement sigaction
73// right now it is just a shim to allow using start.zig code
74pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
75 _ = oact;
76 _ = act;
77 _ = sig;
78 return 0;
79}
8pub const SYS = enum(usize) {80pub const SYS = enum(usize) {
9 SYSR1 = 0,81 SYSR1 = 0,
10 _ERRSTR = 1,82 _ERRSTR = 1,
...@@ -64,6 +136,10 @@ pub fn pwrite(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize {...@@ -64,6 +136,10 @@ pub fn pwrite(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize {
64 return syscall_bits.syscall4(.PWRITE, fd, @ptrToInt(buf), count, offset);136 return syscall_bits.syscall4(.PWRITE, fd, @ptrToInt(buf), count, offset);
65}137}
66138
139pub fn pread(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize {
140 return syscall_bits.syscall4(.PREAD, fd, @ptrToInt(buf), count, offset);
141}
142
67pub fn open(path: [*:0]const u8, omode: OpenMode) usize {143pub fn open(path: [*:0]const u8, omode: OpenMode) usize {
68 return syscall_bits.syscall2(.OPEN, @ptrToInt(path), @enumToInt(omode));144 return syscall_bits.syscall2(.OPEN, @ptrToInt(path), @enumToInt(omode));
69}145}
...@@ -72,8 +148,19 @@ pub fn create(path: [*:0]const u8, omode: OpenMode, perms: usize) usize {...@@ -72,8 +148,19 @@ pub fn create(path: [*:0]const u8, omode: OpenMode, perms: usize) usize {
72 return syscall_bits.syscall3(.CREATE, @ptrToInt(path), @enumToInt(omode), perms);148 return syscall_bits.syscall3(.CREATE, @ptrToInt(path), @enumToInt(omode), perms);
73}149}
74150
75pub fn exits(status: ?[*:0]const u8) void {151pub fn exit(status: u8) noreturn {
152 if (status == 0) {
153 exits(null);
154 } else {
155 // TODO plan9 does not have exit codes. You either exit with 0 or a string
156 const arr: [1:0]u8 = .{status};
157 exits(&arr);
158 }
159}
160
161pub fn exits(status: ?[*:0]const u8) noreturn {
76 _ = syscall_bits.syscall1(.EXITS, if (status) |s| @ptrToInt(s) else 0);162 _ = syscall_bits.syscall1(.EXITS, if (status) |s| @ptrToInt(s) else 0);
163 unreachable;
77}164}
78165
79pub fn close(fd: usize) usize {166pub fn close(fd: usize) usize {
lib/std/os/plan9/errno.zig created+76
...@@ -0,0 +1,76 @@
1//! Ported from /sys/include/ape/errno.h
2pub const E = enum(u16) {
3 SUCCESS = 0,
4 DOM = 1000,
5 RANGE = 1001,
6 PLAN9 = 1002,
7
8 @"2BIG" = 1,
9 ACCES = 2,
10 AGAIN = 3,
11 // WOULDBLOCK = 3, // TODO errno.h has 2 names for 3
12 BADF = 4,
13 BUSY = 5,
14 CHILD = 6,
15 DEADLK = 7,
16 EXIST = 8,
17 FAULT = 9,
18 FBIG = 10,
19 INTR = 11,
20 INVAL = 12,
21 IO = 13,
22 ISDIR = 14,
23 MFILE = 15,
24 MLINK = 16,
25 NAMETOOLONG = 17,
26 NFILE = 18,
27 NODEV = 19,
28 NOENT = 20,
29 NOEXEC = 21,
30 NOLCK = 22,
31 NOMEM = 23,
32 NOSPC = 24,
33 NOSYS = 25,
34 NOTDIR = 26,
35 NOTEMPTY = 27,
36 NOTTY = 28,
37 NXIO = 29,
38 PERM = 30,
39 PIPE = 31,
40 ROFS = 32,
41 SPIPE = 33,
42 SRCH = 34,
43 XDEV = 35,
44
45 // bsd networking software
46 NOTSOCK = 36,
47 PROTONOSUPPORT = 37,
48 // PROTOTYPE = 37, // TODO errno.h has two names for 37
49 CONNREFUSED = 38,
50 AFNOSUPPORT = 39,
51 NOBUFS = 40,
52 OPNOTSUPP = 41,
53 ADDRINUSE = 42,
54 DESTADDRREQ = 43,
55 MSGSIZE = 44,
56 NOPROTOOPT = 45,
57 SOCKTNOSUPPORT = 46,
58 PFNOSUPPORT = 47,
59 ADDRNOTAVAIL = 48,
60 NETDOWN = 49,
61 NETUNREACH = 50,
62 NETRESET = 51,
63 CONNABORTED = 52,
64 ISCONN = 53,
65 NOTCONN = 54,
66 SHUTDOWN = 55,
67 TOOMANYREFS = 56,
68 TIMEDOUT = 57,
69 HOSTDOWN = 58,
70 HOSTUNREACH = 59,
71 GREG = 60,
72
73 // These added in 1003.1b-1993
74 CANCELED = 61,
75 INPROGRESS = 62,
76};
lib/std/os/plan9/x86_64.zig+1-1
...@@ -66,7 +66,7 @@ pub fn syscall4(sys: plan9.SYS, arg0: usize, arg1: usize, arg2: usize, arg3: usi...@@ -66,7 +66,7 @@ pub fn syscall4(sys: plan9.SYS, arg0: usize, arg1: usize, arg2: usize, arg3: usi
66 : [arg0] "{r8}" (arg0),66 : [arg0] "{r8}" (arg0),
67 [arg1] "{r9}" (arg1),67 [arg1] "{r9}" (arg1),
68 [arg2] "{r10}" (arg2),68 [arg2] "{r10}" (arg2),
69 [arg2] "{r11}" (arg3),69 [arg3] "{r11}" (arg3),
70 [syscall_number] "{rbp}" (@enumToInt(sys)),70 [syscall_number] "{rbp}" (@enumToInt(sys)),
71 : "rcx", "rax", "rbp", "r11", "memory"71 : "rcx", "rax", "rbp", "r11", "memory"
72 );72 );
lib/std/start.zig-1
...@@ -18,7 +18,6 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";...@@ -18,7 +18,6 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start";
18// Until then, we have simplified logic here for self-hosted. TODO remove this once18// Until then, we have simplified logic here for self-hosted. TODO remove this once
19// self-hosted is capable enough to handle all of the real start.zig logic.19// self-hosted is capable enough to handle all of the real start.zig logic.
20pub const simplified_logic =20pub const simplified_logic =
21 (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .plan9) or
22 builtin.zig_backend == .stage2_x86 or21 builtin.zig_backend == .stage2_x86 or
23 builtin.zig_backend == .stage2_aarch64 or22 builtin.zig_backend == .stage2_aarch64 or
24 builtin.zig_backend == .stage2_arm or23 builtin.zig_backend == .stage2_arm or
src/arch/aarch64/CodeGen.zig+3-8
...@@ -4335,14 +4335,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4335,14 +4335,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4335 },4335 },
4336 });4336 });
4337 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {4337 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4338 const decl_block_index = try p9.seeDecl(func.owner_decl);4338 const atom_index = try p9.seeDecl(func.owner_decl);
4339 const decl_block = p9.getDeclBlock(decl_block_index);4339 const atom = p9.getAtom(atom_index);
4340 const ptr_bits = self.target.ptrBitWidth();4340 try self.genSetReg(Type.usize, .x30, .{ .memory = atom.getOffsetTableAddress(p9) });
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 });
4346 } else unreachable;4341 } else unreachable;
43474342
4348 _ = try self.addInst(.{4343 _ = try self.addInst(.{
src/arch/x86_64/CodeGen.zig+30-8
...@@ -130,6 +130,8 @@ const Owner = union(enum) {...@@ -130,6 +130,8 @@ const Owner = union(enum) {
130 } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| {130 } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| {
131 const atom = try coff_file.getOrCreateAtomForDecl(decl_index);131 const atom = try coff_file.getOrCreateAtomForDecl(decl_index);
132 return coff_file.getAtom(atom).getSymbolIndex().?;132 return coff_file.getAtom(atom).getSymbolIndex().?;
133 } else if (ctx.bin_file.cast(link.File.Plan9)) |p9_file| {
134 return p9_file.seeDecl(decl_index);
133 } else unreachable;135 } else unreachable;
134 },136 },
135 .lazy_sym => |lazy_sym| {137 .lazy_sym => |lazy_sym| {
...@@ -141,6 +143,9 @@ const Owner = union(enum) {...@@ -141,6 +143,9 @@ const Owner = union(enum) {
141 const atom = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|143 const atom = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
142 return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});144 return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
143 return coff_file.getAtom(atom).getSymbolIndex().?;145 return coff_file.getAtom(atom).getSymbolIndex().?;
146 } else if (ctx.bin_file.cast(link.File.Plan9)) |p9_file| {
147 return p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
148 return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
144 } else unreachable;149 } else unreachable;
145 },150 },
146 }151 }
...@@ -8115,16 +8120,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -8115,16 +8120,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
8115 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });8120 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
8116 try self.asmRegister(.{ ._, .call }, .rax);8121 try self.asmRegister(.{ ._, .call }, .rax);
8117 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {8122 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
8118 const decl_block_index = try p9.seeDecl(owner_decl);8123 const atom_index = try p9.seeDecl(owner_decl);
8119 const decl_block = p9.getDeclBlock(decl_block_index);8124 const atom = p9.getAtom(atom_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;
8125 try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{8125 try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
8126 .base = .{ .reg = .ds },8126 .base = .{ .reg = .ds },
8127 .disp = @intCast(i32, fn_got_addr),8127 .disp = @intCast(i32, atom.getOffsetTableAddress(p9)),
8128 }));8128 }));
8129 } else unreachable;8129 } else unreachable;
8130 } else if (func_value.getExternFunc(mod)) |extern_func| {8130 } else if (func_value.getExternFunc(mod)) |extern_func| {
...@@ -10092,6 +10092,28 @@ fn genLazySymbolRef(...@@ -10092,6 +10092,28 @@ fn genLazySymbolRef(
10092 ),10092 ),
10093 else => unreachable,10093 else => unreachable,
10094 }10094 }
10095 } else if (self.bin_file.cast(link.File.Plan9)) |p9_file| {
10096 const atom_index = p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
10097 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
10098 var atom = p9_file.getAtom(atom_index);
10099 _ = atom.getOrCreateOffsetTableEntry(p9_file);
10100 const got_addr = atom.getOffsetTableAddress(p9_file);
10101 const got_mem =
10102 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) });
10103 switch (tag) {
10104 .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), got_mem),
10105 .call => try self.asmMemory(.{ ._, .call }, got_mem),
10106 else => unreachable,
10107 }
10108 switch (tag) {
10109 .lea, .call => {},
10110 .mov => try self.asmRegisterMemory(
10111 .{ ._, tag },
10112 reg.to64(),
10113 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),
10114 ),
10115 else => unreachable,
10116 }
10095 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {10117 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
10096 const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|10118 const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
10097 return self.fail("{s} creating lazy symbol", .{@errorName(err)});10119 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
src/arch/x86_64/Emit.zig+8
...@@ -118,6 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -118,6 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void {
118 .pcrel = true,118 .pcrel = true,
119 .length = 2,119 .length = 2,
120 });120 });
121 } else if (emit.bin_file.cast(link.File.Plan9)) |p9_file| {
122 const atom_index = symbol.atom_index;
123 try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct
124 .target = symbol.sym_index, // we set sym_index to just be the atom index
125 .offset = @intCast(u32, end_offset - 4),
126 .addend = 0,
127 .pcrel = true,
128 });
121 } else return emit.fail("TODO implement linker reloc for {s}", .{129 } else return emit.fail("TODO implement linker reloc for {s}", .{
122 @tagName(emit.bin_file.tag),130 @tagName(emit.bin_file.tag),
123 }),131 }),
src/codegen.zig+6-10
...@@ -852,10 +852,9 @@ fn genDeclRef(...@@ -852,10 +852,9 @@ fn genDeclRef(
852 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;852 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
853 return GenResult.mcv(.{ .load_got = sym_index });853 return GenResult.mcv(.{ .load_got = sym_index });
854 } else if (bin_file.cast(link.File.Plan9)) |p9| {854 } else if (bin_file.cast(link.File.Plan9)) |p9| {
855 const decl_block_index = try p9.seeDecl(decl_index);855 const atom_index = try p9.seeDecl(decl_index);
856 const decl_block = p9.getDeclBlock(decl_block_index);856 const atom = p9.getAtom(atom_index);
857 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;857 return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(p9) });
858 return GenResult.mcv(.{ .memory = got_addr });
859 } else {858 } else {
860 return GenResult.fail(bin_file.allocator, src_loc, "TODO genDeclRef for target {}", .{target});859 return GenResult.fail(bin_file.allocator, src_loc, "TODO genDeclRef for target {}", .{target});
861 }860 }
...@@ -880,12 +879,9 @@ fn genUnnamedConst(...@@ -880,12 +879,9 @@ fn genUnnamedConst(
880 return GenResult.mcv(.{ .load_direct = local_sym_index });879 return GenResult.mcv(.{ .load_direct = local_sym_index });
881 } else if (bin_file.cast(link.File.Coff)) |_| {880 } else if (bin_file.cast(link.File.Coff)) |_| {
882 return GenResult.mcv(.{ .load_direct = local_sym_index });881 return GenResult.mcv(.{ .load_direct = local_sym_index });
883 } else if (bin_file.cast(link.File.Plan9)) |p9| {882 } else if (bin_file.cast(link.File.Plan9)) |_| {
884 const ptr_bits = target.ptrBitWidth();883 const atom_index = local_sym_index; // plan9 returns the atom_index
885 const ptr_bytes: u64 = @divExact(ptr_bits, 8);884 return GenResult.mcv(.{ .load_direct = atom_index });
886 const got_index = local_sym_index; // the plan9 backend returns the got_index
887 const got_addr = p9.bases.data + got_index * ptr_bytes;
888 return GenResult.mcv(.{ .memory = got_addr });
889 } else {885 } else {
890 return GenResult.fail(bin_file.allocator, src_loc, "TODO genUnnamedConst for target {}", .{target});886 return GenResult.fail(bin_file.allocator, src_loc, "TODO genUnnamedConst for target {}", .{target});
891 }887 }
src/link/Elf.zig+1
...@@ -341,6 +341,7 @@ pub fn deinit(self: *Elf) void {...@@ -341,6 +341,7 @@ pub fn deinit(self: *Elf) void {
341341
342 self.atoms.deinit(gpa);342 self.atoms.deinit(gpa);
343 self.atom_by_index_table.deinit(gpa);343 self.atom_by_index_table.deinit(gpa);
344 self.lazy_syms.deinit(gpa);
344345
345 {346 {
346 var it = self.unnamed_const_atoms.valueIterator();347 var it = self.unnamed_const_atoms.valueIterator();
src/link/Plan9.zig+395-102
...@@ -79,7 +79,9 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []u8) = .{},...@@ -79,7 +79,9 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []u8) = .{},
79/// with `Decl` `main`, and lives as long as that `Decl`.79/// with `Decl` `main`, and lives as long as that `Decl`.
80unnamed_const_atoms: UnnamedConstTable = .{},80unnamed_const_atoms: UnnamedConstTable = .{},
8181
82relocs: std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Reloc)) = .{},82lazy_syms: LazySymbolTable = .{},
83
84relocs: std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Reloc)) = .{},
83hdr: aout.ExecHdr = undefined,85hdr: aout.ExecHdr = undefined,
8486
85// relocs: std.87// relocs: std.
...@@ -94,13 +96,14 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},...@@ -94,13 +96,14 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},
9496
95syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},97syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},
9698
97decl_blocks: std.ArrayListUnmanaged(DeclBlock) = .{},99atoms: std.ArrayListUnmanaged(Atom) = .{},
98decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},100decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
99101
100const Reloc = struct {102const Reloc = struct {
101 target: Module.Decl.Index,103 target: Atom.Index,
102 offset: u64,104 offset: u64,
103 addend: u32,105 addend: u32,
106 pcrel: bool = false,
104};107};
105108
106const Bases = struct {109const Bases = struct {
...@@ -109,11 +112,28 @@ const Bases = struct {...@@ -109,11 +112,28 @@ const Bases = struct {
109 data: u64,112 data: u64,
110};113};
111114
112const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 }));115const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
116
117const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
118
119const LazySymbolMetadata = struct {
120 const State = enum { unused, pending_flush, flushed };
121 text_atom: Atom.Index = undefined,
122 rodata_atom: Atom.Index = undefined,
123 text_state: State = .unused,
124 rodata_state: State = .unused,
125
126 fn numberOfAtoms(self: LazySymbolMetadata) u32 {
127 var n: u32 = 0;
128 if (self.text_state != .unused) n += 1;
129 if (self.rodata_state != .unused) n += 1;
130 return n;
131 }
132};
113133
114pub const PtrWidth = enum { p32, p64 };134pub const PtrWidth = enum { p32, p64 };
115135
116pub const DeclBlock = struct {136pub const Atom = struct {
117 type: aout.Sym.Type,137 type: aout.Sym.Type,
118 /// offset in the text or data sects138 /// offset in the text or data sects
119 offset: ?u64,139 offset: ?u64,
...@@ -121,12 +141,60 @@ pub const DeclBlock = struct {...@@ -121,12 +141,60 @@ pub const DeclBlock = struct {
121 sym_index: ?usize,141 sym_index: ?usize,
122 /// offset into got142 /// offset into got
123 got_index: ?usize,143 got_index: ?usize,
144 /// We include the code here to be use in relocs
145 /// In the case of unnamed_const_atoms and lazy_syms, this atom owns the code.
146 /// But, in the case of function and data decls, they own the code and this field
147 /// is just a pointer for convience.
148 code: CodePtr,
149
150 const CodePtr = struct {
151 code_ptr: ?[*]u8,
152 other: union {
153 code_len: usize,
154 decl_index: Module.Decl.Index,
155 },
156 fn getCode(self: CodePtr, plan9: *const Plan9) []u8 {
157 const mod = plan9.base.options.module.?;
158 return if (self.code_ptr) |p| p[0..self.other.code_len] else blk: {
159 const decl_index = self.other.decl_index;
160 const decl = mod.declPtr(decl_index);
161 if (decl.ty.zigTypeTag(mod) == .Fn) {
162 const table = plan9.fn_decl_table.get(decl.getFileScope(mod)).?.functions;
163 const output = table.get(decl_index).?;
164 break :blk output.code;
165 } else {
166 break :blk plan9.data_decl_table.get(decl_index).?;
167 }
168 };
169 }
170 fn getOwnedCode(self: CodePtr) ?[]u8 {
171 return if (self.code_ptr) |p| p[0..self.other.code_len] else null;
172 }
173 };
124174
125 pub const Index = u32;175 pub const Index = u32;
176
177 pub fn getOrCreateOffsetTableEntry(self: *Atom, plan9: *Plan9) usize {
178 if (self.got_index == null) self.got_index = plan9.allocateGotIndex();
179 return self.got_index.?;
180 }
181
182 pub fn getOrCreateSymbolTableEntry(self: *Atom, plan9: *Plan9) !usize {
183 if (self.sym_index == null) self.sym_index = try plan9.allocateSymbolIndex();
184 return self.sym_index.?;
185 }
186
187 // asserts that self.got_index != null
188 pub fn getOffsetTableAddress(self: Atom, plan9: *Plan9) u64 {
189 const ptr_bytes = @divExact(plan9.base.options.target.ptrBitWidth(), 8);
190 const got_addr = plan9.bases.data;
191 const got_index = self.got_index.?;
192 return got_addr + got_index * ptr_bytes;
193 }
126};194};
127195
128const DeclMetadata = struct {196const DeclMetadata = struct {
129 index: DeclBlock.Index,197 index: Atom.Index,
130 exports: std.ArrayListUnmanaged(usize) = .{},198 exports: std.ArrayListUnmanaged(usize) = .{},
131199
132 fn getExport(m: DeclMetadata, p9: *const Plan9, name: []const u8) ?usize {200 fn getExport(m: DeclMetadata, p9: *const Plan9, name: []const u8) ?usize {
...@@ -286,7 +354,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air:...@@ -286,7 +354,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air:
286 const decl = mod.declPtr(decl_index);354 const decl = mod.declPtr(decl_index);
287 self.freeUnnamedConsts(decl_index);355 self.freeUnnamedConsts(decl_index);
288356
289 _ = try self.seeDecl(decl_index);357 const atom_idx = try self.seeDecl(decl_index);
290358
291 var code_buffer = std.ArrayList(u8).init(self.base.allocator);359 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
292 defer code_buffer.deinit();360 defer code_buffer.deinit();
...@@ -320,6 +388,10 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air:...@@ -320,6 +388,10 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air:
320 return;388 return;
321 },389 },
322 };390 };
391 self.getAtomPtr(atom_idx).code = .{
392 .code_ptr = null,
393 .other = .{ .decl_index = decl_index },
394 };
323 const out: FnDeclOutput = .{395 const out: FnDeclOutput = .{
324 .code = code,396 .code = code,
325 .lineinfo = try dbg_line_buffer.toOwnedSlice(),397 .lineinfo = try dbg_line_buffer.toOwnedSlice(),
...@@ -351,12 +423,13 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I...@@ -351,12 +423,13 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I
351 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index });423 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index });
352424
353 const sym_index = try self.allocateSymbolIndex();425 const sym_index = try self.allocateSymbolIndex();
354426 const new_atom_idx = try self.createAtom();
355 const info: DeclBlock = .{427 var info: Atom = .{
356 .type = .d,428 .type = .d,
357 .offset = null,429 .offset = null,
358 .sym_index = sym_index,430 .sym_index = sym_index,
359 .got_index = self.allocateGotIndex(),431 .got_index = self.allocateGotIndex(),
432 .code = undefined, // filled in later
360 };433 };
361 const sym: aout.Sym = .{434 const sym: aout.Sym = .{
362 .value = undefined,435 .value = undefined,
...@@ -368,7 +441,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I...@@ -368,7 +441,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I
368 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .{441 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .{
369 .none = {},442 .none = {},
370 }, .{443 }, .{
371 .parent_atom_index = @enumToInt(decl_index),444 .parent_atom_index = new_atom_idx,
372 });445 });
373 const code = switch (res) {446 const code = switch (res) {
374 .ok => code_buffer.items,447 .ok => code_buffer.items,
...@@ -382,9 +455,12 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I...@@ -382,9 +455,12 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I
382 // duped_code is freed when the unnamed const is freed455 // duped_code is freed when the unnamed const is freed
383 var duped_code = try self.base.allocator.dupe(u8, code);456 var duped_code = try self.base.allocator.dupe(u8, code);
384 errdefer self.base.allocator.free(duped_code);457 errdefer self.base.allocator.free(duped_code);
385 try unnamed_consts.append(self.base.allocator, .{ .info = info, .code = duped_code });458 const new_atom = self.getAtomPtr(new_atom_idx);
386 // we return the got_index to codegen so that it can reference to the place of the data in the got459 new_atom.* = info;
387 return @intCast(u32, info.got_index.?);460 new_atom.code = .{ .code_ptr = duped_code.ptr, .other = .{ .code_len = duped_code.len } };
461 try unnamed_consts.append(self.base.allocator, new_atom_idx);
462 // we return the new_atom_idx to codegen
463 return new_atom_idx;
388}464}
389465
390pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void {466pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void {
...@@ -399,7 +475,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo...@@ -399,7 +475,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo
399 }475 }
400 }476 }
401477
402 _ = try self.seeDecl(decl_index);478 const atom_idx = try self.seeDecl(decl_index);
403479
404 var code_buffer = std.ArrayList(u8).init(self.base.allocator);480 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
405 defer code_buffer.deinit();481 defer code_buffer.deinit();
...@@ -409,7 +485,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo...@@ -409,7 +485,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo
409 .ty = decl.ty,485 .ty = decl.ty,
410 .val = decl_val,486 .val = decl_val,
411 }, &code_buffer, .{ .none = {} }, .{487 }, &code_buffer, .{ .none = {} }, .{
412 .parent_atom_index = @enumToInt(decl_index),488 .parent_atom_index = @intCast(Atom.Index, atom_idx),
413 });489 });
414 const code = switch (res) {490 const code = switch (res) {
415 .ok => code_buffer.items,491 .ok => code_buffer.items,
...@@ -421,6 +497,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo...@@ -421,6 +497,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo
421 };497 };
422 try self.data_decl_table.ensureUnusedCapacity(self.base.allocator, 1);498 try self.data_decl_table.ensureUnusedCapacity(self.base.allocator, 1);
423 const duped_code = try self.base.allocator.dupe(u8, code);499 const duped_code = try self.base.allocator.dupe(u8, code);
500 self.getAtomPtr(self.decls.get(decl_index).?.index).code = .{ .code_ptr = null, .other = .{ .decl_index = decl_index } };
424 if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| {501 if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| {
425 self.base.allocator.free(old_entry.value);502 self.base.allocator.free(old_entry.value);
426 }503 }
...@@ -433,22 +510,22 @@ fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void {...@@ -433,22 +510,22 @@ fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void {
433 const is_fn = (decl.ty.zigTypeTag(mod) == .Fn);510 const is_fn = (decl.ty.zigTypeTag(mod) == .Fn);
434 const sym_t: aout.Sym.Type = if (is_fn) .t else .d;511 const sym_t: aout.Sym.Type = if (is_fn) .t else .d;
435512
436 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);513 const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
437 // write the internal linker metadata514 // write the internal linker metadata
438 decl_block.type = sym_t;515 atom.type = sym_t;
439 // write the symbol516 // write the symbol
440 // we already have the got index517 // we already have the got index
441 const sym: aout.Sym = .{518 const sym: aout.Sym = .{
442 .value = undefined, // the value of stuff gets filled in in flushModule519 .value = undefined, // the value of stuff gets filled in in flushModule
443 .type = decl_block.type,520 .type = atom.type,
444 .name = try self.base.allocator.dupe(u8, mod.intern_pool.stringToSlice(decl.name)),521 .name = try self.base.allocator.dupe(u8, mod.intern_pool.stringToSlice(decl.name)),
445 };522 };
446523
447 if (decl_block.sym_index) |s| {524 if (atom.sym_index) |s| {
448 self.syms.items[s] = sym;525 self.syms.items[s] = sym;
449 } else {526 } else {
450 const s = try self.allocateSymbolIndex();527 const s = try self.allocateSymbolIndex();
451 decl_block.sym_index = s;528 atom.sym_index = s;
452 self.syms.items[s] = sym;529 self.syms.items[s] = sym;
453 }530 }
454}531}
...@@ -461,6 +538,7 @@ fn allocateSymbolIndex(self: *Plan9) !usize {...@@ -461,6 +538,7 @@ fn allocateSymbolIndex(self: *Plan9) !usize {
461 return self.syms.items.len - 1;538 return self.syms.items.len - 1;
462 }539 }
463}540}
541
464fn allocateGotIndex(self: *Plan9) usize {542fn allocateGotIndex(self: *Plan9) usize {
465 if (self.got_index_free_list.popOrNull()) |i| {543 if (self.got_index_free_list.popOrNull()) |i| {
466 return i;544 return i;
...@@ -495,7 +573,7 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void {...@@ -495,7 +573,7 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void {
495 }573 }
496}574}
497575
498// counts decls and unnamed consts576// counts decls, unnamed consts, and lazy syms
499fn atomCount(self: *Plan9) usize {577fn atomCount(self: *Plan9) usize {
500 var fn_decl_count: usize = 0;578 var fn_decl_count: usize = 0;
501 var itf_files = self.fn_decl_table.iterator();579 var itf_files = self.fn_decl_table.iterator();
...@@ -510,7 +588,12 @@ fn atomCount(self: *Plan9) usize {...@@ -510,7 +588,12 @@ fn atomCount(self: *Plan9) usize {
510 while (it_unc.next()) |unnamed_consts| {588 while (it_unc.next()) |unnamed_consts| {
511 unnamed_const_count += unnamed_consts.value_ptr.items.len;589 unnamed_const_count += unnamed_consts.value_ptr.items.len;
512 }590 }
513 return data_decl_count + fn_decl_count + unnamed_const_count;591 var lazy_atom_count: usize = 0;
592 var it_lazy = self.lazy_syms.iterator();
593 while (it_lazy.next()) |kv| {
594 lazy_atom_count += kv.value_ptr.numberOfAtoms();
595 }
596 return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count;
514}597}
515598
516pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {599pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
...@@ -532,7 +615,32 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -532,7 +615,32 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
532615
533 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;616 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
534617
535 assert(self.got_len == self.atomCount() + self.got_index_free_list.items.len);618 // finish up the lazy syms
619 if (self.lazy_syms.getPtr(.none)) |metadata| {
620 // Most lazy symbols can be updated on first use, but
621 // anyerror needs to wait for everything to be flushed.
622 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
623 File.LazySymbol.initDecl(.code, null, mod),
624 metadata.text_atom,
625 ) catch |err| return switch (err) {
626 error.CodegenFail => error.FlushFailure,
627 else => |e| e,
628 };
629 if (metadata.rodata_state != .unused) self.updateLazySymbolAtom(
630 File.LazySymbol.initDecl(.const_data, null, mod),
631 metadata.rodata_atom,
632 ) catch |err| return switch (err) {
633 error.CodegenFail => error.FlushFailure,
634 else => |e| e,
635 };
636 }
637 for (self.lazy_syms.values()) |*metadata| {
638 if (metadata.text_state != .unused) metadata.text_state = .flushed;
639 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
640 }
641 // make sure the got table is good
642 const atom_count = self.atomCount();
643 assert(self.got_len == atom_count + self.got_index_free_list.items.len);
536 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;644 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
537 var got_table = try self.base.allocator.alloc(u8, got_size);645 var got_table = try self.base.allocator.alloc(u8, got_size);
538 defer self.base.allocator.free(got_table);646 defer self.base.allocator.free(got_table);
...@@ -562,7 +670,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -562,7 +670,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
562 var it = fentry.value_ptr.functions.iterator();670 var it = fentry.value_ptr.functions.iterator();
563 while (it.next()) |entry| {671 while (it.next()) |entry| {
564 const decl_index = entry.key_ptr.*;672 const decl_index = entry.key_ptr.*;
565 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);673 const decl = mod.declPtr(decl_index);
674 const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
566 const out = entry.value_ptr.*;675 const out = entry.value_ptr.*;
567 {676 {
568 // connect the previous decl to the next677 // connect the previous decl to the next
...@@ -580,14 +689,14 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -580,14 +689,14 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
580 iovecs_i += 1;689 iovecs_i += 1;
581 const off = self.getAddr(text_i, .t);690 const off = self.getAddr(text_i, .t);
582 text_i += out.code.len;691 text_i += out.code.len;
583 decl_block.offset = off;692 atom.offset = off;
693 log.debug("write text decl {*} ({}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ decl, decl.name.fmt(&mod.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off });
584 if (!self.sixtyfour_bit) {694 if (!self.sixtyfour_bit) {
585 mem.writeIntNative(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off));695 mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
586 mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
587 } else {696 } else {
588 mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());697 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
589 }698 }
590 self.syms.items[decl_block.sym_index.?].value = off;699 self.syms.items[atom.sym_index.?].value = off;
591 if (mod.decl_exports.get(decl_index)) |exports| {700 if (mod.decl_exports.get(decl_index)) |exports| {
592 try self.addDeclExports(mod, decl_index, exports.items);701 try self.addDeclExports(mod, decl_index, exports.items);
593 }702 }
...@@ -597,9 +706,30 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -597,9 +706,30 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
597 // just a nop to make it even, the plan9 linker does this706 // just a nop to make it even, the plan9 linker does this
598 try linecountinfo.append(129);707 try linecountinfo.append(129);
599 }708 }
600 // etext symbol
601 self.syms.items[2].value = self.getAddr(text_i, .t);
602 }709 }
710 // the text lazy symbols
711 {
712 var it = self.lazy_syms.iterator();
713 while (it.next()) |kv| {
714 const meta = kv.value_ptr;
715 const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue;
716 const code = text_atom.code.getOwnedCode().?;
717 foff += code.len;
718 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
719 iovecs_i += 1;
720 const off = self.getAddr(text_i, .t);
721 text_i += code.len;
722 text_atom.offset = off;
723 if (!self.sixtyfour_bit) {
724 mem.writeInt(u32, got_table[text_atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
725 } else {
726 mem.writeInt(u64, got_table[text_atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
727 }
728 self.syms.items[text_atom.sym_index.?].value = off;
729 }
730 }
731 // etext symbol
732 self.syms.items[2].value = self.getAddr(text_i, .t);
603 // global offset table is in data733 // global offset table is in data
604 iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len };734 iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len };
605 iovecs_i += 1;735 iovecs_i += 1;
...@@ -609,7 +739,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -609,7 +739,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
609 var it = self.data_decl_table.iterator();739 var it = self.data_decl_table.iterator();
610 while (it.next()) |entry| {740 while (it.next()) |entry| {
611 const decl_index = entry.key_ptr.*;741 const decl_index = entry.key_ptr.*;
612 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);742 const atom = self.getAtomPtr(self.decls.get(decl_index).?.index);
613 const code = entry.value_ptr.*;743 const code = entry.value_ptr.*;
614744
615 foff += code.len;745 foff += code.len;
...@@ -617,13 +747,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -617,13 +747,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
617 iovecs_i += 1;747 iovecs_i += 1;
618 const off = self.getAddr(data_i, .d);748 const off = self.getAddr(data_i, .d);
619 data_i += code.len;749 data_i += code.len;
620 decl_block.offset = off;750 atom.offset = off;
621 if (!self.sixtyfour_bit) {751 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());752 mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
623 } else {753 } else {
624 mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());754 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
625 }755 }
626 self.syms.items[decl_block.sym_index.?].value = off;756 self.syms.items[atom.sym_index.?].value = off;
627 if (mod.decl_exports.get(decl_index)) |exports| {757 if (mod.decl_exports.get(decl_index)) |exports| {
628 try self.addDeclExports(mod, decl_index, exports.items);758 try self.addDeclExports(mod, decl_index, exports.items);
629 }759 }
...@@ -631,28 +761,48 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -631,28 +761,48 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
631 // write the unnamed constants after the other data decls761 // write the unnamed constants after the other data decls
632 var it_unc = self.unnamed_const_atoms.iterator();762 var it_unc = self.unnamed_const_atoms.iterator();
633 while (it_unc.next()) |unnamed_consts| {763 while (it_unc.next()) |unnamed_consts| {
634 for (unnamed_consts.value_ptr.items) |*unnamed_const| {764 for (unnamed_consts.value_ptr.items) |atom_idx| {
635 const code = unnamed_const.code;765 const atom = self.getAtomPtr(atom_idx);
636 log.debug("write unnamed const: ({s})", .{self.syms.items[unnamed_const.info.sym_index.?].name});766 const code = atom.code.getOwnedCode().?; // unnamed consts must own their code
767 log.debug("write unnamed const: ({s})", .{self.syms.items[atom.sym_index.?].name});
637 foff += code.len;768 foff += code.len;
638 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };769 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
639 iovecs_i += 1;770 iovecs_i += 1;
640 const off = self.getAddr(data_i, .d);771 const off = self.getAddr(data_i, .d);
641 data_i += code.len;772 data_i += code.len;
642 unnamed_const.info.offset = off;773 atom.offset = off;
643 if (!self.sixtyfour_bit) {774 if (!self.sixtyfour_bit) {
644 mem.writeInt(u32, got_table[unnamed_const.info.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());775 mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
645 } else {776 } else {
646 mem.writeInt(u64, got_table[unnamed_const.info.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());777 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
647 }778 }
648 self.syms.items[unnamed_const.info.sym_index.?].value = off;779 self.syms.items[atom.sym_index.?].value = off;
780 }
781 }
782 // the lazy data symbols
783 var it_lazy = self.lazy_syms.iterator();
784 while (it_lazy.next()) |kv| {
785 const meta = kv.value_ptr;
786 const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue;
787 const code = data_atom.code.getOwnedCode().?; // lazy symbols must own their code
788 foff += code.len;
789 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
790 iovecs_i += 1;
791 const off = self.getAddr(data_i, .d);
792 data_i += code.len;
793 data_atom.offset = off;
794 if (!self.sixtyfour_bit) {
795 mem.writeInt(u32, got_table[data_atom.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
796 } else {
797 mem.writeInt(u64, got_table[data_atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
649 }798 }
799 self.syms.items[data_atom.sym_index.?].value = off;
650 }800 }
651 // edata symbol801 // edata symbol
652 self.syms.items[0].value = self.getAddr(data_i, .b);802 self.syms.items[0].value = self.getAddr(data_i, .b);
803 // end
804 self.syms.items[1].value = self.getAddr(data_i, .b);
653 }805 }
654 // edata
655 self.syms.items[1].value = self.getAddr(0x0, .b);
656 var sym_buf = std.ArrayList(u8).init(self.base.allocator);806 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
657 try self.writeSyms(&sym_buf);807 try self.writeSyms(&sym_buf);
658 const syms = try sym_buf.toOwnedSlice();808 const syms = try sym_buf.toOwnedSlice();
...@@ -682,33 +832,31 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -682,33 +832,31 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
682 {832 {
683 var it = self.relocs.iterator();833 var it = self.relocs.iterator();
684 while (it.next()) |kv| {834 while (it.next()) |kv| {
685 const source_decl_index = kv.key_ptr.*;835 const source_atom_index = kv.key_ptr.*;
686 const source_decl = mod.declPtr(source_decl_index);836 const source_atom = self.getAtom(source_atom_index);
837 const source_atom_symbol = self.syms.items[source_atom.sym_index.?];
687 for (kv.value_ptr.items) |reloc| {838 for (kv.value_ptr.items) |reloc| {
688 const target_decl_index = reloc.target;839 const target_atom_index = reloc.target;
689 const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index);840 const target_atom = self.getAtomPtr(target_atom_index);
690 const target_decl_offset = target_decl_block.offset.?;841 const target_symbol = self.syms.items[target_atom.sym_index.?];
842 const target_offset = target_atom.offset.?;
691843
692 const offset = reloc.offset;844 const offset = reloc.offset;
693 const addend = reloc.addend;845 const addend = reloc.addend;
694846
695 const code = blk: {847 const code = source_atom.code.getCode(self);
696 const is_fn = source_decl.ty.zigTypeTag(mod) == .Fn;
697 if (is_fn) {
698 const table = self.fn_decl_table.get(source_decl.getFileScope(mod)).?.functions;
699 const output = table.get(source_decl_index).?;
700 break :blk output.code;
701 } else {
702 const code = self.data_decl_table.get(source_decl_index).?;
703 break :blk code;
704 }
705 };
706848
707 if (!self.sixtyfour_bit) {849 if (reloc.pcrel) {
708 mem.writeInt(u32, code[@intCast(usize, offset)..][0..4], @intCast(u32, target_decl_offset + addend), self.base.options.target.cpu.arch.endian());850 const disp = @intCast(i32, target_offset) - @intCast(i32, source_atom.offset.?) - 4 - @intCast(i32, offset);
851 mem.writeInt(i32, code[@intCast(usize, offset)..][0..4], @intCast(i32, disp), self.base.options.target.cpu.arch.endian());
709 } else {852 } else {
710 mem.writeInt(u64, code[@intCast(usize, offset)..][0..8], target_decl_offset + addend, self.base.options.target.cpu.arch.endian());853 if (!self.sixtyfour_bit) {
854 mem.writeInt(u32, code[@intCast(usize, offset)..][0..4], @intCast(u32, target_offset + addend), self.base.options.target.cpu.arch.endian());
855 } else {
856 mem.writeInt(u64, code[@intCast(usize, offset)..][0..8], target_offset + addend, self.base.options.target.cpu.arch.endian());
857 }
711 }858 }
859 log.debug("relocating the address of '{s}' + {d} into '{s}' + {d} (({s}[{d}] = 0x{x} + 0x{x})", .{ target_symbol.name, addend, source_atom_symbol.name, offset, source_atom_symbol.name, offset, target_offset, addend });
712 }860 }
713 }861 }
714 }862 }
...@@ -722,7 +870,7 @@ fn addDeclExports(...@@ -722,7 +870,7 @@ fn addDeclExports(
722 exports: []const *Module.Export,870 exports: []const *Module.Export,
723) !void {871) !void {
724 const metadata = self.decls.getPtr(decl_index).?;872 const metadata = self.decls.getPtr(decl_index).?;
725 const decl_block = self.getDeclBlock(metadata.index);873 const atom = self.getAtom(metadata.index);
726874
727 for (exports) |exp| {875 for (exports) |exp| {
728 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);876 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
...@@ -739,8 +887,8 @@ fn addDeclExports(...@@ -739,8 +887,8 @@ fn addDeclExports(
739 }887 }
740 }888 }
741 const sym = .{889 const sym = .{
742 .value = decl_block.offset.?,890 .value = atom.offset.?,
743 .type = decl_block.type.toGlobal(),891 .type = atom.type.toGlobal(),
744 .name = try self.base.allocator.dupe(u8, exp_name),892 .name = try self.base.allocator.dupe(u8, exp_name),
745 };893 };
746894
...@@ -780,12 +928,12 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {...@@ -780,12 +928,12 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {
780 }928 }
781 if (self.decls.fetchRemove(decl_index)) |const_kv| {929 if (self.decls.fetchRemove(decl_index)) |const_kv| {
782 var kv = const_kv;930 var kv = const_kv;
783 const decl_block = self.getDeclBlock(kv.value.index);931 const atom = self.getAtom(kv.value.index);
784 if (decl_block.got_index) |i| {932 if (atom.got_index) |i| {
785 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length933 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length
786 self.got_index_free_list.append(self.base.allocator, i) catch {};934 self.got_index_free_list.append(self.base.allocator, i) catch {};
787 }935 }
788 if (decl_block.sym_index) |i| {936 if (atom.sym_index) |i| {
789 self.syms_index_free_list.append(self.base.allocator, i) catch {};937 self.syms_index_free_list.append(self.base.allocator, i) catch {};
790 self.syms.items[i] = aout.Sym.undefined_symbol;938 self.syms.items[i] = aout.Sym.undefined_symbol;
791 }939 }
...@@ -793,40 +941,42 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {...@@ -793,40 +941,42 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {
793 }941 }
794 self.freeUnnamedConsts(decl_index);942 self.freeUnnamedConsts(decl_index);
795 {943 {
796 const relocs = self.relocs.getPtr(decl_index) orelse return;944 const atom_index = self.decls.get(decl_index).?.index;
945 const relocs = self.relocs.getPtr(atom_index) orelse return;
797 relocs.clearAndFree(self.base.allocator);946 relocs.clearAndFree(self.base.allocator);
798 assert(self.relocs.remove(decl_index));947 assert(self.relocs.remove(atom_index));
799 }948 }
800}949}
801fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void {950fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void {
802 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;951 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
803 for (unnamed_consts.items) |c| {952 for (unnamed_consts.items) |atom_idx| {
804 self.base.allocator.free(self.syms.items[c.info.sym_index.?].name);953 const atom = self.getAtom(atom_idx);
805 self.base.allocator.free(c.code);954 self.base.allocator.free(self.syms.items[atom.sym_index.?].name);
806 self.syms.items[c.info.sym_index.?] = aout.Sym.undefined_symbol;955 self.syms.items[atom.sym_index.?] = aout.Sym.undefined_symbol;
807 self.syms_index_free_list.append(self.base.allocator, c.info.sym_index.?) catch {};956 self.syms_index_free_list.append(self.base.allocator, atom.sym_index.?) catch {};
808 }957 }
809 unnamed_consts.clearAndFree(self.base.allocator);958 unnamed_consts.clearAndFree(self.base.allocator);
810}959}
811960
812fn createDeclBlock(self: *Plan9) !DeclBlock.Index {961fn createAtom(self: *Plan9) !Atom.Index {
813 const gpa = self.base.allocator;962 const gpa = self.base.allocator;
814 const index = @intCast(DeclBlock.Index, self.decl_blocks.items.len);963 const index = @intCast(Atom.Index, self.atoms.items.len);
815 const decl_block = try self.decl_blocks.addOne(gpa);964 const atom = try self.atoms.addOne(gpa);
816 decl_block.* = .{965 atom.* = .{
817 .type = .t,966 .type = .t,
818 .offset = null,967 .offset = null,
819 .sym_index = null,968 .sym_index = null,
820 .got_index = null,969 .got_index = null,
970 .code = undefined,
821 };971 };
822 return index;972 return index;
823}973}
824974
825pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !DeclBlock.Index {975pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !Atom.Index {
826 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);976 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
827 if (!gop.found_existing) {977 if (!gop.found_existing) {
828 const index = try self.createDeclBlock();978 const index = try self.createAtom();
829 self.getDeclBlockPtr(index).got_index = self.allocateGotIndex();979 self.getAtomPtr(index).got_index = self.allocateGotIndex();
830 gop.value_ptr.* = .{980 gop.value_ptr.* = .{
831 .index = index,981 .index = index,
832 .exports = .{},982 .exports = .{},
...@@ -846,6 +996,88 @@ pub fn updateDeclExports(...@@ -846,6 +996,88 @@ pub fn updateDeclExports(
846 _ = module;996 _ = module;
847 _ = exports;997 _ = exports;
848}998}
999
1000pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {
1001 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(self.base.options.module.?));
1002 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
1003
1004 if (!gop.found_existing) gop.value_ptr.* = .{};
1005
1006 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
1007 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
1008 .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state },
1009 };
1010 switch (metadata.state.*) {
1011 .unused => metadata.atom.* = try self.createAtom(),
1012 .pending_flush => return metadata.atom.*,
1013 .flushed => {},
1014 }
1015 metadata.state.* = .pending_flush;
1016 const atom = metadata.atom.*;
1017 _ = try self.getAtomPtr(atom).getOrCreateSymbolTableEntry(self);
1018 _ = self.getAtomPtr(atom).getOrCreateOffsetTableEntry(self);
1019 // anyerror needs to be deferred until flushModule
1020 if (sym.getDecl(self.base.options.module.?) != .none) {
1021 try self.updateLazySymbolAtom(sym, atom);
1022 }
1023 return atom;
1024}
1025
1026fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Index) !void {
1027 const gpa = self.base.allocator;
1028 const mod = self.base.options.module.?;
1029
1030 var required_alignment: u32 = undefined;
1031 var code_buffer = std.ArrayList(u8).init(gpa);
1032 defer code_buffer.deinit();
1033
1034 // create the symbol for the name
1035 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1036 @tagName(sym.kind),
1037 sym.ty.fmt(mod),
1038 });
1039
1040 const symbol: aout.Sym = .{
1041 .value = undefined,
1042 .type = if (sym.kind == .code) .t else .d,
1043 .name = name,
1044 };
1045 self.syms.items[self.getAtomPtr(atom_index).sym_index.?] = symbol;
1046
1047 // generate the code
1048 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
1049 mod.declPtr(owner_decl).srcLoc(mod)
1050 else
1051 Module.SrcLoc{
1052 .file_scope = undefined,
1053 .parent_decl_node = undefined,
1054 .lazy = .unneeded,
1055 };
1056 const res = try codegen.generateLazySymbol(
1057 &self.base,
1058 src,
1059 sym,
1060 &required_alignment,
1061 &code_buffer,
1062 .none,
1063 .{ .parent_atom_index = @intCast(Atom.Index, atom_index) },
1064 );
1065 const code = switch (res) {
1066 .ok => code_buffer.items,
1067 .fail => |em| {
1068 log.err("{s}", .{em.msg});
1069 return error.CodegenFail;
1070 },
1071 };
1072 // duped_code is freed when the atom is freed
1073 var duped_code = try self.base.allocator.dupe(u8, code);
1074 errdefer self.base.allocator.free(duped_code);
1075 self.getAtomPtr(atom_index).code = .{
1076 .code_ptr = duped_code.ptr,
1077 .other = .{ .code_len = duped_code.len },
1078 };
1079}
1080
849pub fn deinit(self: *Plan9) void {1081pub fn deinit(self: *Plan9) void {
850 const gpa = self.base.allocator;1082 const gpa = self.base.allocator;
851 {1083 {
...@@ -861,6 +1093,14 @@ pub fn deinit(self: *Plan9) void {...@@ -861,6 +1093,14 @@ pub fn deinit(self: *Plan9) void {
861 self.freeUnnamedConsts(kv.key_ptr.*);1093 self.freeUnnamedConsts(kv.key_ptr.*);
862 }1094 }
863 self.unnamed_const_atoms.deinit(gpa);1095 self.unnamed_const_atoms.deinit(gpa);
1096 var it_lzc = self.lazy_syms.iterator();
1097 while (it_lzc.next()) |kv| {
1098 if (kv.value_ptr.text_state != .unused)
1099 gpa.free(self.syms.items[self.getAtom(kv.value_ptr.text_atom).sym_index.?].name);
1100 if (kv.value_ptr.rodata_state != .unused)
1101 gpa.free(self.syms.items[self.getAtom(kv.value_ptr.rodata_atom).sym_index.?].name);
1102 }
1103 self.lazy_syms.deinit(gpa);
864 var itf_files = self.fn_decl_table.iterator();1104 var itf_files = self.fn_decl_table.iterator();
865 while (itf_files.next()) |ent| {1105 while (itf_files.next()) |ent| {
866 // get the submap1106 // get the submap
...@@ -883,7 +1123,12 @@ pub fn deinit(self: *Plan9) void {...@@ -883,7 +1123,12 @@ pub fn deinit(self: *Plan9) void {
883 self.syms_index_free_list.deinit(gpa);1123 self.syms_index_free_list.deinit(gpa);
884 self.file_segments.deinit(gpa);1124 self.file_segments.deinit(gpa);
885 self.path_arena.deinit();1125 self.path_arena.deinit();
886 self.decl_blocks.deinit(gpa);1126 for (self.atoms.items) |a| {
1127 if (a.code.getOwnedCode()) |c| {
1128 gpa.free(c);
1129 }
1130 }
1131 self.atoms.deinit(gpa);
8871132
888 {1133 {
889 var it = self.decls.iterator();1134 var it = self.decls.iterator();
...@@ -911,7 +1156,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -911,7 +1156,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
9111156
912 self.bases = defaultBaseAddrs(options.target.cpu.arch);1157 self.bases = defaultBaseAddrs(options.target.cpu.arch);
9131158
914 // first 3 symbols in our table are edata, end, etext1159 // first 4 symbols in our table are edata, end, etext, and got
915 try self.syms.appendSlice(self.base.allocator, &.{1160 try self.syms.appendSlice(self.base.allocator, &.{
916 .{1161 .{
917 .value = 0xcafebabe,1162 .value = 0xcafebabe,
...@@ -928,13 +1173,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -928,13 +1173,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
928 .type = .T,1173 .type = .T,
929 .name = "etext",1174 .name = "etext",
930 },1175 },
1176 // we include the global offset table to make it easier for debugging
1177 .{
1178 .value = self.getAddr(0, .d), // the global offset table starts at 0
1179 .type = .d,
1180 .name = "__GOT",
1181 },
931 });1182 });
9321183
933 return self;1184 return self;
934}1185}
9351186
936pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void {1187pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void {
937 log.debug("write sym{{name: {s}, value: {x}}}", .{ sym.name, sym.value });1188 // log.debug("write sym{{name: {s}, value: {x}}}", .{ sym.name, sym.value });
938 if (sym.type == .bad) return; // we don't want to write free'd symbols1189 if (sym.type == .bad) return; // we don't want to write free'd symbols
939 if (!self.sixtyfour_bit) {1190 if (!self.sixtyfour_bit) {
940 try w.writeIntBig(u32, @intCast(u32, sym.value));1191 try w.writeIntBig(u32, @intCast(u32, sym.value));
...@@ -950,6 +1201,11 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -950,6 +1201,11 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
950 const mod = self.base.options.module.?;1201 const mod = self.base.options.module.?;
951 const ip = &mod.intern_pool;1202 const ip = &mod.intern_pool;
952 const writer = buf.writer();1203 const writer = buf.writer();
1204 // write the first four symbols (edata, etext, end, __GOT)
1205 try self.writeSym(writer, self.syms.items[0]);
1206 try self.writeSym(writer, self.syms.items[1]);
1207 try self.writeSym(writer, self.syms.items[2]);
1208 try self.writeSym(writer, self.syms.items[3]);
953 // write the f symbols1209 // write the f symbols
954 {1210 {
955 var it = self.file_segments.iterator();1211 var it = self.file_segments.iterator();
...@@ -968,8 +1224,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -968,8 +1224,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
968 while (it.next()) |entry| {1224 while (it.next()) |entry| {
969 const decl_index = entry.key_ptr.*;1225 const decl_index = entry.key_ptr.*;
970 const decl_metadata = self.decls.get(decl_index).?;1226 const decl_metadata = self.decls.get(decl_index).?;
971 const decl_block = self.getDeclBlock(decl_metadata.index);1227 const atom = self.getAtom(decl_metadata.index);
972 const sym = self.syms.items[decl_block.sym_index.?];1228 const sym = self.syms.items[atom.sym_index.?];
973 try self.writeSym(writer, sym);1229 try self.writeSym(writer, sym);
974 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {1230 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
975 for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| {1231 for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| {
...@@ -978,6 +1234,27 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -978,6 +1234,27 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
978 }1234 }
979 }1235 }
980 }1236 }
1237 // the data lazy symbols
1238 {
1239 var it = self.lazy_syms.iterator();
1240 while (it.next()) |kv| {
1241 const meta = kv.value_ptr;
1242 const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue;
1243 const sym = self.syms.items[data_atom.sym_index.?];
1244 try self.writeSym(writer, sym);
1245 }
1246 }
1247 // unnamed consts
1248 {
1249 var it = self.unnamed_const_atoms.iterator();
1250 while (it.next()) |kv| {
1251 const consts = kv.value_ptr;
1252 for (consts.items) |atom_index| {
1253 const sym = self.syms.items[self.getAtom(atom_index).sym_index.?];
1254 try self.writeSym(writer, sym);
1255 }
1256 }
1257 }
981 // text symbols are the hardest:1258 // text symbols are the hardest:
982 // the file of a text symbol is the .z symbol before it1259 // the file of a text symbol is the .z symbol before it
983 // so we have to write everything in the right order1260 // so we have to write everything in the right order
...@@ -994,8 +1271,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -994,8 +1271,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
994 while (submap_it.next()) |entry| {1271 while (submap_it.next()) |entry| {
995 const decl_index = entry.key_ptr.*;1272 const decl_index = entry.key_ptr.*;
996 const decl_metadata = self.decls.get(decl_index).?;1273 const decl_metadata = self.decls.get(decl_index).?;
997 const decl_block = self.getDeclBlock(decl_metadata.index);1274 const atom = self.getAtom(decl_metadata.index);
998 const sym = self.syms.items[decl_block.sym_index.?];1275 const sym = self.syms.items[atom.sym_index.?];
999 try self.writeSym(writer, sym);1276 try self.writeSym(writer, sym);
1000 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {1277 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
1001 for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| {1278 for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| {
...@@ -1007,6 +1284,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -1007,6 +1284,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
1007 }1284 }
1008 }1285 }
1009 }1286 }
1287 // the text lazy symbols
1288 {
1289 var it = self.lazy_syms.iterator();
1290 while (it.next()) |kv| {
1291 const meta = kv.value_ptr;
1292 const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue;
1293 const sym = self.syms.items[text_atom.sym_index.?];
1294 try self.writeSym(writer, sym);
1295 }
1296 }
1010 }1297 }
1011}1298}
10121299
...@@ -1024,6 +1311,7 @@ pub fn getDeclVAddr(...@@ -1024,6 +1311,7 @@ pub fn getDeclVAddr(
1024) !u64 {1311) !u64 {
1025 const mod = self.base.options.module.?;1312 const mod = self.base.options.module.?;
1026 const decl = mod.declPtr(decl_index);1313 const decl = mod.declPtr(decl_index);
1314 // we might already know the vaddr
1027 if (decl.ty.zigTypeTag(mod) == .Fn) {1315 if (decl.ty.zigTypeTag(mod) == .Fn) {
1028 var start = self.bases.text;1316 var start = self.bases.text;
1029 var it_file = self.fn_decl_table.iterator();1317 var it_file = self.fn_decl_table.iterator();
...@@ -1043,23 +1331,28 @@ pub fn getDeclVAddr(...@@ -1043,23 +1331,28 @@ pub fn getDeclVAddr(
1043 start += kv.value_ptr.len;1331 start += kv.value_ptr.len;
1044 }1332 }
1045 }1333 }
1334 const atom_index = try self.seeDecl(decl_index);
1046 // the parent_atom_index in this case is just the decl_index of the parent1335 // the parent_atom_index in this case is just the decl_index of the parent
1047 const gop = try self.relocs.getOrPut(self.base.allocator, @intToEnum(Module.Decl.Index, reloc_info.parent_atom_index));1336 try self.addReloc(reloc_info.parent_atom_index, .{
1048 if (!gop.found_existing) {1337 .target = atom_index,
1049 gop.value_ptr.* = .{};
1050 }
1051 try gop.value_ptr.append(self.base.allocator, .{
1052 .target = decl_index,
1053 .offset = reloc_info.offset,1338 .offset = reloc_info.offset,
1054 .addend = reloc_info.addend,1339 .addend = reloc_info.addend,
1055 });1340 });
1056 return 0;1341 return 0xcafebabe;
1342}
1343
1344pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void {
1345 const gop = try self.relocs.getOrPut(self.base.allocator, parent_index);
1346 if (!gop.found_existing) {
1347 gop.value_ptr.* = .{};
1348 }
1349 try gop.value_ptr.append(self.base.allocator, reloc);
1057}1350}
10581351
1059pub fn getDeclBlock(self: *const Plan9, index: DeclBlock.Index) DeclBlock {1352pub fn getAtom(self: *const Plan9, index: Atom.Index) Atom {
1060 return self.decl_blocks.items[index];1353 return self.atoms.items[index];
1061}1354}
10621355
1063fn getDeclBlockPtr(self: *Plan9, index: DeclBlock.Index) *DeclBlock {1356fn getAtomPtr(self: *Plan9, index: Atom.Index) *Atom {
1064 return &self.decl_blocks.items[index];1357 return &self.atoms.items[index];
1065}1358}