| ... | @@ -22,7 +22,8 @@ const log = std.log.scoped(.link); | ... | @@ -22,7 +22,8 @@ const log = std.log.scoped(.link); |
| 22 | const assert = std.debug.assert; | 22 | const assert = std.debug.assert; |
| 23 | | 23 | |
| 24 | const FnDeclOutput = struct { | 24 | const FnDeclOutput = struct { |
| 25 | code: []const u8, | 25 | /// this code is modified when relocated so it is mutable |
| | 26 | code: []u8, |
| 26 | /// this might have to be modified in the linker, so thats why its mutable | 27 | /// this might have to be modified in the linker, so thats why its mutable |
| 27 | lineinfo: []u8, | 28 | lineinfo: []u8, |
| 28 | start_line: u32, | 29 | start_line: u32, |
| ... | @@ -61,7 +62,8 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged( | ... | @@ -61,7 +62,8 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged( |
| 61 | *Module.File, | 62 | *Module.File, |
| 62 | struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, FnDeclOutput) = .{} }, | 63 | struct { sym_index: u32, functions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, FnDeclOutput) = .{} }, |
| 63 | ) = .{}, | 64 | ) = .{}, |
| 64 | data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []const u8) = .{}, | 65 | /// the code is modified when relocated, so that is why it is mutable |
| | 66 | data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []u8) = .{}, |
| 65 | | 67 | |
| 66 | /// Table of unnamed constants associated with a parent `Decl`. | 68 | /// Table of unnamed constants associated with a parent `Decl`. |
| 67 | /// We store them here so that we can free the constants whenever the `Decl` | 69 | /// We store them here so that we can free the constants whenever the `Decl` |
| ... | @@ -83,6 +85,8 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []const u8) = | ... | @@ -83,6 +85,8 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []const u8) = |
| 83 | /// value assigned to label `foo` is an unnamed constant belonging/associated | 85 | /// value assigned to label `foo` is an unnamed constant belonging/associated |
| 84 | /// with `Decl` `main`, and lives as long as that `Decl`. | 86 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| 85 | unnamed_const_atoms: UnnamedConstTable = .{}, | 87 | unnamed_const_atoms: UnnamedConstTable = .{}, |
| | 88 | |
| | 89 | relocs: std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Reloc)) = .{}, |
| 86 | hdr: aout.ExecHdr = undefined, | 90 | hdr: aout.ExecHdr = undefined, |
| 87 | | 91 | |
| 88 | // relocs: std. | 92 | // relocs: std. |
| ... | @@ -97,6 +101,12 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{}, | ... | @@ -97,6 +101,12 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{}, |
| 97 | | 101 | |
| 98 | syms_index_free_list: std.ArrayListUnmanaged(usize) = .{}, | 102 | syms_index_free_list: std.ArrayListUnmanaged(usize) = .{}, |
| 99 | | 103 | |
| | 104 | const Reloc = struct { |
| | 105 | target: Module.Decl.Index, |
| | 106 | offset: u64, |
| | 107 | addend: u32, |
| | 108 | }; |
| | 109 | |
| 100 | const Bases = struct { | 110 | const Bases = struct { |
| 101 | text: u64, | 111 | text: u64, |
| 102 | /// the Global Offset Table starts at the beginning of the data section | 112 | /// the Global Offset Table starts at the beginning of the data section |
| ... | @@ -342,7 +352,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I | ... | @@ -342,7 +352,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 342 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .{ | 352 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .{ |
| 343 | .none = {}, | 353 | .none = {}, |
| 344 | }, .{ | 354 | }, .{ |
| 345 | .parent_atom_index = undefined, | 355 | .parent_atom_index = @enumToInt(decl_index), |
| 346 | }); | 356 | }); |
| 347 | const code = switch (res) { | 357 | const code = switch (res) { |
| 348 | .externally_managed => |x| x, | 358 | .externally_managed => |x| x, |
| ... | @@ -377,18 +387,17 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -377,18 +387,17 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) |
| 377 | | 387 | |
| 378 | try self.seeDecl(decl_index); | 388 | try self.seeDecl(decl_index); |
| 379 | | 389 | |
| 380 | log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); | 390 | log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index }); |
| 381 | | 391 | |
| 382 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 392 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 383 | defer code_buffer.deinit(); | 393 | defer code_buffer.deinit(); |
| 384 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 394 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 385 | // TODO we need the symbol index for symbol in the table of locals for the containing atom | 395 | // TODO we need the symbol index for symbol in the table of locals for the containing atom |
| 386 | const sym_index = decl.link.plan9.sym_index orelse 0; | | |
| 387 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 396 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 388 | .ty = decl.ty, | 397 | .ty = decl.ty, |
| 389 | .val = decl_val, | 398 | .val = decl_val, |
| 390 | }, &code_buffer, .{ .none = {} }, .{ | 399 | }, &code_buffer, .{ .none = {} }, .{ |
| 391 | .parent_atom_index = @intCast(u32, sym_index), | 400 | .parent_atom_index = @enumToInt(decl_index), |
| 392 | }); | 401 | }); |
| 393 | const code = switch (res) { | 402 | const code = switch (res) { |
| 394 | .externally_managed => |x| x, | 403 | .externally_managed => |x| x, |
| ... | @@ -655,6 +664,42 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -655,6 +664,42 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 655 | if (self.sixtyfour_bit) { | 664 | if (self.sixtyfour_bit) { |
| 656 | mem.writeIntSliceBig(u64, hdr_buf[32..40], self.entry_val.?); | 665 | mem.writeIntSliceBig(u64, hdr_buf[32..40], self.entry_val.?); |
| 657 | } | 666 | } |
| | 667 | // perform the relocs |
| | 668 | { |
| | 669 | var it = self.relocs.iterator(); |
| | 670 | while (it.next()) |kv| { |
| | 671 | const source_decl_index = kv.key_ptr.*; |
| | 672 | const source_decl = mod.declPtr(source_decl_index); |
| | 673 | for (kv.value_ptr.items) |reloc| { |
| | 674 | const target_decl_index = reloc.target; |
| | 675 | const target_decl = mod.declPtr(target_decl_index); |
| | 676 | const target_decl_offset = target_decl.link.plan9.offset.?; |
| | 677 | |
| | 678 | const offset = reloc.offset; |
| | 679 | const addend = reloc.addend; |
| | 680 | |
| | 681 | log.debug("relocating the address of '{s}' + {d} into '{s}' + {d}", .{ target_decl.name, addend, source_decl.name, offset }); |
| | 682 | |
| | 683 | const code = blk: { |
| | 684 | const is_fn = source_decl.ty.zigTypeTag() == .Fn; |
| | 685 | if (is_fn) { |
| | 686 | const table = self.fn_decl_table.get(source_decl.getFileScope()).?.functions; |
| | 687 | const output = table.get(source_decl_index).?; |
| | 688 | break :blk output.code; |
| | 689 | } else { |
| | 690 | const code = self.data_decl_table.get(source_decl_index).?; |
| | 691 | break :blk code; |
| | 692 | } |
| | 693 | }; |
| | 694 | |
| | 695 | if (!self.sixtyfour_bit) { |
| | 696 | mem.writeInt(u32, code[@intCast(usize, offset)..][0..4], @intCast(u32, target_decl_offset + addend), self.base.options.target.cpu.arch.endian()); |
| | 697 | } else { |
| | 698 | mem.writeInt(u64, code[@intCast(usize, offset)..][0..8], target_decl_offset + addend, self.base.options.target.cpu.arch.endian()); |
| | 699 | } |
| | 700 | } |
| | 701 | } |
| | 702 | } |
| 658 | // write it all! | 703 | // write it all! |
| 659 | try file.pwritevAll(iovecs, 0); | 704 | try file.pwritevAll(iovecs, 0); |
| 660 | } | 705 | } |
| ... | @@ -716,6 +761,11 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { | ... | @@ -716,6 +761,11 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { |
| 716 | self.syms.items[i] = aout.Sym.undefined_symbol; | 761 | self.syms.items[i] = aout.Sym.undefined_symbol; |
| 717 | } | 762 | } |
| 718 | self.freeUnnamedConsts(decl_index); | 763 | self.freeUnnamedConsts(decl_index); |
| | 764 | { |
| | 765 | const relocs = self.relocs.getPtr(decl_index) orelse return; |
| | 766 | relocs.clearAndFree(self.base.allocator); |
| | 767 | assert(self.relocs.remove(decl_index)); |
| | 768 | } |
| 719 | } | 769 | } |
| 720 | fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void { | 770 | fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void { |
| 721 | const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; | 771 | const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; |
| ... | @@ -749,6 +799,13 @@ pub fn updateDeclExports( | ... | @@ -749,6 +799,13 @@ pub fn updateDeclExports( |
| 749 | } | 799 | } |
| 750 | pub fn deinit(self: *Plan9) void { | 800 | pub fn deinit(self: *Plan9) void { |
| 751 | const gpa = self.base.allocator; | 801 | const gpa = self.base.allocator; |
| | 802 | { |
| | 803 | var it = self.relocs.valueIterator(); |
| | 804 | while (it.next()) |relocs| { |
| | 805 | relocs.deinit(self.base.allocator); |
| | 806 | } |
| | 807 | self.relocs.deinit(self.base.allocator); |
| | 808 | } |
| 752 | // free the unnamed consts | 809 | // free the unnamed consts |
| 753 | var it_unc = self.unnamed_const_atoms.iterator(); | 810 | var it_unc = self.unnamed_const_atoms.iterator(); |
| 754 | while (it_unc.next()) |kv| { | 811 | while (it_unc.next()) |kv| { |
| ... | @@ -904,7 +961,6 @@ pub fn getDeclVAddr( | ... | @@ -904,7 +961,6 @@ pub fn getDeclVAddr( |
| 904 | decl_index: Module.Decl.Index, | 961 | decl_index: Module.Decl.Index, |
| 905 | reloc_info: link.File.RelocInfo, | 962 | reloc_info: link.File.RelocInfo, |
| 906 | ) !u64 { | 963 | ) !u64 { |
| 907 | _ = reloc_info; | | |
| 908 | const mod = self.base.options.module.?; | 964 | const mod = self.base.options.module.?; |
| 909 | const decl = mod.declPtr(decl_index); | 965 | const decl = mod.declPtr(decl_index); |
| 910 | if (decl.ty.zigTypeTag() == .Fn) { | 966 | if (decl.ty.zigTypeTag() == .Fn) { |
| ... | @@ -918,9 +974,6 @@ pub fn getDeclVAddr( | ... | @@ -918,9 +974,6 @@ pub fn getDeclVAddr( |
| 918 | start += entry.value_ptr.code.len; | 974 | start += entry.value_ptr.code.len; |
| 919 | } | 975 | } |
| 920 | } | 976 | } |
| 921 | // TODO | | |
| 922 | return undefined; | | |
| 923 | // unreachable; | | |
| 924 | } else { | 977 | } else { |
| 925 | var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; | 978 | var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 926 | var it = self.data_decl_table.iterator(); | 979 | var it = self.data_decl_table.iterator(); |
| ... | @@ -928,8 +981,16 @@ pub fn getDeclVAddr( | ... | @@ -928,8 +981,16 @@ pub fn getDeclVAddr( |
| 928 | if (decl_index == kv.key_ptr.*) return start; | 981 | if (decl_index == kv.key_ptr.*) return start; |
| 929 | start += kv.value_ptr.len; | 982 | start += kv.value_ptr.len; |
| 930 | } | 983 | } |
| 931 | // TODO | | |
| 932 | return undefined; | | |
| 933 | // unreachable; | | |
| 934 | } | 984 | } |
| | 985 | // the parent_atom_index in this case is just the decl_index of the parent |
| | 986 | const gop = try self.relocs.getOrPut(self.base.allocator, @intToEnum(Module.Decl.Index, reloc_info.parent_atom_index)); |
| | 987 | if (!gop.found_existing) { |
| | 988 | gop.value_ptr.* = .{}; |
| | 989 | } |
| | 990 | try gop.value_ptr.append(self.base.allocator, .{ |
| | 991 | .target = decl_index, |
| | 992 | .offset = reloc_info.offset, |
| | 993 | .addend = reloc_info.addend, |
| | 994 | }); |
| | 995 | return undefined; |
| 935 | } | 996 | } |