authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-31 21:15:23+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-07 22:42:55+02:00
log1ab149c5fc474e73cb52872e11cbd2b916961ede
treecdc61d8adf4f353e6c92919a4560a38ddc2ba738
parent51fba37af70283427a7ef5d2f2fd39f97aaa1e35

coff: create import atoms and matching bindings


2 files changed, 131 insertions(+), 6 deletions(-)

src/link/Coff.zig+121-6
......@@ -51,9 +51,11 @@ got_section_index: ?u16 = null,
5151rdata_section_index: ?u16 = null,
5252data_section_index: ?u16 = null,
5353reloc_section_index: ?u16 = null,
54idata_section_index: ?u16 = null,
5455
5556locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
5657globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
58unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},
5759
5860locals_free_list: std.ArrayListUnmanaged(u32) = .{},
5961
......@@ -63,6 +65,9 @@ strtab_offset: ?u32 = null,
6365got_entries: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{},
6466got_entries_free_list: std.ArrayListUnmanaged(u32) = .{},
6567
68imports_table: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{},
69imports_table_free_list: std.ArrayListUnmanaged(u32) = .{},
70
6671/// Virtual address of the entry point procedure relative to image base.
6772entry_addr: ?u32 = null,
6873
......@@ -109,6 +114,11 @@ relocs: RelocTable = .{},
109114/// this will be a table indexed by index into the list of Atoms.
110115base_relocs: BaseRelocationTable = .{},
111116
117/// A table of bindings indexed by the owning them `Atom`.
118/// Note that once we refactor `Atom`'s lifetime and ownership rules,
119/// this will be a table indexed by index into the list of Atoms.
120bindings: BindingTable = .{},
121
112122pub const Reloc = struct {
113123 @"type": enum {
114124 got,
......@@ -124,6 +134,7 @@ pub const Reloc = struct {
124134
125135const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc));
126136const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32));
137const BindingTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(SymbolWithLoc));
127138const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));
128139
129140const default_file_alignment: u16 = 0x200;
......@@ -269,10 +280,13 @@ pub fn deinit(self: *Coff) void {
269280
270281 self.locals.deinit(gpa);
271282 self.globals.deinit(gpa);
283 self.unresolved.deinit(gpa);
272284 self.locals_free_list.deinit(gpa);
273285 self.strtab.deinit(gpa);
274286 self.got_entries.deinit(gpa);
275287 self.got_entries_free_list.deinit(gpa);
288 self.imports_table.deinit(gpa);
289 self.imports_table_free_list.deinit(gpa);
276290 self.decls.deinit(gpa);
277291 self.atom_by_index_table.deinit(gpa);
278292
......@@ -299,6 +313,14 @@ pub fn deinit(self: *Coff) void {
299313 }
300314 self.base_relocs.deinit(gpa);
301315 }
316
317 {
318 var it = self.bindings.valueIterator();
319 while (it.next()) |bindings| {
320 bindings.deinit(gpa);
321 }
322 self.bindings.deinit(gpa);
323 }
302324}
303325
304326fn populateMissingMetadata(self: *Coff) !void {
......@@ -420,7 +442,7 @@ fn populateMissingMetadata(self: *Coff) !void {
420442 .number_of_linenumbers = 0,
421443 .flags = .{
422444 .CNT_INITIALIZED_DATA = 1,
423 .MEM_PURGEABLE = 1,
445 .MEM_DISCARDABLE = 1,
424446 .MEM_READ = 1,
425447 },
426448 };
......@@ -428,6 +450,30 @@ fn populateMissingMetadata(self: *Coff) !void {
428450 try self.sections.append(gpa, .{ .header = header });
429451 }
430452
453 if (self.idata_section_index == null) {
454 self.idata_section_index = @intCast(u16, self.sections.slice().len);
455 const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize();
456 const off = self.findFreeSpace(file_size, self.page_size);
457 log.debug("found .idata free space 0x{x} to 0x{x}", .{ off, off + file_size });
458 var header = coff.SectionHeader{
459 .name = undefined,
460 .virtual_size = file_size,
461 .virtual_address = off,
462 .size_of_raw_data = file_size,
463 .pointer_to_raw_data = off,
464 .pointer_to_relocations = 0,
465 .pointer_to_linenumbers = 0,
466 .number_of_relocations = 0,
467 .number_of_linenumbers = 0,
468 .flags = .{
469 .CNT_INITIALIZED_DATA = 1,
470 .MEM_READ = 1,
471 },
472 };
473 try self.setSectionName(&header, ".idata");
474 try self.sections.append(gpa, .{ .header = header });
475 }
476
431477 if (self.strtab_offset == null) {
432478 try self.strtab.buffer.append(gpa, 0);
433479 self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1);
......@@ -626,6 +672,27 @@ pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {
626672 return index;
627673}
628674
675pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 {
676 const gpa = self.base.allocator;
677 try self.imports_table.ensureUnusedCapacity(gpa, 1);
678 const index: u32 = blk: {
679 if (self.imports_table_free_list.popOrNull()) |index| {
680 log.debug(" (reusing import entry index {d})", .{index});
681 if (self.imports_table.getIndex(target)) |existing| {
682 assert(existing == index);
683 }
684 break :blk index;
685 } else {
686 log.debug(" (allocating import entry at index {d})", .{self.imports_table.keys().len});
687 const index = @intCast(u32, self.imports_table.keys().len);
688 self.imports_table.putAssumeCapacityNoClobber(target, 0);
689 break :blk index;
690 }
691 };
692 self.imports_table.keys()[index] = target;
693 return index;
694}
695
629696fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
630697 const gpa = self.base.allocator;
631698 const atom = try gpa.create(Atom);
......@@ -666,6 +733,32 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
666733 return atom;
667734}
668735
736fn createImportAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
737 const gpa = self.base.allocator;
738 const atom = try gpa.create(Atom);
739 errdefer gpa.destroy(atom);
740 atom.* = Atom.empty;
741 atom.sym_index = try self.allocateSymbol();
742 atom.size = @sizeOf(u64);
743 atom.alignment = @alignOf(u64);
744
745 try self.managed_atoms.append(gpa, atom);
746 try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom);
747 self.imports_table.getPtr(target).?.* = atom.sym_index;
748
749 const sym = atom.getSymbolPtr(self);
750 sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1);
751 sym.value = try self.allocateAtom(atom, atom.size, atom.alignment);
752
753 log.debug("allocated import atom at 0x{x}", .{sym.value});
754
755 const target_sym = self.getSymbol(target);
756 assert(target_sym.section_number == .UNDEFINED);
757 try atom.addBinding(self, target);
758
759 return atom;
760}
761
669762fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 {
670763 const sym = atom.getSymbol(self);
671764 const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value;
......@@ -691,7 +784,7 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void {
691784 try self.resolveRelocs(atom);
692785}
693786
694fn writeGotAtom(self: *Coff, atom: *Atom) !void {
787fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void {
695788 switch (self.ptr_width) {
696789 .p32 => {
697790 var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32);
......@@ -718,7 +811,12 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
718811 const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue;
719812 break :blk got_atom.getSymbol(self).value;
720813 },
721 .direct => self.getSymbol(reloc.target).value,
814 .direct => blk: {
815 if (self.getImportAtomForSymbol(reloc.target)) |import_atom| {
816 break :blk import_atom.getSymbol(self).value;
817 }
818 break :blk self.getSymbol(reloc.target).value;
819 },
722820 };
723821 const target_vaddr_with_addend = target_vaddr + reloc.addend;
724822
......@@ -971,7 +1069,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
9711069 sym.value = vaddr;
9721070 log.debug(" (updating GOT entry)", .{});
9731071 const got_atom = self.getGotAtomForSymbol(.{ .sym_index = atom.sym_index, .file = null }).?;
974 try self.writeGotAtom(got_atom);
1072 try self.writePtrWidthAtom(got_atom);
9751073 }
9761074 } else if (code_len < atom.size) {
9771075 self.shrinkAtom(atom, code_len);
......@@ -992,7 +1090,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
9921090 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };
9931091 _ = try self.allocateGotEntry(got_target);
9941092 const got_atom = try self.createGotAtom(got_target);
995 try self.writeGotAtom(got_atom);
1093 try self.writePtrWidthAtom(got_atom);
9961094 }
9971095
9981096 try self.writeAtom(atom, code);
......@@ -1227,6 +1325,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
12271325 sub_prog_node.activate();
12281326 defer sub_prog_node.end();
12291327
1328 while (self.unresolved.popOrNull()) |entry| {
1329 assert(entry.value); // We only expect imports generated by the incremental linker for now.
1330 const global = self.globals.values()[entry.key];
1331 if (self.imports_table.contains(global)) continue;
1332
1333 _ = try self.allocateImportEntry(global);
1334 const import_atom = try self.createImportAtom(global);
1335 try self.writePtrWidthAtom(import_atom);
1336 }
1337
12301338 if (build_options.enable_logging) {
12311339 self.logSymtab();
12321340 }
......@@ -1272,7 +1380,6 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
12721380 const gpa = self.base.allocator;
12731381 const sym_name = try gpa.dupe(u8, name);
12741382 const global_index = @intCast(u32, self.globals.values().len);
1275 _ = global_index;
12761383 const gop = try self.globals.getOrPut(gpa, sym_name);
12771384 defer if (gop.found_existing) gpa.free(sym_name);
12781385
......@@ -1288,6 +1395,7 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
12881395 try self.setSymbolName(sym, sym_name);
12891396 sym.storage_class = .EXTERNAL;
12901397 gop.value_ptr.* = sym_loc;
1398 try self.unresolved.putNoClobber(gpa, global_index, true);
12911399
12921400 return sym_index;
12931401}
......@@ -1676,6 +1784,13 @@ pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
16761784 return self.atom_by_index_table.get(got_index);
16771785}
16781786
1787/// Returns import atom that references `sym_with_loc` if one exists.
1788/// Returns null otherwise.
1789pub fn getImportAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
1790 const imports_index = self.imports_table.get(sym_loc) orelse return null;
1791 return self.atom_by_index_table.get(imports_index);
1792}
1793
16791794fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {
16801795 if (name.len <= 8) {
16811796 mem.copy(u8, &header.name, name);
src/link/Coff/Atom.zig+10
......@@ -118,3 +118,13 @@ pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void {
118118 }
119119 try gop.value_ptr.append(gpa, offset);
120120}
121
122pub fn addBinding(self: *Atom, coff_file: *Coff, target: SymbolWithLoc) !void {
123 const gpa = coff_file.base.allocator;
124 log.debug(" (adding binding to target %{d} in %{d})", .{ target.sym_index, self.sym_index });
125 const gop = try coff_file.bindings.getOrPut(gpa, self);
126 if (!gop.found_existing) {
127 gop.value_ptr.* = .{};
128 }
129 try gop.value_ptr.append(gpa, target);
130}