authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-29 18:00:57+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-29 18:55:58+01:00
log71dfea1f174b0531139e33e8aa4fe86ccd9f23dd
tree1981e3e6b7e0706abb6ce910c51ae87afd20a391
parenta7a95ce9c4e11e8b3ab887481a7f0e7e8294a87c

coff: implement exporting anon decls


2 files changed, 53 insertions(+), 39 deletions(-)

src/link/Coff.zig+49-37
...@@ -54,7 +54,7 @@ entry_addr: ?u32 = null,...@@ -54,7 +54,7 @@ entry_addr: ?u32 = null,
54lazy_syms: LazySymbolTable = .{},54lazy_syms: LazySymbolTable = .{},
5555
56/// Table of tracked Decls.56/// Table of tracked Decls.
57decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},57decls: DeclTable = .{},
5858
59/// List of atoms that are either synthetic or map directly to the Zig source program.59/// List of atoms that are either synthetic or map directly to the Zig source program.
60atoms: std.ArrayListUnmanaged(Atom) = .{},60atoms: std.ArrayListUnmanaged(Atom) = .{},
...@@ -108,7 +108,8 @@ const HotUpdateState = struct {...@@ -108,7 +108,8 @@ const HotUpdateState = struct {
108 loaded_base_address: ?std.os.windows.HMODULE = null,108 loaded_base_address: ?std.os.windows.HMODULE = null,
109};109};
110110
111const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index);111const DeclTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
112const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
112const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));113const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
113const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));114const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
114const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));115const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
...@@ -325,7 +326,14 @@ pub fn deinit(self: *Coff) void {...@@ -325,7 +326,14 @@ pub fn deinit(self: *Coff) void {
325 atoms.deinit(gpa);326 atoms.deinit(gpa);
326 }327 }
327 self.unnamed_const_atoms.deinit(gpa);328 self.unnamed_const_atoms.deinit(gpa);
328 self.anon_decls.deinit(gpa);329
330 {
331 var it = self.anon_decls.iterator();
332 while (it.next()) |entry| {
333 entry.value_ptr.exports.deinit(gpa);
334 }
335 self.anon_decls.deinit(gpa);
336 }
329337
330 for (self.relocs.values()) |*relocs| {338 for (self.relocs.values()) |*relocs| {
331 relocs.deinit(gpa);339 relocs.deinit(gpa);
...@@ -1462,62 +1470,66 @@ pub fn updateExports(...@@ -1462,62 +1470,66 @@ pub fn updateExports(
14621470
1463 const gpa = self.base.allocator;1471 const gpa = self.base.allocator;
14641472
1465 const decl_index = switch (exported) {1473 const metadata = switch (exported) {
1466 .decl_index => |i| i,1474 .decl_index => |decl_index| blk: {
1467 .value => |val| {1475 _ = try self.getOrCreateAtomForDecl(decl_index);
1468 _ = val;1476 break :blk self.decls.getPtr(decl_index).?;
1469 @panic("TODO: implement COFF linker code for exporting a constant value");1477 },
1478 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1479 const first_exp = exports[0];
1480 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
1481 switch (res) {
1482 .ok => {},
1483 .fail => |em| {
1484 // TODO maybe it's enough to return an error here and let Module.processExportsInner
1485 // handle the error?
1486 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1487 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1488 return;
1489 },
1490 }
1491 break :blk self.anon_decls.getPtr(value).?;
1470 },1492 },
1471 };1493 };
1472 const decl = mod.declPtr(decl_index);1494 const atom_index = metadata.atom;
1473 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
1474 const atom = self.getAtom(atom_index);1495 const atom = self.getAtom(atom_index);
1475 const decl_metadata = self.decls.getPtr(decl_index).?;
14761496
1477 for (exports) |exp| {1497 for (exports) |exp| {
1478 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});1498 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});
14791499
1480 if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section_name| {1500 if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section_name| {
1481 if (!mem.eql(u8, section_name, ".text")) {1501 if (!mem.eql(u8, section_name, ".text")) {
1482 try mod.failed_exports.putNoClobber(1502 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1483 gpa,1503 gpa,
1484 exp,1504 exp.getSrcLoc(mod),
1485 try Module.ErrorMsg.create(1505 "Unimplemented: ExportOptions.section",
1486 gpa,1506 .{},
1487 decl.srcLoc(mod),1507 ));
1488 "Unimplemented: ExportOptions.section",
1489 .{},
1490 ),
1491 );
1492 continue;1508 continue;
1493 }1509 }
1494 }1510 }
14951511
1496 if (exp.opts.linkage == .LinkOnce) {1512 if (exp.opts.linkage == .LinkOnce) {
1497 try mod.failed_exports.putNoClobber(1513 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1498 gpa,1514 gpa,
1499 exp,1515 exp.getSrcLoc(mod),
1500 try Module.ErrorMsg.create(1516 "Unimplemented: GlobalLinkage.LinkOnce",
1501 gpa,1517 .{},
1502 decl.srcLoc(mod),1518 ));
1503 "Unimplemented: GlobalLinkage.LinkOnce",
1504 .{},
1505 ),
1506 );
1507 continue;1519 continue;
1508 }1520 }
15091521
1510 const sym_index = decl_metadata.getExport(self, mod.intern_pool.stringToSlice(exp.opts.name)) orelse blk: {1522 const sym_index = metadata.getExport(self, mod.intern_pool.stringToSlice(exp.opts.name)) orelse blk: {
1511 const sym_index = try self.allocateSymbol();1523 const sym_index = try self.allocateSymbol();
1512 try decl_metadata.exports.append(gpa, sym_index);1524 try metadata.exports.append(gpa, sym_index);
1513 break :blk sym_index;1525 break :blk sym_index;
1514 };1526 };
1515 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };1527 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1516 const sym = self.getSymbolPtr(sym_loc);1528 const sym = self.getSymbolPtr(sym_loc);
1517 try self.setSymbolName(sym, mod.intern_pool.stringToSlice(exp.opts.name));1529 try self.setSymbolName(sym, mod.intern_pool.stringToSlice(exp.opts.name));
1518 sym.value = atom.getSymbol(self).value;1530 sym.value = atom.getSymbol(self).value;
1519 sym.section_number = @as(coff.SectionNumber, @enumFromInt(self.text_section_index.? + 1));1531 sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1));
1520 sym.type = .{ .complex_type = .FUNCTION, .base_type = .NULL };1532 sym.type = atom.getSymbol(self).type;
15211533
1522 switch (exp.opts.linkage) {1534 switch (exp.opts.linkage) {
1523 .Strong => {1535 .Strong => {
...@@ -1761,8 +1773,8 @@ pub fn lowerAnonDecl(...@@ -1761,8 +1773,8 @@ pub fn lowerAnonDecl(
1761 .none => ty.abiAlignment(mod),1773 .none => ty.abiAlignment(mod),
1762 else => explicit_alignment,1774 else => explicit_alignment,
1763 };1775 };
1764 if (self.anon_decls.get(decl_val)) |atom_index| {1776 if (self.anon_decls.get(decl_val)) |metadata| {
1765 const existing_addr = self.getAtom(atom_index).getSymbol(self).value;1777 const existing_addr = self.getAtom(metadata.atom).getSymbol(self).value;
1766 if (decl_alignment.check(existing_addr))1778 if (decl_alignment.check(existing_addr))
1767 return .ok;1779 return .ok;
1768 }1780 }
...@@ -1792,14 +1804,14 @@ pub fn lowerAnonDecl(...@@ -1792,14 +1804,14 @@ pub fn lowerAnonDecl(
1792 .ok => |atom_index| atom_index,1804 .ok => |atom_index| atom_index,
1793 .fail => |em| return .{ .fail = em },1805 .fail => |em| return .{ .fail = em },
1794 };1806 };
1795 try self.anon_decls.put(gpa, decl_val, atom_index);1807 try self.anon_decls.put(gpa, decl_val, .{ .atom = atom_index, .section = self.rdata_section_index.? });
1796 return .ok;1808 return .ok;
1797}1809}
17981810
1799pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {1811pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1800 assert(self.llvm_object == null);1812 assert(self.llvm_object == null);
18011813
1802 const this_atom_index = self.anon_decls.get(decl_val).?;1814 const this_atom_index = self.anon_decls.get(decl_val).?.atom;
1803 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;1815 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
1804 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;1816 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
1805 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };1817 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
test/behavior/export_builtin.zig+4-2
...@@ -56,7 +56,8 @@ test "exporting comptime-known value" {...@@ -56,7 +56,8 @@ test "exporting comptime-known value" {
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_x86_64 and57 if (builtin.zig_backend == .stage2_x86_64 and
58 (builtin.target.ofmt != .elf and58 (builtin.target.ofmt != .elf and
59 builtin.target.ofmt != .macho)) return error.SkipZigTest;59 builtin.target.ofmt != .macho and
60 builtin.target.ofmt != .coff)) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;61 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
61 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;62 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
62 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;63 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
...@@ -74,7 +75,8 @@ test "exporting comptime var" {...@@ -74,7 +75,8 @@ test "exporting comptime var" {
74 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;75 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_x86_64 and76 if (builtin.zig_backend == .stage2_x86_64 and
76 (builtin.target.ofmt != .elf and77 (builtin.target.ofmt != .elf and
77 builtin.target.ofmt != .macho)) return error.SkipZigTest;78 builtin.target.ofmt != .macho and
79 builtin.target.ofmt != .coff)) return error.SkipZigTest;
78 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;80 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
79 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;81 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
80 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;82 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;