| ... | @@ -53,10 +53,12 @@ reloc_section_index: ?u16 = null, | ... | @@ -53,10 +53,12 @@ reloc_section_index: ?u16 = null, |
| 53 | idata_section_index: ?u16 = null, | 53 | idata_section_index: ?u16 = null, |
| 54 | | 54 | |
| 55 | locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, | 55 | locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, |
| 56 | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, | 56 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| | 57 | resolver: std.StringHashMapUnmanaged(u32) = .{}, |
| 57 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, | 58 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, |
| 58 | | 59 | |
| 59 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 60 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| | 61 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 60 | | 62 | |
| 61 | strtab: StringTable(.strtab) = .{}, | 63 | strtab: StringTable(.strtab) = .{}, |
| 62 | strtab_offset: ?u32 = null, | 64 | strtab_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); |
| 293 | | 295 | |
| 294 | self.locals.deinit(gpa); | 296 | self.locals.deinit(gpa); |
| | 297 | self.globals.deinit(gpa); |
| 295 | | 298 | |
| 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); | | |
| 300 | | 306 | |
| 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 | } |
| 653 | | 659 | |
| | 660 | fn 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 | |
| 654 | pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 { | 684 | pub 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 {}; |
| 1353 | | 1383 | |
| 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 | } |
| 1361 | | 1393 | |
| 1362 | fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { | 1394 | fn 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); |
| 1367 | | 1398 | |
| 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); |
| 1373 | | 1404 | 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 | }; |
| 1379 | | 1409 | |
| 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 | } |
| 1382 | | 1417 | |
| 1383 | pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void { | 1418 | pub 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 |
| 1415 | | 1450 | |
| 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; |
| 1420 | | 1455 | |
| 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 | } |
| 1482 | | 1517 | |
| 1483 | pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 { | 1518 | pub 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 | } |
| 1495 | | 1522 | |
| | 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); |
| 1503 | | 1536 | |
| 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 | } |
| 1608 | | 1641 | |
| 1609 | fn writeImportTable(self: *Coff) !void { | 1642 | fn 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; |
| 1611 | | 1646 | |
| 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 | }; | | |
| 1618 | | 1652 | |
| 1619 | const dll_name = "KERNEL32.dll"; | 1653 | const dll_name = "KERNEL32.dll"; |
| 1620 | | 1654 | |
| ... | @@ -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). |
| 1976 | pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { | 2010 | pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { |
| 1977 | const entry_name = self.base.options.entry orelse "wWinMainCRTStartup"; // TODO this is incomplete | 2011 | 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 | } |
| 1980 | | 2015 | |
| 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 | } |
| 2101 | | 2136 | |
| 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 | } |
| 2107 | | 2142 | |
| 2108 | log.debug("GOT entries:", .{}); | 2143 | log.debug("GOT entries:", .{}); |