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,...@@ -53,10 +53,12 @@ reloc_section_index: ?u16 = null,
53idata_section_index: ?u16 = null,53idata_section_index: ?u16 = null,
5454
55locals: std.ArrayListUnmanaged(coff.Symbol) = .{},55locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
56globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},56globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
57resolver: std.StringHashMapUnmanaged(u32) = .{},
57unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},58unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},
5859
59locals_free_list: std.ArrayListUnmanaged(u32) = .{},60locals_free_list: std.ArrayListUnmanaged(u32) = .{},
61globals_free_list: std.ArrayListUnmanaged(u32) = .{},
6062
61strtab: StringTable(.strtab) = .{},63strtab: StringTable(.strtab) = .{},
62strtab_offset: ?u32 = null,64strtab_offset: ?u32 = null,
...@@ -292,11 +294,15 @@ pub fn deinit(self: *Coff) void {...@@ -292,11 +294,15 @@ pub fn deinit(self: *Coff) void {
292 self.managed_atoms.deinit(gpa);294 self.managed_atoms.deinit(gpa);
293295
294 self.locals.deinit(gpa);296 self.locals.deinit(gpa);
297 self.globals.deinit(gpa);
295298
296 for (self.globals.keys()) |key| {299 {
297 gpa.free(key);300 var it = self.resolver.keyIterator();
301 while (it.next()) |key_ptr| {
302 gpa.free(key_ptr.*);
303 }
304 self.resolver.deinit(gpa);
298 }305 }
299 self.globals.deinit(gpa);
300306
301 self.unresolved.deinit(gpa);307 self.unresolved.deinit(gpa);
302 self.locals_free_list.deinit(gpa);308 self.locals_free_list.deinit(gpa);
...@@ -651,6 +657,30 @@ fn allocateSymbol(self: *Coff) !u32 {...@@ -651,6 +657,30 @@ fn allocateSymbol(self: *Coff) !u32 {
651 return index;657 return index;
652}658}
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
654pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {684pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {
655 const gpa = self.base.allocator;685 const gpa = self.base.allocator;
656 try self.got_entries.ensureUnusedCapacity(gpa, 1);686 try self.got_entries.ensureUnusedCapacity(gpa, 1);
...@@ -1340,7 +1370,7 @@ pub fn deleteExport(self: *Coff, exp: Export) void {...@@ -1340,7 +1370,7 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
1340 const sym = self.getSymbolPtr(sym_loc);1370 const sym = self.getSymbolPtr(sym_loc);
1341 const sym_name = self.getSymbolName(sym_loc);1371 const sym_name = self.getSymbolName(sym_loc);
1342 log.debug("deleting export '{s}'", .{sym_name});1372 log.debug("deleting export '{s}'", .{sym_name});
1343 assert(sym.storage_class == .EXTERNAL);1373 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
1344 sym.* = .{1374 sym.* = .{
1345 .name = [_]u8{0} ** 8,1375 .name = [_]u8{0} ** 8,
1346 .value = 0,1376 .value = 0,
...@@ -1351,33 +1381,38 @@ pub fn deleteExport(self: *Coff, exp: Export) void {...@@ -1351,33 +1381,38 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
1351 };1381 };
1352 self.locals_free_list.append(gpa, sym_index) catch {};1382 self.locals_free_list.append(gpa, sym_index) catch {};
13531383
1354 if (self.globals.get(sym_name)) |global| blk: {1384 if (self.resolver.fetchRemove(sym_name)) |entry| {
1355 if (global.sym_index != sym_index) break :blk;1385 defer gpa.free(entry.key);
1356 if (global.file != null) break :blk;1386 self.globals_free_list.append(gpa, entry.value) catch {};
1357 const kv = self.globals.fetchSwapRemove(sym_name);1387 self.globals.items[entry.value] = .{
1358 gpa.free(kv.?.key);1388 .sym_index = 0,
1389 .file = null,
1390 };
1359 }1391 }
1360}1392}
13611393
1362fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {1394fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
1363 const gpa = self.base.allocator;1395 const gpa = self.base.allocator;
1364 const sym = self.getSymbol(current);1396 const sym = self.getSymbol(current);
1365 _ = sym;
1366 const sym_name = self.getSymbolName(current);1397 const sym_name = self.getSymbolName(current);
13671398
1368 const name = try gpa.dupe(u8, sym_name);1399 const global_index = self.resolver.get(sym_name) orelse {
1369 const global_index = @intCast(u32, self.globals.values().len);1400 const name = try gpa.dupe(u8, sym_name);
1370 _ = global_index;1401 const global_index = try self.allocateGlobal();
1371 const gop = try self.globals.getOrPut(gpa, name);1402 self.globals.items[global_index] = current;
1372 defer if (gop.found_existing) gpa.free(name);1403 try self.resolver.putNoClobber(gpa, name, global_index);
13731404 if (sym.section_number == .UNDEFINED) {
1374 if (!gop.found_existing) {1405 try self.unresolved.putNoClobber(gpa, global_index, false);
1375 gop.value_ptr.* = current;1406 }
1376 // TODO undef + tentative
1377 return;1407 return;
1378 }1408 };
13791409
1380 log.debug("TODO finish resolveGlobalSymbols implementation", .{});1410 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;
1381}1416}
13821417
1383pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {1418pub 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...@@ -1415,7 +1450,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
14151450
1416 while (self.unresolved.popOrNull()) |entry| {1451 while (self.unresolved.popOrNull()) |entry| {
1417 assert(entry.value); // We only expect imports generated by the incremental linker for now.1452 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];
1419 if (self.imports_table.contains(global)) continue;1454 if (self.imports_table.contains(global)) continue;
14201455
1421 _ = try self.allocateImportEntry(global);1456 _ = try self.allocateImportEntry(global);
...@@ -1481,24 +1516,22 @@ pub fn getDeclVAddr(...@@ -1481,24 +1516,22 @@ pub fn getDeclVAddr(
1481}1516}
14821517
1483pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {1518pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
1484 const gpa = self.base.allocator;1519 if (self.resolver.get(name)) |global_index| {
1485 const sym_name = try gpa.dupe(u8, name);1520 return self.globals.items[global_index].sym_index;
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;
1494 }1521 }
14951522
1523 const gpa = self.base.allocator;
1496 const sym_index = try self.allocateSymbol();1524 const sym_index = try self.allocateSymbol();
1525 const global_index = try self.allocateGlobal();
1497 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };1526 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);
1498 const sym = self.getSymbolPtr(sym_loc);1530 const sym = self.getSymbolPtr(sym_loc);
1499 try self.setSymbolName(sym, sym_name);1531 try self.setSymbolName(sym, sym_name);
1500 sym.storage_class = .EXTERNAL;1532 sym.storage_class = .EXTERNAL;
1501 gop.value_ptr.* = sym_loc;1533
1534 try self.resolver.putNoClobber(gpa, sym_name, global_index);
1502 try self.unresolved.putNoClobber(gpa, global_index, true);1535 try self.unresolved.putNoClobber(gpa, global_index, true);
15031536
1504 return sym_index;1537 return sym_index;
...@@ -1607,14 +1640,15 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1607,14 +1640,15 @@ fn writeBaseRelocations(self: *Coff) !void {
1607}1640}
16081641
1609fn writeImportTable(self: *Coff) !void {1642fn writeImportTable(self: *Coff) !void {
1643 if (self.idata_section_index == null) return;
1644
1610 const gpa = self.base.allocator;1645 const gpa = self.base.allocator;
16111646
1612 const section = self.sections.get(self.idata_section_index.?);1647 const section = self.sections.get(self.idata_section_index.?);
1648 const last_atom = section.last_atom orelse return;
1649
1613 const iat_rva = section.header.virtual_address;1650 const iat_rva = section.header.virtual_address;
1614 const iat_size = blk: {1651 const iat_size = last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer
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 };
16181652
1619 const dll_name = "KERNEL32.dll";1653 const dll_name = "KERNEL32.dll";
16201654
...@@ -1975,7 +2009,8 @@ inline fn getSizeOfImage(self: Coff) u32 {...@@ -1975,7 +2009,8 @@ inline fn getSizeOfImage(self: Coff) u32 {
1975/// Returns symbol location corresponding to the set entrypoint (if any).2009/// Returns symbol location corresponding to the set entrypoint (if any).
1976pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {2010pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
1977 const entry_name = self.base.options.entry orelse "wWinMainCRTStartup"; // TODO this is incomplete2011 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];
1979}2014}
19802015
1981/// Returns pointer-to-symbol described by `sym_with_loc` descriptor.2016/// Returns pointer-to-symbol described by `sym_with_loc` descriptor.
...@@ -2100,9 +2135,9 @@ fn logSymtab(self: *Coff) void {...@@ -2100,9 +2135,9 @@ fn logSymtab(self: *Coff) void {
2100 }2135 }
21012136
2102 log.debug("globals table:", .{});2137 log.debug("globals table:", .{});
2103 for (self.globals.keys()) |name, id| {2138 for (self.globals.items) |sym_loc| {
2104 const value = self.globals.values()[id];2139 const sym_name = self.getSymbolName(sym_loc);
2105 log.debug(" {s} => %{d} in object({?d})", .{ name, value.sym_index, value.file });2140 log.debug(" {s} => %{d} in object({?d})", .{ sym_name, sym_loc.sym_index, sym_loc.file });
2106 }2141 }
21072142
2108 log.debug("GOT entries:", .{});2143 log.debug("GOT entries:", .{});