| ... | ... | @@ -100,11 +100,23 @@ syms_index_free_list: std.ArrayListUnmanaged(usize) = .{}, |
| 100 | 100 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 101 | 101 | decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, |
| 102 | 102 | |
| 103 | /// Indices of the three "special" symbols into atoms |
| 104 | etext_edata_end_atom_indices: [3]?Atom.Index = .{ null, null, null }, |
| 105 | |
| 103 | 106 | const Reloc = struct { |
| 104 | 107 | target: Atom.Index, |
| 105 | 108 | offset: u64, |
| 106 | 109 | addend: u32, |
| 107 | | pcrel: bool = false, |
| 110 | type: enum { |
| 111 | pcrel, |
| 112 | nonpcrel, |
| 113 | // for getting the value of the etext symbol; we ignore target |
| 114 | special_etext, |
| 115 | // for getting the value of the edata symbol; we ignore target |
| 116 | special_edata, |
| 117 | // for getting the value of the end symbol; we ignore target |
| 118 | special_end, |
| 119 | } = .nonpcrel, |
| 108 | 120 | }; |
| 109 | 121 | |
| 110 | 122 | const Bases = struct { |
| ... | ... | @@ -467,15 +479,10 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 467 | 479 | pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void { |
| 468 | 480 | const decl = mod.declPtr(decl_index); |
| 469 | 481 | |
| 470 | | if (decl.val.getExternFunc(mod)) |_| { |
| 471 | | return; // TODO Should we do more when front-end analyzed extern decl? |
| 472 | | } |
| 473 | | if (decl.val.getVariable(mod)) |variable| { |
| 474 | | if (variable.is_extern) { |
| 475 | | return; // TODO Should we do more when front-end analyzed extern decl? |
| 476 | | } |
| 482 | if (decl.isExtern(mod)) { |
| 483 | log.debug("found extern decl: {s}", .{mod.intern_pool.stringToSlice(decl.name)}); |
| 484 | return; |
| 477 | 485 | } |
| 478 | | |
| 479 | 486 | const atom_idx = try self.seeDecl(decl_index); |
| 480 | 487 | |
| 481 | 488 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| ... | ... | @@ -574,6 +581,13 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { |
| 574 | 581 | } |
| 575 | 582 | } |
| 576 | 583 | |
| 584 | fn externCount(self: *Plan9) usize { |
| 585 | var extern_atom_count: usize = 0; |
| 586 | for (self.etext_edata_end_atom_indices) |idx| { |
| 587 | if (idx != null) extern_atom_count += 1; |
| 588 | } |
| 589 | return extern_atom_count; |
| 590 | } |
| 577 | 591 | // counts decls, unnamed consts, and lazy syms |
| 578 | 592 | fn atomCount(self: *Plan9) usize { |
| 579 | 593 | var fn_decl_count: usize = 0; |
| ... | ... | @@ -594,7 +608,8 @@ fn atomCount(self: *Plan9) usize { |
| 594 | 608 | while (it_lazy.next()) |kv| { |
| 595 | 609 | lazy_atom_count += kv.value_ptr.numberOfAtoms(); |
| 596 | 610 | } |
| 597 | | return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count; |
| 611 | const extern_atom_count = self.externCount(); |
| 612 | return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count; |
| 598 | 613 | } |
| 599 | 614 | |
| 600 | 615 | pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { |
| ... | ... | @@ -647,7 +662,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 647 | 662 | defer self.base.allocator.free(got_table); |
| 648 | 663 | |
| 649 | 664 | // + 4 for header, got, symbols, linecountinfo |
| 650 | | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4); |
| 665 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount()); |
| 651 | 666 | defer self.base.allocator.free(iovecs); |
| 652 | 667 | |
| 653 | 668 | const file = self.base.file.?; |
| ... | ... | @@ -729,8 +744,17 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 729 | 744 | self.syms.items[text_atom.sym_index.?].value = off; |
| 730 | 745 | } |
| 731 | 746 | } |
| 732 | | // etext symbol |
| 733 | | self.syms.items[2].value = self.getAddr(text_i, .t); |
| 747 | // fix the sym for etext |
| 748 | if (self.etext_edata_end_atom_indices[0]) |etext_atom_idx| { |
| 749 | const etext_atom = self.getAtom(etext_atom_idx); |
| 750 | const val = self.getAddr(text_i, .t); |
| 751 | self.syms.items[etext_atom.sym_index.?].value = val; |
| 752 | if (!self.sixtyfour_bit) { |
| 753 | mem.writeInt(u32, got_table[etext_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian()); |
| 754 | } else { |
| 755 | mem.writeInt(u64, got_table[etext_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian()); |
| 756 | } |
| 757 | } |
| 734 | 758 | // global offset table is in data |
| 735 | 759 | iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len }; |
| 736 | 760 | iovecs_i += 1; |
| ... | ... | @@ -800,15 +824,34 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 800 | 824 | self.syms.items[data_atom.sym_index.?].value = off; |
| 801 | 825 | } |
| 802 | 826 | // edata symbol |
| 803 | | self.syms.items[0].value = self.getAddr(data_i, .b); |
| 804 | | // end |
| 805 | | self.syms.items[1].value = self.getAddr(data_i, .b); |
| 827 | if (self.etext_edata_end_atom_indices[1]) |edata_atom_idx| { |
| 828 | const edata_atom = self.getAtom(edata_atom_idx); |
| 829 | const val = self.getAddr(data_i, .b); |
| 830 | self.syms.items[edata_atom.sym_index.?].value = val; |
| 831 | if (!self.sixtyfour_bit) { |
| 832 | mem.writeInt(u32, got_table[edata_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian()); |
| 833 | } else { |
| 834 | mem.writeInt(u64, got_table[edata_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian()); |
| 835 | } |
| 836 | } |
| 837 | // end symbol (same as edata because native backends don't do .bss yet) |
| 838 | if (self.etext_edata_end_atom_indices[2]) |end_atom_idx| { |
| 839 | const end_atom = self.getAtom(end_atom_idx); |
| 840 | const val = self.getAddr(data_i, .b); |
| 841 | self.syms.items[end_atom.sym_index.?].value = val; |
| 842 | if (!self.sixtyfour_bit) { |
| 843 | mem.writeInt(u32, got_table[end_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian()); |
| 844 | } else { |
| 845 | log.debug("write end (got_table[0x{x}] = 0x{x})", .{ end_atom.got_index.? * 8, val }); |
| 846 | mem.writeInt(u64, got_table[end_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian()); |
| 847 | } |
| 848 | } |
| 806 | 849 | } |
| 807 | 850 | var sym_buf = std.ArrayList(u8).init(self.base.allocator); |
| 808 | 851 | try self.writeSyms(&sym_buf); |
| 809 | 852 | const syms = try sym_buf.toOwnedSlice(); |
| 810 | 853 | defer self.base.allocator.free(syms); |
| 811 | | assert(2 + self.atomCount() == iovecs_i); // we didn't write all the decls |
| 854 | assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls |
| 812 | 855 | iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len }; |
| 813 | 856 | iovecs_i += 1; |
| 814 | 857 | iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len }; |
| ... | ... | @@ -836,28 +879,46 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 836 | 879 | const source_atom_index = kv.key_ptr.*; |
| 837 | 880 | const source_atom = self.getAtom(source_atom_index); |
| 838 | 881 | const source_atom_symbol = self.syms.items[source_atom.sym_index.?]; |
| 882 | const code = source_atom.code.getCode(self); |
| 883 | const endian = self.base.options.target.cpu.arch.endian(); |
| 839 | 884 | for (kv.value_ptr.items) |reloc| { |
| 840 | | const target_atom_index = reloc.target; |
| 841 | | const target_atom = self.getAtomPtr(target_atom_index); |
| 842 | | const target_symbol = self.syms.items[target_atom.sym_index.?]; |
| 843 | | const target_offset = target_atom.offset.?; |
| 844 | | |
| 845 | 885 | const offset = reloc.offset; |
| 846 | 886 | const addend = reloc.addend; |
| 847 | | |
| 848 | | const code = source_atom.code.getCode(self); |
| 849 | | |
| 850 | | if (reloc.pcrel) { |
| 851 | | const disp = @as(i32, @intCast(target_offset)) - @as(i32, @intCast(source_atom.offset.?)) - 4 - @as(i32, @intCast(offset)); |
| 852 | | mem.writeInt(i32, code[@as(usize, @intCast(offset))..][0..4], @as(i32, @intCast(disp)), self.base.options.target.cpu.arch.endian()); |
| 887 | if (reloc.type == .pcrel or reloc.type == .nonpcrel) { |
| 888 | const target_atom_index = reloc.target; |
| 889 | const target_atom = self.getAtomPtr(target_atom_index); |
| 890 | const target_symbol = self.syms.items[target_atom.sym_index.?]; |
| 891 | const target_offset = target_atom.offset.?; |
| 892 | |
| 893 | switch (reloc.type) { |
| 894 | .pcrel => { |
| 895 | const disp = @as(i32, @intCast(target_offset)) - @as(i32, @intCast(source_atom.offset.?)) - 4 - @as(i32, @intCast(offset)); |
| 896 | mem.writeInt(i32, code[@as(usize, @intCast(offset))..][0..4], @as(i32, @intCast(disp)), endian); |
| 897 | }, |
| 898 | .nonpcrel => { |
| 899 | if (!self.sixtyfour_bit) { |
| 900 | mem.writeInt(u32, code[@intCast(offset)..][0..4], @as(u32, @intCast(target_offset + addend)), endian); |
| 901 | } else { |
| 902 | mem.writeInt(u64, code[@intCast(offset)..][0..8], target_offset + addend, endian); |
| 903 | } |
| 904 | }, |
| 905 | else => unreachable, |
| 906 | } |
| 907 | 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 }); |
| 853 | 908 | } else { |
| 909 | const addr = switch (reloc.type) { |
| 910 | .special_etext => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[0].?).sym_index.?].value, |
| 911 | .special_edata => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[1].?).sym_index.?].value, |
| 912 | .special_end => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[2].?).sym_index.?].value, |
| 913 | else => unreachable, |
| 914 | }; |
| 854 | 915 | if (!self.sixtyfour_bit) { |
| 855 | | mem.writeInt(u32, code[@as(usize, @intCast(offset))..][0..4], @as(u32, @intCast(target_offset + addend)), self.base.options.target.cpu.arch.endian()); |
| 916 | mem.writeInt(u32, code[@intCast(offset)..][0..4], @as(u32, @intCast(addr + addend)), endian); |
| 856 | 917 | } else { |
| 857 | | mem.writeInt(u64, code[@as(usize, @intCast(offset))..][0..8], target_offset + addend, self.base.options.target.cpu.arch.endian()); |
| 918 | mem.writeInt(u64, code[@intCast(offset)..][0..8], addr + addend, endian); |
| 858 | 919 | } |
| 920 | log.debug("relocating the address of '{s}' + {d} into '{s}' + {d} (({s}[{d}] = 0x{x} + 0x{x})", .{ @tagName(reloc.type), addend, source_atom_symbol.name, offset, source_atom_symbol.name, offset, addr, addend }); |
| 859 | 921 | } |
| 860 | | 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 }); |
| 861 | 922 | } |
| 862 | 923 | } |
| 863 | 924 | } |
| ... | ... | @@ -983,7 +1044,24 @@ pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !Atom.Index { |
| 983 | 1044 | .exports = .{}, |
| 984 | 1045 | }; |
| 985 | 1046 | } |
| 986 | | return gop.value_ptr.index; |
| 1047 | const atom_idx = gop.value_ptr.index; |
| 1048 | // handle externs here because they might not get updateDecl called on them |
| 1049 | const mod = self.base.options.module.?; |
| 1050 | const decl = mod.declPtr(decl_index); |
| 1051 | const name = mod.intern_pool.stringToSlice(decl.name); |
| 1052 | if (decl.isExtern(mod)) { |
| 1053 | // this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs |
| 1054 | if (std.mem.eql(u8, name, "etext")) { |
| 1055 | self.etext_edata_end_atom_indices[0] = atom_idx; |
| 1056 | } else if (std.mem.eql(u8, name, "edata")) { |
| 1057 | self.etext_edata_end_atom_indices[1] = atom_idx; |
| 1058 | } else if (std.mem.eql(u8, name, "end")) { |
| 1059 | self.etext_edata_end_atom_indices[2] = atom_idx; |
| 1060 | } |
| 1061 | try self.updateFinish(decl_index); |
| 1062 | log.debug("seeDecl(extern) for {s} (got_addr=0x{x})", .{ name, self.getAtom(atom_idx).getOffsetTableAddress(self) }); |
| 1063 | } else log.debug("seeDecl for {s}", .{name}); |
| 1064 | return atom_idx; |
| 987 | 1065 | } |
| 988 | 1066 | |
| 989 | 1067 | pub fn updateDeclExports( |
| ... | ... | @@ -1157,23 +1235,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 1157 | 1235 | |
| 1158 | 1236 | self.bases = defaultBaseAddrs(options.target.cpu.arch); |
| 1159 | 1237 | |
| 1160 | | // first 4 symbols in our table are edata, end, etext, and got |
| 1161 | 1238 | try self.syms.appendSlice(self.base.allocator, &.{ |
| 1162 | | .{ |
| 1163 | | .value = 0xcafebabe, |
| 1164 | | .type = .B, |
| 1165 | | .name = "edata", |
| 1166 | | }, |
| 1167 | | .{ |
| 1168 | | .value = 0xcafebabe, |
| 1169 | | .type = .B, |
| 1170 | | .name = "end", |
| 1171 | | }, |
| 1172 | | .{ |
| 1173 | | .value = 0xcafebabe, |
| 1174 | | .type = .T, |
| 1175 | | .name = "etext", |
| 1176 | | }, |
| 1177 | 1239 | // we include the global offset table to make it easier for debugging |
| 1178 | 1240 | .{ |
| 1179 | 1241 | .value = self.getAddr(0, .d), // the global offset table starts at 0 |
| ... | ... | @@ -1202,11 +1264,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 1202 | 1264 | const mod = self.base.options.module.?; |
| 1203 | 1265 | const ip = &mod.intern_pool; |
| 1204 | 1266 | const writer = buf.writer(); |
| 1205 | | // write the first four symbols (edata, etext, end, __GOT) |
| 1267 | // write __GOT |
| 1206 | 1268 | try self.writeSym(writer, self.syms.items[0]); |
| 1207 | | try self.writeSym(writer, self.syms.items[1]); |
| 1208 | | try self.writeSym(writer, self.syms.items[2]); |
| 1209 | | try self.writeSym(writer, self.syms.items[3]); |
| 1210 | 1269 | // write the f symbols |
| 1211 | 1270 | { |
| 1212 | 1271 | var it = self.file_segments.iterator(); |
| ... | ... | @@ -1296,6 +1355,14 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 1296 | 1355 | } |
| 1297 | 1356 | } |
| 1298 | 1357 | } |
| 1358 | // special symbols |
| 1359 | for (self.etext_edata_end_atom_indices) |idx| { |
| 1360 | if (idx) |atom_idx| { |
| 1361 | const atom = self.getAtom(atom_idx); |
| 1362 | const sym = self.syms.items[atom.sym_index.?]; |
| 1363 | try self.writeSym(writer, sym); |
| 1364 | } |
| 1365 | } |
| 1299 | 1366 | } |
| 1300 | 1367 | |
| 1301 | 1368 | /// Must be called only after a successful call to `updateDecl`. |
| ... | ... | @@ -1312,6 +1379,34 @@ pub fn getDeclVAddr( |
| 1312 | 1379 | ) !u64 { |
| 1313 | 1380 | const mod = self.base.options.module.?; |
| 1314 | 1381 | const decl = mod.declPtr(decl_index); |
| 1382 | log.debug("getDeclVAddr for {s}", .{mod.intern_pool.stringToSlice(decl.name)}); |
| 1383 | if (decl.isExtern(mod)) { |
| 1384 | const extern_name = mod.intern_pool.stringToSlice(decl.name); |
| 1385 | if (std.mem.eql(u8, extern_name, "etext")) { |
| 1386 | try self.addReloc(reloc_info.parent_atom_index, .{ |
| 1387 | .target = undefined, |
| 1388 | .offset = reloc_info.offset, |
| 1389 | .addend = reloc_info.addend, |
| 1390 | .type = .special_etext, |
| 1391 | }); |
| 1392 | } else if (std.mem.eql(u8, extern_name, "edata")) { |
| 1393 | try self.addReloc(reloc_info.parent_atom_index, .{ |
| 1394 | .target = undefined, |
| 1395 | .offset = reloc_info.offset, |
| 1396 | .addend = reloc_info.addend, |
| 1397 | .type = .special_edata, |
| 1398 | }); |
| 1399 | } else if (std.mem.eql(u8, extern_name, "end")) { |
| 1400 | try self.addReloc(reloc_info.parent_atom_index, .{ |
| 1401 | .target = undefined, |
| 1402 | .offset = reloc_info.offset, |
| 1403 | .addend = reloc_info.addend, |
| 1404 | .type = .special_end, |
| 1405 | }); |
| 1406 | } |
| 1407 | // TODO handle other extern variables and functions |
| 1408 | return undefined; |
| 1409 | } |
| 1315 | 1410 | // we might already know the vaddr |
| 1316 | 1411 | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 1317 | 1412 | var start = self.bases.text; |
| ... | ... | @@ -1339,7 +1434,7 @@ pub fn getDeclVAddr( |
| 1339 | 1434 | .offset = reloc_info.offset, |
| 1340 | 1435 | .addend = reloc_info.addend, |
| 1341 | 1436 | }); |
| 1342 | | return 0xcafebabe; |
| 1437 | return undefined; |
| 1343 | 1438 | } |
| 1344 | 1439 | |
| 1345 | 1440 | pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void { |