| ... | ... | @@ -22,7 +22,8 @@ const log = std.log.scoped(.link); |
| 22 | 22 | const assert = std.debug.assert; |
| 23 | 23 | |
| 24 | 24 | const FnDeclOutput = struct { |
| 25 | | code: []const u8, |
| 25 | /// this code is modified when relocated so it is mutable |
| 26 | code: []u8, |
| 26 | 27 | /// this might have to be modified in the linker, so thats why its mutable |
| 27 | 28 | lineinfo: []u8, |
| 28 | 29 | start_line: u32, |
| ... | ... | @@ -61,7 +62,8 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged( |
| 61 | 62 | *Module.File, |
| 62 | 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 | 68 | /// Table of unnamed constants associated with a parent `Decl`. |
| 67 | 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 | 85 | /// value assigned to label `foo` is an unnamed constant belonging/associated |
| 84 | 86 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| 85 | 87 | unnamed_const_atoms: UnnamedConstTable = .{}, |
| 88 | |
| 89 | relocs: std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Reloc)) = .{}, |
| 86 | 90 | hdr: aout.ExecHdr = undefined, |
| 87 | 91 | |
| 88 | 92 | // relocs: std. |
| ... | ... | @@ -97,6 +101,12 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{}, |
| 97 | 101 | |
| 98 | 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 | 110 | const Bases = struct { |
| 101 | 111 | text: u64, |
| 102 | 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 | 352 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .{ |
| 343 | 353 | .none = {}, |
| 344 | 354 | }, .{ |
| 345 | | .parent_atom_index = undefined, |
| 355 | .parent_atom_index = @enumToInt(decl_index), |
| 346 | 356 | }); |
| 347 | 357 | const code = switch (res) { |
| 348 | 358 | .externally_managed => |x| x, |
| ... | ... | @@ -377,18 +387,17 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) |
| 377 | 387 | |
| 378 | 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 | 392 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 383 | 393 | defer code_buffer.deinit(); |
| 384 | 394 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 385 | 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 | 396 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 388 | 397 | .ty = decl.ty, |
| 389 | 398 | .val = decl_val, |
| 390 | 399 | }, &code_buffer, .{ .none = {} }, .{ |
| 391 | | .parent_atom_index = @intCast(u32, sym_index), |
| 400 | .parent_atom_index = @enumToInt(decl_index), |
| 392 | 401 | }); |
| 393 | 402 | const code = switch (res) { |
| 394 | 403 | .externally_managed => |x| x, |
| ... | ... | @@ -655,6 +664,42 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 655 | 664 | if (self.sixtyfour_bit) { |
| 656 | 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 | 703 | // write it all! |
| 659 | 704 | try file.pwritevAll(iovecs, 0); |
| 660 | 705 | } |
| ... | ... | @@ -716,6 +761,11 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { |
| 716 | 761 | self.syms.items[i] = aout.Sym.undefined_symbol; |
| 717 | 762 | } |
| 718 | 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 | 770 | fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void { |
| 721 | 771 | const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; |
| ... | ... | @@ -749,6 +799,13 @@ pub fn updateDeclExports( |
| 749 | 799 | } |
| 750 | 800 | pub fn deinit(self: *Plan9) void { |
| 751 | 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 | 809 | // free the unnamed consts |
| 753 | 810 | var it_unc = self.unnamed_const_atoms.iterator(); |
| 754 | 811 | while (it_unc.next()) |kv| { |
| ... | ... | @@ -904,7 +961,6 @@ pub fn getDeclVAddr( |
| 904 | 961 | decl_index: Module.Decl.Index, |
| 905 | 962 | reloc_info: link.File.RelocInfo, |
| 906 | 963 | ) !u64 { |
| 907 | | _ = reloc_info; |
| 908 | 964 | const mod = self.base.options.module.?; |
| 909 | 965 | const decl = mod.declPtr(decl_index); |
| 910 | 966 | if (decl.ty.zigTypeTag() == .Fn) { |
| ... | ... | @@ -918,9 +974,6 @@ pub fn getDeclVAddr( |
| 918 | 974 | start += entry.value_ptr.code.len; |
| 919 | 975 | } |
| 920 | 976 | } |
| 921 | | // TODO |
| 922 | | return undefined; |
| 923 | | // unreachable; |
| 924 | 977 | } else { |
| 925 | 978 | var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 926 | 979 | var it = self.data_decl_table.iterator(); |
| ... | ... | @@ -928,8 +981,16 @@ pub fn getDeclVAddr( |
| 928 | 981 | if (decl_index == kv.key_ptr.*) return start; |
| 929 | 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 | } |