| ... | ... | @@ -53,10 +53,12 @@ reloc_section_index: ?u16 = null, |
| 53 | 53 | idata_section_index: ?u16 = null, |
| 54 | 54 | |
| 55 | 55 | locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, |
| 56 | | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, |
| 56 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| 57 | resolver: std.StringHashMapUnmanaged(u32) = .{}, |
| 57 | 58 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, |
| 58 | 59 | |
| 59 | 60 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 61 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 60 | 62 | |
| 61 | 63 | strtab: StringTable(.strtab) = .{}, |
| 62 | 64 | strtab_offset: ?u32 = null, |
| ... | ... | @@ -292,11 +294,15 @@ pub fn deinit(self: *Coff) void { |
| 292 | 294 | self.managed_atoms.deinit(gpa); |
| 293 | 295 | |
| 294 | 296 | self.locals.deinit(gpa); |
| 297 | self.globals.deinit(gpa); |
| 295 | 298 | |
| 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); |
| 298 | 305 | } |
| 299 | | self.globals.deinit(gpa); |
| 300 | 306 | |
| 301 | 307 | self.unresolved.deinit(gpa); |
| 302 | 308 | self.locals_free_list.deinit(gpa); |
| ... | ... | @@ -651,6 +657,30 @@ fn allocateSymbol(self: *Coff) !u32 { |
| 651 | 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 | 684 | pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 { |
| 655 | 685 | const gpa = self.base.allocator; |
| 656 | 686 | try self.got_entries.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -1340,7 +1370,7 @@ pub fn deleteExport(self: *Coff, exp: Export) void { |
| 1340 | 1370 | const sym = self.getSymbolPtr(sym_loc); |
| 1341 | 1371 | const sym_name = self.getSymbolName(sym_loc); |
| 1342 | 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 | 1374 | sym.* = .{ |
| 1345 | 1375 | .name = [_]u8{0} ** 8, |
| 1346 | 1376 | .value = 0, |
| ... | ... | @@ -1351,33 +1381,38 @@ pub fn deleteExport(self: *Coff, exp: Export) void { |
| 1351 | 1381 | }; |
| 1352 | 1382 | self.locals_free_list.append(gpa, sym_index) catch {}; |
| 1353 | 1383 | |
| 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 | }; |
| 1359 | 1391 | } |
| 1360 | 1392 | } |
| 1361 | 1393 | |
| 1362 | 1394 | fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { |
| 1363 | 1395 | const gpa = self.base.allocator; |
| 1364 | 1396 | const sym = self.getSymbol(current); |
| 1365 | | _ = sym; |
| 1366 | 1397 | const sym_name = self.getSymbolName(current); |
| 1367 | 1398 | |
| 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 | } |
| 1377 | 1407 | return; |
| 1378 | | } |
| 1408 | }; |
| 1379 | 1409 | |
| 1380 | 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 | 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 | 1450 | |
| 1416 | 1451 | while (self.unresolved.popOrNull()) |entry| { |
| 1417 | 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 | 1454 | if (self.imports_table.contains(global)) continue; |
| 1420 | 1455 | |
| 1421 | 1456 | _ = try self.allocateImportEntry(global); |
| ... | ... | @@ -1481,24 +1516,22 @@ pub fn getDeclVAddr( |
| 1481 | 1516 | } |
| 1482 | 1517 | |
| 1483 | 1518 | pub 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; |
| 1494 | 1521 | } |
| 1495 | 1522 | |
| 1523 | const gpa = self.base.allocator; |
| 1496 | 1524 | const sym_index = try self.allocateSymbol(); |
| 1525 | const global_index = try self.allocateGlobal(); |
| 1497 | 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 | 1530 | const sym = self.getSymbolPtr(sym_loc); |
| 1499 | 1531 | try self.setSymbolName(sym, sym_name); |
| 1500 | 1532 | sym.storage_class = .EXTERNAL; |
| 1501 | | gop.value_ptr.* = sym_loc; |
| 1533 | |
| 1534 | try self.resolver.putNoClobber(gpa, sym_name, global_index); |
| 1502 | 1535 | try self.unresolved.putNoClobber(gpa, global_index, true); |
| 1503 | 1536 | |
| 1504 | 1537 | return sym_index; |
| ... | ... | @@ -1607,14 +1640,15 @@ fn writeBaseRelocations(self: *Coff) !void { |
| 1607 | 1640 | } |
| 1608 | 1641 | |
| 1609 | 1642 | fn writeImportTable(self: *Coff) !void { |
| 1643 | if (self.idata_section_index == null) return; |
| 1644 | |
| 1610 | 1645 | const gpa = self.base.allocator; |
| 1611 | 1646 | |
| 1612 | 1647 | const section = self.sections.get(self.idata_section_index.?); |
| 1648 | const last_atom = section.last_atom orelse return; |
| 1649 | |
| 1613 | 1650 | 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 |
| 1618 | 1652 | |
| 1619 | 1653 | const dll_name = "KERNEL32.dll"; |
| 1620 | 1654 | |
| ... | ... | @@ -1975,7 +2009,8 @@ inline fn getSizeOfImage(self: Coff) u32 { |
| 1975 | 2009 | /// Returns symbol location corresponding to the set entrypoint (if any). |
| 1976 | 2010 | pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { |
| 1977 | 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 | 2016 | /// Returns pointer-to-symbol described by `sym_with_loc` descriptor. |
| ... | ... | @@ -2100,9 +2135,9 @@ fn logSymtab(self: *Coff) void { |
| 2100 | 2135 | } |
| 2101 | 2136 | |
| 2102 | 2137 | 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 }); |
| 2106 | 2141 | } |
| 2107 | 2142 | |
| 2108 | 2143 | log.debug("GOT entries:", .{}); |