authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-06 22:34:32+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-07 22:42:59+02:00
log99c2cb72e850ffdfd83abcc941c84a0053f8494e
tree5131b21e24590db6bd49e0e5aee9444c27285d3c
parentf3e4e44a2b8de8ee860c2c9d11ee1a770e625e0e

coff: track globals in contiguous array to allow for tombstones


1 files changed, 76 insertions(+), 41 deletions(-)

src/link/Coff.zig+76-41
......@@ -53,10 +53,12 @@ reloc_section_index: ?u16 = null,
5353idata_section_index: ?u16 = null,
5454
5555locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
56globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
56globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
57resolver: std.StringHashMapUnmanaged(u32) = .{},
5758unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},
5859
5960locals_free_list: std.ArrayListUnmanaged(u32) = .{},
61globals_free_list: std.ArrayListUnmanaged(u32) = .{},
6062
6163strtab: StringTable(.strtab) = .{},
6264strtab_offset: ?u32 = null,
......@@ -292,11 +294,15 @@ pub fn deinit(self: *Coff) void {
292294 self.managed_atoms.deinit(gpa);
293295
294296 self.locals.deinit(gpa);
297 self.globals.deinit(gpa);
295298
296 for (self.globals.keys()) |key| {
297 gpa.free(key);
299 {
300 var it = self.resolver.keyIterator();
301 while (it.next()) |key_ptr| {
302 gpa.free(key_ptr.*);
303 }
304 self.resolver.deinit(gpa);
298305 }
299 self.globals.deinit(gpa);
300306
301307 self.unresolved.deinit(gpa);
302308 self.locals_free_list.deinit(gpa);
......@@ -651,6 +657,30 @@ fn allocateSymbol(self: *Coff) !u32 {
651657 return index;
652658}
653659
660fn allocateGlobal(self: *Coff) !u32 {
661 const gpa = self.base.allocator;
662 try self.globals.ensureUnusedCapacity(gpa, 1);
663
664 const index = blk: {
665 if (self.globals_free_list.popOrNull()) |index| {
666 log.debug(" (reusing global index {d})", .{index});
667 break :blk index;
668 } else {
669 log.debug(" (allocating global index {d})", .{self.globals.items.len});
670 const index = @intCast(u32, self.globals.items.len);
671 _ = self.globals.addOneAssumeCapacity();
672 break :blk index;
673 }
674 };
675
676 self.globals.items[index] = .{
677 .sym_index = 0,
678 .file = null,
679 };
680
681 return index;
682}
683
654684pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {
655685 const gpa = self.base.allocator;
656686 try self.got_entries.ensureUnusedCapacity(gpa, 1);
......@@ -1340,7 +1370,7 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
13401370 const sym = self.getSymbolPtr(sym_loc);
13411371 const sym_name = self.getSymbolName(sym_loc);
13421372 log.debug("deleting export '{s}'", .{sym_name});
1343 assert(sym.storage_class == .EXTERNAL);
1373 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
13441374 sym.* = .{
13451375 .name = [_]u8{0} ** 8,
13461376 .value = 0,
......@@ -1351,33 +1381,38 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
13511381 };
13521382 self.locals_free_list.append(gpa, sym_index) catch {};
13531383
1354 if (self.globals.get(sym_name)) |global| blk: {
1355 if (global.sym_index != sym_index) break :blk;
1356 if (global.file != null) break :blk;
1357 const kv = self.globals.fetchSwapRemove(sym_name);
1358 gpa.free(kv.?.key);
1384 if (self.resolver.fetchRemove(sym_name)) |entry| {
1385 defer gpa.free(entry.key);
1386 self.globals_free_list.append(gpa, entry.value) catch {};
1387 self.globals.items[entry.value] = .{
1388 .sym_index = 0,
1389 .file = null,
1390 };
13591391 }
13601392}
13611393
13621394fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
13631395 const gpa = self.base.allocator;
13641396 const sym = self.getSymbol(current);
1365 _ = sym;
13661397 const sym_name = self.getSymbolName(current);
13671398
1368 const name = try gpa.dupe(u8, sym_name);
1369 const global_index = @intCast(u32, self.globals.values().len);
1370 _ = global_index;
1371 const gop = try self.globals.getOrPut(gpa, name);
1372 defer if (gop.found_existing) gpa.free(name);
1373
1374 if (!gop.found_existing) {
1375 gop.value_ptr.* = current;
1376 // TODO undef + tentative
1399 const global_index = self.resolver.get(sym_name) orelse {
1400 const name = try gpa.dupe(u8, sym_name);
1401 const global_index = try self.allocateGlobal();
1402 self.globals.items[global_index] = current;
1403 try self.resolver.putNoClobber(gpa, name, global_index);
1404 if (sym.section_number == .UNDEFINED) {
1405 try self.unresolved.putNoClobber(gpa, global_index, false);
1406 }
13771407 return;
1378 }
1408 };
13791409
13801410 log.debug("TODO finish resolveGlobalSymbols implementation", .{});
1411
1412 if (sym.section_number == .UNDEFINED) return;
1413
1414 _ = self.unresolved.swapRemove(global_index);
1415 self.globals.items[global_index] = current;
13811416}
13821417
13831418pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {
......@@ -1415,7 +1450,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
14151450
14161451 while (self.unresolved.popOrNull()) |entry| {
14171452 assert(entry.value); // We only expect imports generated by the incremental linker for now.
1418 const global = self.globals.values()[entry.key];
1453 const global = self.globals.items[entry.key];
14191454 if (self.imports_table.contains(global)) continue;
14201455
14211456 _ = try self.allocateImportEntry(global);
......@@ -1481,24 +1516,22 @@ pub fn getDeclVAddr(
14811516}
14821517
14831518pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
1484 const gpa = self.base.allocator;
1485 const sym_name = try gpa.dupe(u8, name);
1486 const global_index = @intCast(u32, self.globals.values().len);
1487 const gop = try self.globals.getOrPut(gpa, sym_name);
1488 defer if (gop.found_existing) gpa.free(sym_name);
1489
1490 if (gop.found_existing) {
1491 // TODO audit this: can we ever reference anything from outside the Zig module?
1492 assert(gop.value_ptr.file == null);
1493 return gop.value_ptr.sym_index;
1519 if (self.resolver.get(name)) |global_index| {
1520 return self.globals.items[global_index].sym_index;
14941521 }
14951522
1523 const gpa = self.base.allocator;
14961524 const sym_index = try self.allocateSymbol();
1525 const global_index = try self.allocateGlobal();
14971526 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1527 self.globals.items[global_index] = sym_loc;
1528
1529 const sym_name = try gpa.dupe(u8, name);
14981530 const sym = self.getSymbolPtr(sym_loc);
14991531 try self.setSymbolName(sym, sym_name);
15001532 sym.storage_class = .EXTERNAL;
1501 gop.value_ptr.* = sym_loc;
1533
1534 try self.resolver.putNoClobber(gpa, sym_name, global_index);
15021535 try self.unresolved.putNoClobber(gpa, global_index, true);
15031536
15041537 return sym_index;
......@@ -1607,14 +1640,15 @@ fn writeBaseRelocations(self: *Coff) !void {
16071640}
16081641
16091642fn writeImportTable(self: *Coff) !void {
1643 if (self.idata_section_index == null) return;
1644
16101645 const gpa = self.base.allocator;
16111646
16121647 const section = self.sections.get(self.idata_section_index.?);
1648 const last_atom = section.last_atom orelse return;
1649
16131650 const iat_rva = section.header.virtual_address;
1614 const iat_size = blk: {
1615 const last_atom = section.last_atom.?;
1616 break :blk last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer
1617 };
1651 const iat_size = last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer
16181652
16191653 const dll_name = "KERNEL32.dll";
16201654
......@@ -1975,7 +2009,8 @@ inline fn getSizeOfImage(self: Coff) u32 {
19752009/// Returns symbol location corresponding to the set entrypoint (if any).
19762010pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
19772011 const entry_name = self.base.options.entry orelse "wWinMainCRTStartup"; // TODO this is incomplete
1978 return self.globals.get(entry_name);
2012 const global_index = self.resolver.get(entry_name) orelse return null;
2013 return self.globals.items[global_index];
19792014}
19802015
19812016/// Returns pointer-to-symbol described by `sym_with_loc` descriptor.
......@@ -2100,9 +2135,9 @@ fn logSymtab(self: *Coff) void {
21002135 }
21012136
21022137 log.debug("globals table:", .{});
2103 for (self.globals.keys()) |name, id| {
2104 const value = self.globals.values()[id];
2105 log.debug(" {s} => %{d} in object({?d})", .{ name, value.sym_index, value.file });
2138 for (self.globals.items) |sym_loc| {
2139 const sym_name = self.getSymbolName(sym_loc);
2140 log.debug(" {s} => %{d} in object({?d})", .{ sym_name, sym_loc.sym_index, sym_loc.file });
21062141 }
21072142
21082143 log.debug("GOT entries:", .{});