authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-01-31 20:27:17+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-01-31 20:27:17+01:00
logc430e9afa7b050400b9703360a0af4ab824335ce
tree1a91f7abd8ca2c92100a713e5978c16cfe845a9c
parent4404c4d20094bb5021aac4a047cd33b6c24b9a9b

link: make Coff atoms fully owned by the linker


12 files changed, 350 insertions(+), 275 deletions(-)

src/Module.zig+3-3
......@@ -5274,7 +5274,7 @@ pub fn clearDecl(
52745274 // TODO instead of a union, put this memory trailing Decl objects,
52755275 // and allow it to be variably sized.
52765276 decl.link = switch (mod.comp.bin_file.tag) {
5277 .coff => .{ .coff = link.File.Coff.Atom.empty },
5277 .coff => .{ .coff = {} },
52785278 .elf => .{ .elf = {} },
52795279 .macho => .{ .macho = {} },
52805280 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
......@@ -5390,7 +5390,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void
53905390 wasm.deleteExport(exp.link.wasm);
53915391 }
53925392 if (mod.comp.bin_file.cast(link.File.Coff)) |coff| {
5393 coff.deleteExport(exp.link.coff);
5393 coff.deleteDeclExport(decl_index, exp.options.name);
53945394 }
53955395 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
53965396 failed_kv.value.destroy(mod.gpa);
......@@ -5694,7 +5694,7 @@ pub fn allocateNewDecl(
56945694 .zir_decl_index = 0,
56955695 .src_scope = src_scope,
56965696 .link = switch (mod.comp.bin_file.tag) {
5697 .coff => .{ .coff = link.File.Coff.Atom.empty },
5697 .coff => .{ .coff = {} },
56985698 .elf => .{ .elf = {} },
56995699 .macho => .{ .macho = {} },
57005700 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
src/Sema.zig+1-1
......@@ -5565,7 +5565,7 @@ pub fn analyzeExport(
55655565 },
55665566 .src = src,
55675567 .link = switch (mod.comp.bin_file.tag) {
5568 .coff => .{ .coff = .{} },
5568 .coff => .{ .coff = {} },
55695569 .elf => .{ .elf = {} },
55705570 .macho => .{ .macho = {} },
55715571 .plan9 => .{ .plan9 = null },
src/arch/aarch64/CodeGen.zig+26-16
......@@ -4019,15 +4019,17 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
40194019 .direct => .load_memory_ptr_direct,
40204020 .import => unreachable,
40214021 };
4022 const mod = self.bin_file.options.module.?;
4023 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
40244022 const atom_index = switch (self.bin_file.tag) {
40254023 .macho => blk: {
40264024 const macho_file = self.bin_file.cast(link.File.MachO).?;
40274025 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
40284026 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
40294027 },
4030 .coff => owner_decl.link.coff.getSymbolIndex().?,
4028 .coff => blk: {
4029 const coff_file = self.bin_file.cast(link.File.Coff).?;
4030 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4031 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
4032 },
40314033 else => unreachable, // unsupported target format
40324034 };
40334035 _ = try self.addInst(.{
......@@ -4322,11 +4324,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
43224324 },
43234325 });
43244326 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4325 try fn_owner_decl.link.coff.ensureInitialized(coff_file);
4327 const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
4328 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
43264329 try self.genSetReg(Type.initTag(.u64), .x30, .{
43274330 .linker_load = .{
43284331 .type = .got,
4329 .sym_index = fn_owner_decl.link.coff.getSymbolIndex().?,
4332 .sym_index = sym_index,
43304333 },
43314334 });
43324335 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
......@@ -5496,15 +5499,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
54965499 .direct => .load_memory_ptr_direct,
54975500 .import => unreachable,
54985501 };
5499 const mod = self.bin_file.options.module.?;
5500 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
55015502 const atom_index = switch (self.bin_file.tag) {
55025503 .macho => blk: {
55035504 const macho_file = self.bin_file.cast(link.File.MachO).?;
55045505 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
55055506 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
55065507 },
5507 .coff => owner_decl.link.coff.getSymbolIndex().?,
5508 .coff => blk: {
5509 const coff_file = self.bin_file.cast(link.File.Coff).?;
5510 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5511 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
5512 },
55085513 else => unreachable, // unsupported target format
55095514 };
55105515 _ = try self.addInst(.{
......@@ -5614,15 +5619,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
56145619 .direct => .load_memory_direct,
56155620 .import => .load_memory_import,
56165621 };
5617 const mod = self.bin_file.options.module.?;
5618 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
56195622 const atom_index = switch (self.bin_file.tag) {
56205623 .macho => blk: {
56215624 const macho_file = self.bin_file.cast(link.File.MachO).?;
56225625 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
56235626 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
56245627 },
5625 .coff => owner_decl.link.coff.getSymbolIndex().?,
5628 .coff => blk: {
5629 const coff_file = self.bin_file.cast(link.File.Coff).?;
5630 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5631 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
5632 },
56265633 else => unreachable, // unsupported target format
56275634 };
56285635 _ = try self.addInst(.{
......@@ -5812,15 +5819,17 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
58125819 .direct => .load_memory_ptr_direct,
58135820 .import => unreachable,
58145821 };
5815 const mod = self.bin_file.options.module.?;
5816 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
58175822 const atom_index = switch (self.bin_file.tag) {
58185823 .macho => blk: {
58195824 const macho_file = self.bin_file.cast(link.File.MachO).?;
58205825 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
58215826 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
58225827 },
5823 .coff => owner_decl.link.coff.getSymbolIndex().?,
5828 .coff => blk: {
5829 const coff_file = self.bin_file.cast(link.File.Coff).?;
5830 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5831 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
5832 },
58245833 else => unreachable, // unsupported target format
58255834 };
58265835 _ = try self.addInst(.{
......@@ -6150,10 +6159,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
61506159 .sym_index = sym_index,
61516160 } };
61526161 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6153 try decl.link.coff.ensureInitialized(coff_file);
6162 const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index);
6163 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
61546164 return MCValue{ .linker_load = .{
61556165 .type = .got,
6156 .sym_index = decl.link.coff.getSymbolIndex().?,
6166 .sym_index = sym_index,
61576167 } };
61586168 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
61596169 try p9.seeDecl(decl_index);
src/arch/aarch64/Emit.zig+3-3
......@@ -919,7 +919,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
919919 },
920920 });
921921 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
922 const atom = coff_file.getAtomForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
922 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
923923 const target = switch (tag) {
924924 .load_memory_got,
925925 .load_memory_ptr_got,
......@@ -929,7 +929,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
929929 .load_memory_import => coff_file.getGlobalByIndex(data.sym_index),
930930 else => unreachable,
931931 };
932 try atom.addRelocation(coff_file, .{
932 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
933933 .target = target,
934934 .offset = offset,
935935 .addend = 0,
......@@ -946,7 +946,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
946946 else => unreachable,
947947 },
948948 });
949 try atom.addRelocation(coff_file, .{
949 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
950950 .target = target,
951951 .offset = offset + 4,
952952 .addend = 0,
src/arch/x86_64/CodeGen.zig+8-8
......@@ -2668,13 +2668,12 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
26682668 switch (ptr) {
26692669 .linker_load => |load_struct| {
26702670 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));
2671 const mod = self.bin_file.options.module.?;
2672 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
26732671 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
26742672 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
26752673 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
2676 } else if (self.bin_file.cast(link.File.Coff)) |_| blk: {
2677 break :blk fn_owner_decl.link.coff.getSymbolIndex().?;
2674 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
2675 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
2676 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
26782677 } else unreachable;
26792678 const flags: u2 = switch (load_struct.type) {
26802679 .got => 0b00,
......@@ -4009,8 +4008,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
40094008 .data = .{ .imm = got_addr },
40104009 });
40114010 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4012 try fn_owner_decl.link.coff.ensureInitialized(coff_file);
4013 const sym_index = fn_owner_decl.link.coff.getSymbolIndex().?;
4011 const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
4012 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
40144013 try self.genSetReg(Type.initTag(.usize), .rax, .{
40154014 .linker_load = .{
40164015 .type = .got,
......@@ -6733,10 +6732,11 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
67336732 .sym_index = sym_index,
67346733 } };
67356734 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6736 try decl.link.coff.ensureInitialized(coff_file);
6735 const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index);
6736 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
67376737 return MCValue{ .linker_load = .{
67386738 .type = .got,
6739 .sym_index = decl.link.coff.getSymbolIndex().?,
6739 .sym_index = sym_index,
67406740 } };
67416741 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
67426742 try p9.seeDecl(decl_index);
src/arch/x86_64/Emit.zig+4-4
......@@ -1011,8 +1011,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
10111011 .length = 2,
10121012 });
10131013 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
1014 const atom = coff_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
1015 try atom.addRelocation(coff_file, .{
1014 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
1015 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
10161016 .type = switch (ops.flags) {
10171017 0b00 => .got,
10181018 0b01 => .direct,
......@@ -1152,9 +1152,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
11521152 });
11531153 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
11541154 // Add relocation to the decl.
1155 const atom = coff_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
1155 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
11561156 const target = coff_file.getGlobalByIndex(relocation.sym_index);
1157 try atom.addRelocation(coff_file, .{
1157 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
11581158 .type = .direct,
11591159 .target = target,
11601160 .offset = offset,
src/link.zig+2-2
......@@ -263,7 +263,7 @@ pub const File = struct {
263263
264264 pub const LinkBlock = union {
265265 elf: void,
266 coff: Coff.Atom,
266 coff: void,
267267 macho: void,
268268 plan9: Plan9.DeclBlock,
269269 c: void,
......@@ -285,7 +285,7 @@ pub const File = struct {
285285
286286 pub const Export = union {
287287 elf: void,
288 coff: Coff.Export,
288 coff: void,
289289 macho: void,
290290 plan9: Plan9.Export,
291291 c: void,
src/link/Coff.zig+256-204
......@@ -79,13 +79,13 @@ entry_addr: ?u32 = null,
7979/// We store them here so that we can properly dispose of any allocated
8080/// memory within the atom in the incremental linker.
8181/// TODO consolidate this.
82decls: std.AutoHashMapUnmanaged(Module.Decl.Index, ?u16) = .{},
82decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
8383
8484/// List of atoms that are either synthetic or map directly to the Zig source program.
85managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
85atoms: std.ArrayListUnmanaged(Atom) = .{},
8686
8787/// Table of atoms indexed by the symbol index.
88atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
88atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
8989
9090/// Table of unnamed constants associated with a parent `Decl`.
9191/// We store them here so that we can free the constants whenever the `Decl`
......@@ -124,9 +124,9 @@ const Entry = struct {
124124 sym_index: u32,
125125};
126126
127const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation));
128const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32));
129const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));
127const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
128const BaseRelocationTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
129const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
130130
131131const default_file_alignment: u16 = 0x200;
132132const default_size_of_stack_reserve: u32 = 0x1000000;
......@@ -137,7 +137,7 @@ const default_size_of_heap_commit: u32 = 0x1000;
137137const Section = struct {
138138 header: coff.SectionHeader,
139139
140 last_atom: ?*Atom = null,
140 last_atom_index: ?Atom.Index = null,
141141
142142 /// A list of atoms that have surplus capacity. This list can have false
143143 /// positives, as functions grow and shrink over time, only sometimes being added
......@@ -154,7 +154,34 @@ const Section = struct {
154154 /// overcapacity can be negative. A simple way to have negative overcapacity is to
155155 /// allocate a fresh atom, which will have ideal capacity, and then grow it
156156 /// by 1 byte. It will then have -1 overcapacity.
157 free_list: std.ArrayListUnmanaged(*Atom) = .{},
157 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
158};
159
160const DeclMetadata = struct {
161 atom: Atom.Index,
162 section: u16,
163 /// A list of all exports aliases of this Decl.
164 exports: std.ArrayListUnmanaged(u32) = .{},
165
166 fn getExport(m: DeclMetadata, coff_file: *const Coff, name: []const u8) ?u32 {
167 for (m.exports.items) |exp| {
168 if (mem.eql(u8, name, coff_file.getSymbolName(.{
169 .sym_index = exp,
170 .file = null,
171 }))) return exp;
172 }
173 return null;
174 }
175
176 fn getExportPtr(m: *DeclMetadata, coff_file: *Coff, name: []const u8) ?*u32 {
177 for (m.exports.items) |*exp| {
178 if (mem.eql(u8, name, coff_file.getSymbolName(.{
179 .sym_index = exp.*,
180 .file = null,
181 }))) return exp;
182 }
183 return null;
184 }
158185};
159186
160187pub const PtrWidth = enum {
......@@ -170,10 +197,6 @@ pub const PtrWidth = enum {
170197};
171198pub const SrcFn = void;
172199
173pub const Export = struct {
174 sym_index: ?u32 = null,
175};
176
177200pub const SymbolWithLoc = struct {
178201 // Index into the respective symbol table.
179202 sym_index: u32,
......@@ -271,11 +294,7 @@ pub fn deinit(self: *Coff) void {
271294 }
272295 self.sections.deinit(gpa);
273296
274 for (self.managed_atoms.items) |atom| {
275 gpa.destroy(atom);
276 }
277 self.managed_atoms.deinit(gpa);
278
297 self.atoms.deinit(gpa);
279298 self.locals.deinit(gpa);
280299 self.globals.deinit(gpa);
281300
......@@ -297,7 +316,15 @@ pub fn deinit(self: *Coff) void {
297316 self.imports.deinit(gpa);
298317 self.imports_free_list.deinit(gpa);
299318 self.imports_table.deinit(gpa);
300 self.decls.deinit(gpa);
319
320 {
321 var it = self.decls.iterator();
322 while (it.next()) |entry| {
323 entry.value_ptr.exports.deinit(gpa);
324 }
325 self.decls.deinit(gpa);
326 }
327
301328 self.atom_by_index_table.deinit(gpa);
302329
303330 {
......@@ -461,17 +488,18 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {
461488 // TODO: enforce order by increasing VM addresses in self.sections container.
462489 // This is required by the loader anyhow as far as I can tell.
463490 for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| {
464 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id + 1 + next_sect_id];
491 const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id];
465492 next_header.virtual_address += diff;
466493
467 if (maybe_last_atom.*) |last_atom| {
468 var atom = last_atom;
494 if (maybe_last_atom_index) |last_atom_index| {
495 var atom_index = last_atom_index;
469496 while (true) {
497 const atom = self.getAtom(atom_index);
470498 const sym = atom.getSymbolPtr(self);
471499 sym.value += diff;
472500
473 if (atom.prev) |prev| {
474 atom = prev;
501 if (atom.prev_index) |prev_index| {
502 atom_index = prev_index;
475503 } else break;
476504 }
477505 }
......@@ -480,14 +508,15 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {
480508 header.virtual_size = increased_size;
481509}
482510
483fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 {
511fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
484512 const tracy = trace(@src());
485513 defer tracy.end();
486514
515 const atom = self.getAtom(atom_index);
487516 const sect_id = @enumToInt(atom.getSymbol(self).section_number) - 1;
488517 const header = &self.sections.items(.header)[sect_id];
489518 const free_list = &self.sections.items(.free_list)[sect_id];
490 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];
519 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
491520 const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size;
492521
493522 // We use these to indicate our intention to update metadata, placing the new atom,
......@@ -495,7 +524,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
495524 // It would be simpler to do it inside the for loop below, but that would cause a
496525 // problem if an error was returned later in the function. So this action
497526 // is actually carried out at the end of the function, when errors are no longer possible.
498 var atom_placement: ?*Atom = null;
527 var atom_placement: ?Atom.Index = null;
499528 var free_list_removal: ?usize = null;
500529
501530 // First we look for an appropriately sized free list node.
......@@ -503,7 +532,8 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
503532 var vaddr = blk: {
504533 var i: usize = 0;
505534 while (i < free_list.items.len) {
506 const big_atom = free_list.items[i];
535 const big_atom_index = free_list.items[i];
536 const big_atom = self.getAtom(big_atom_index);
507537 // We now have a pointer to a live atom that has too much capacity.
508538 // Is it enough that we could fit this new atom?
509539 const sym = big_atom.getSymbol(self);
......@@ -531,34 +561,43 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
531561 const keep_free_list_node = remaining_capacity >= min_text_capacity;
532562
533563 // Set up the metadata to be updated, after errors are no longer possible.
534 atom_placement = big_atom;
564 atom_placement = big_atom_index;
535565 if (!keep_free_list_node) {
536566 free_list_removal = i;
537567 }
538568 break :blk new_start_vaddr;
539 } else if (maybe_last_atom.*) |last| {
569 } else if (maybe_last_atom_index.*) |last_index| {
570 const last = self.getAtom(last_index);
540571 const last_symbol = last.getSymbol(self);
541572 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
542573 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;
543574 const new_start_vaddr = mem.alignForwardGeneric(u32, ideal_capacity_end_vaddr, alignment);
544 atom_placement = last;
575 atom_placement = last_index;
545576 break :blk new_start_vaddr;
546577 } else {
547578 break :blk mem.alignForwardGeneric(u32, header.virtual_address, alignment);
548579 }
549580 };
550581
551 const expand_section = atom_placement == null or atom_placement.?.next == null;
582 const expand_section = if (atom_placement) |placement_index|
583 self.getAtom(placement_index).next_index == null
584 else
585 true;
552586 if (expand_section) {
553587 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
554588 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;
555589 if (needed_size > sect_capacity) {
556590 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
557 const current_size = if (maybe_last_atom.*) |last_atom| blk: {
591 const current_size = if (maybe_last_atom_index.*) |last_atom_index| blk: {
592 const last_atom = self.getAtom(last_atom_index);
558593 const sym = last_atom.getSymbol(self);
559594 break :blk (sym.value + last_atom.size) - header.virtual_address;
560595 } else 0;
561 log.debug("moving {s} from 0x{x} to 0x{x}", .{ self.getSectionName(header), header.pointer_to_raw_data, new_offset });
596 log.debug("moving {s} from 0x{x} to 0x{x}", .{
597 self.getSectionName(header),
598 header.pointer_to_raw_data,
599 new_offset,
600 });
562601 const amt = try self.base.file.?.copyRangeAll(
563602 header.pointer_to_raw_data,
564603 self.base.file.?,
......@@ -577,26 +616,34 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
577616
578617 header.virtual_size = @max(header.virtual_size, needed_size);
579618 header.size_of_raw_data = needed_size;
580 maybe_last_atom.* = atom;
619 maybe_last_atom_index.* = atom_index;
581620 }
582621
583 atom.size = new_atom_size;
584 atom.alignment = alignment;
622 {
623 const atom_ptr = self.getAtomPtr(atom_index);
624 atom_ptr.size = new_atom_size;
625 atom_ptr.alignment = alignment;
626 }
585627
586 if (atom.prev) |prev| {
587 prev.next = atom.next;
628 if (atom.prev_index) |prev_index| {
629 const prev = self.getAtomPtr(prev_index);
630 prev.next_index = atom.next_index;
588631 }
589 if (atom.next) |next| {
590 next.prev = atom.prev;
632 if (atom.next_index) |next_index| {
633 const next = self.getAtomPtr(next_index);
634 next.prev_index = atom.prev_index;
591635 }
592636
593 if (atom_placement) |big_atom| {
594 atom.prev = big_atom;
595 atom.next = big_atom.next;
596 big_atom.next = atom;
637 if (atom_placement) |big_atom_index| {
638 const big_atom = self.getAtomPtr(big_atom_index);
639 const atom_ptr = self.getAtomPtr(atom_index);
640 atom_ptr.prev_index = big_atom_index;
641 atom_ptr.next_index = big_atom.next_index;
642 big_atom.next_index = atom_index;
597643 } else {
598 atom.prev = null;
599 atom.next = null;
644 const atom_ptr = self.getAtomPtr(atom_index);
645 atom_ptr.prev_index = null;
646 atom_ptr.next_index = null;
600647 }
601648 if (free_list_removal) |i| {
602649 _ = free_list.swapRemove(i);
......@@ -701,24 +748,37 @@ pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 {
701748 return index;
702749}
703750
704fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
751pub fn createAtom(self: *Coff) !Atom.Index {
705752 const gpa = self.base.allocator;
706 const atom = try gpa.create(Atom);
707 errdefer gpa.destroy(atom);
708 atom.* = Atom.empty;
709 try atom.ensureInitialized(self);
753 const atom_index = @intCast(Atom.Index, self.atoms.items.len);
754 const atom = try self.atoms.addOne(gpa);
755 const sym_index = try self.allocateSymbol();
756 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
757 atom.* = .{
758 .sym_index = sym_index,
759 .file = null,
760 .size = 0,
761 .alignment = 0,
762 .prev_index = null,
763 .next_index = null,
764 };
765 log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index });
766 return atom_index;
767}
768
769fn createGotAtom(self: *Coff, target: SymbolWithLoc) !Atom.Index {
770 const atom_index = try self.createAtom();
771 const atom = self.getAtomPtr(atom_index);
710772 atom.size = @sizeOf(u64);
711773 atom.alignment = @alignOf(u64);
712774
713 try self.managed_atoms.append(gpa, atom);
714
715775 const sym = atom.getSymbolPtr(self);
716776 sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1);
717 sym.value = try self.allocateAtom(atom, atom.size, atom.alignment);
777 sym.value = try self.allocateAtom(atom_index, atom.size, atom.alignment);
718778
719779 log.debug("allocated GOT atom at 0x{x}", .{sym.value});
720780
721 try atom.addRelocation(self, .{
781 try Atom.addRelocation(self, atom_index, .{
722782 .type = .direct,
723783 .target = target,
724784 .offset = 0,
......@@ -732,49 +792,46 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
732792 .UNDEFINED => @panic("TODO generate a binding for undefined GOT target"),
733793 .ABSOLUTE => {},
734794 .DEBUG => unreachable, // not possible
735 else => try atom.addBaseRelocation(self, 0),
795 else => try Atom.addBaseRelocation(self, atom_index, 0),
736796 }
737797
738 return atom;
798 return atom_index;
739799}
740800
741fn createImportAtom(self: *Coff) !*Atom {
742 const gpa = self.base.allocator;
743 const atom = try gpa.create(Atom);
744 errdefer gpa.destroy(atom);
745 atom.* = Atom.empty;
746 try atom.ensureInitialized(self);
801fn createImportAtom(self: *Coff) !Atom.Index {
802 const atom_index = try self.createAtom();
803 const atom = self.getAtomPtr(atom_index);
747804 atom.size = @sizeOf(u64);
748805 atom.alignment = @alignOf(u64);
749806
750 try self.managed_atoms.append(gpa, atom);
751
752807 const sym = atom.getSymbolPtr(self);
753808 sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1);
754 sym.value = try self.allocateAtom(atom, atom.size, atom.alignment);
809 sym.value = try self.allocateAtom(atom_index, atom.size, atom.alignment);
755810
756811 log.debug("allocated import atom at 0x{x}", .{sym.value});
757812
758 return atom;
813 return atom_index;
759814}
760815
761fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 {
816fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
817 const atom = self.getAtom(atom_index);
762818 const sym = atom.getSymbol(self);
763819 const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value;
764820 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
765821 if (!need_realloc) return sym.value;
766 return self.allocateAtom(atom, new_atom_size, alignment);
822 return self.allocateAtom(atom_index, new_atom_size, alignment);
767823}
768824
769fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u32) void {
825fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void {
770826 _ = self;
771 _ = atom;
827 _ = atom_index;
772828 _ = new_block_size;
773829 // TODO check the new capacity, and if it crosses the size threshold into a big enough
774830 // capacity, insert a free list node for it.
775831}
776832
777fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void {
833fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void {
834 const atom = self.getAtom(atom_index);
778835 const sym = atom.getSymbol(self);
779836 const section = self.sections.get(@enumToInt(sym.section_number) - 1);
780837 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
......@@ -784,18 +841,18 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void {
784841 file_offset + code.len,
785842 });
786843 try self.base.file.?.pwriteAll(code, file_offset);
787 try self.resolveRelocs(atom);
844 try self.resolveRelocs(atom_index);
788845}
789846
790fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void {
847fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {
791848 switch (self.ptr_width) {
792849 .p32 => {
793850 var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32);
794 try self.writeAtom(atom, &buffer);
851 try self.writeAtom(atom_index, &buffer);
795852 },
796853 .p64 => {
797854 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
798 try self.writeAtom(atom, &buffer);
855 try self.writeAtom(atom_index, &buffer);
799856 },
800857 }
801858}
......@@ -815,7 +872,8 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
815872 var it = self.relocs.valueIterator();
816873 while (it.next()) |relocs| {
817874 for (relocs.items) |*reloc| {
818 const target_atom = reloc.getTargetAtom(self) orelse continue;
875 const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;
876 const target_atom = self.getAtom(target_atom_index);
819877 const target_sym = target_atom.getSymbol(self);
820878 if (target_sym.value < addr) continue;
821879 reloc.dirty = true;
......@@ -823,24 +881,26 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
823881 }
824882}
825883
826fn resolveRelocs(self: *Coff, atom: *Atom) !void {
827 const relocs = self.relocs.get(atom) orelse return;
884fn resolveRelocs(self: *Coff, atom_index: Atom.Index) !void {
885 const relocs = self.relocs.get(atom_index) orelse return;
828886
829 log.debug("relocating '{s}'", .{atom.getName(self)});
887 log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)});
830888
831889 for (relocs.items) |*reloc| {
832890 if (!reloc.dirty) continue;
833 try reloc.resolve(atom, self);
891 try reloc.resolve(atom_index, self);
834892 }
835893}
836894
837fn freeAtom(self: *Coff, atom: *Atom) void {
838 log.debug("freeAtom {*}", .{atom});
895fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
896 log.debug("freeAtom {d}", .{atom_index});
897
898 const gpa = self.base.allocator;
839899
840900 // Remove any relocs and base relocs associated with this Atom
841 self.freeRelocationsForAtom(atom);
901 Atom.freeRelocations(self, atom_index);
842902
843 const gpa = self.base.allocator;
903 const atom = self.getAtom(atom_index);
844904 const sym = atom.getSymbol(self);
845905 const sect_id = @enumToInt(sym.section_number) - 1;
846906 const free_list = &self.sections.items(.free_list)[sect_id];
......@@ -849,45 +909,46 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
849909 var i: usize = 0;
850910 // TODO turn free_list into a hash map
851911 while (i < free_list.items.len) {
852 if (free_list.items[i] == atom) {
912 if (free_list.items[i] == atom_index) {
853913 _ = free_list.swapRemove(i);
854914 continue;
855915 }
856 if (free_list.items[i] == atom.prev) {
916 if (free_list.items[i] == atom.prev_index) {
857917 already_have_free_list_node = true;
858918 }
859919 i += 1;
860920 }
861921 }
862922
863 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];
864 if (maybe_last_atom.*) |last_atom| {
865 if (last_atom == atom) {
866 if (atom.prev) |prev| {
923 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
924 if (maybe_last_atom_index.*) |last_atom_index| {
925 if (last_atom_index == atom_index) {
926 if (atom.prev_index) |prev_index| {
867927 // TODO shrink the section size here
868 maybe_last_atom.* = prev;
928 maybe_last_atom_index.* = prev_index;
869929 } else {
870 maybe_last_atom.* = null;
930 maybe_last_atom_index.* = null;
871931 }
872932 }
873933 }
874934
875 if (atom.prev) |prev| {
876 prev.next = atom.next;
935 if (atom.prev_index) |prev_index| {
936 const prev = self.getAtomPtr(prev_index);
937 prev.next_index = atom.next_index;
877938
878 if (!already_have_free_list_node and prev.freeListEligible(self)) {
939 if (!already_have_free_list_node and prev.*.freeListEligible(self)) {
879940 // The free list is heuristics, it doesn't have to be perfect, so we can
880941 // ignore the OOM here.
881 free_list.append(gpa, prev) catch {};
942 free_list.append(gpa, prev_index) catch {};
882943 }
883944 } else {
884 atom.prev = null;
945 self.getAtomPtr(atom_index).prev_index = null;
885946 }
886947
887 if (atom.next) |next| {
888 next.prev = atom.prev;
948 if (atom.next_index) |next_index| {
949 self.getAtomPtr(next_index).prev_index = atom.prev_index;
889950 } else {
890 atom.next = null;
951 self.getAtomPtr(atom_index).next_index = null;
891952 }
892953
893954 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
......@@ -910,7 +971,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
910971 self.locals.items[sym_index].section_number = .UNDEFINED;
911972 _ = self.atom_by_index_table.remove(sym_index);
912973 log.debug(" adding local symbol index {d} to free list", .{sym_index});
913 atom.sym_index = 0;
974 self.getAtomPtr(atom_index).sym_index = 0;
914975}
915976
916977pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
......@@ -927,15 +988,10 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
927988
928989 const decl_index = func.owner_decl;
929990 const decl = module.declPtr(decl_index);
930 const atom = &decl.link.coff;
931 try atom.ensureInitialized(self);
932 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
933 if (gop.found_existing) {
934 self.freeUnnamedConsts(decl_index);
935 self.freeRelocationsForAtom(&decl.link.coff);
936 } else {
937 gop.value_ptr.* = null;
938 }
991
992 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
993 self.freeUnnamedConsts(decl_index);
994 Atom.freeRelocations(self, atom_index);
939995
940996 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
941997 defer code_buffer.deinit();
......@@ -979,11 +1035,8 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
9791035 }
9801036 const unnamed_consts = gop.value_ptr;
9811037
982 const atom = try gpa.create(Atom);
983 errdefer gpa.destroy(atom);
984 atom.* = Atom.empty;
985 try atom.ensureInitialized(self);
986 try self.managed_atoms.append(gpa, atom);
1038 const atom_index = try self.createAtom();
1039 const atom = self.getAtomPtr(atom_index);
9871040
9881041 const sym_name = blk: {
9891042 const decl_name = try decl.getFullyQualifiedName(mod);
......@@ -1012,15 +1065,15 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
10121065 const required_alignment = tv.ty.abiAlignment(self.base.options.target);
10131066 atom.alignment = required_alignment;
10141067 atom.size = @intCast(u32, code.len);
1015 atom.getSymbolPtr(self).value = try self.allocateAtom(atom, atom.size, atom.alignment);
1016 errdefer self.freeAtom(atom);
1068 atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, atom.alignment);
1069 errdefer self.freeAtom(atom_index);
10171070
1018 try unnamed_consts.append(gpa, atom);
1071 try unnamed_consts.append(gpa, atom_index);
10191072
10201073 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value });
10211074 log.debug(" (required alignment 0x{x})", .{required_alignment});
10221075
1023 try self.writeAtom(atom, code);
1076 try self.writeAtom(atom_index, code);
10241077
10251078 return atom.getSymbolIndex().?;
10261079}
......@@ -1047,14 +1100,9 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
10471100 }
10481101 }
10491102
1050 const atom = &decl.link.coff;
1051 try atom.ensureInitialized(self);
1052 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1053 if (gop.found_existing) {
1054 self.freeRelocationsForAtom(atom);
1055 } else {
1056 gop.value_ptr.* = null;
1057 }
1103 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
1104 Atom.freeRelocations(self, atom_index);
1105 const atom = self.getAtom(atom_index);
10581106
10591107 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
10601108 defer code_buffer.deinit();
......@@ -1064,7 +1112,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
10641112 .ty = decl.ty,
10651113 .val = decl_val,
10661114 }, &code_buffer, .none, .{
1067 .parent_atom_index = decl.link.coff.getSymbolIndex().?,
1115 .parent_atom_index = atom.getSymbolIndex().?,
10681116 });
10691117 const code = switch (res) {
10701118 .ok => code_buffer.items,
......@@ -1082,7 +1130,20 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
10821130 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
10831131}
10841132
1085fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 {
1133pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {
1134 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1135 if (!gop.found_existing) {
1136 gop.value_ptr.* = .{
1137 .atom = try self.createAtom(),
1138 .section = self.getDeclOutputSection(decl_index),
1139 .exports = .{},
1140 };
1141 }
1142 return gop.value_ptr.atom;
1143}
1144
1145fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 {
1146 const decl = self.base.options.module.?.declPtr(decl_index);
10861147 const ty = decl.ty;
10871148 const zig_ty = ty.zigTypeTag();
10881149 const val = decl.val;
......@@ -1117,14 +1178,11 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
11171178 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
11181179 const required_alignment = decl.getAlignment(self.base.options.target);
11191180
1120 const decl_ptr = self.decls.getPtr(decl_index).?;
1121 if (decl_ptr.* == null) {
1122 decl_ptr.* = self.getDeclOutputSection(decl);
1123 }
1124 const sect_index = decl_ptr.*.?;
1125
1181 const decl_metadata = self.decls.get(decl_index).?;
1182 const atom_index = decl_metadata.atom;
1183 const atom = self.getAtom(atom_index);
1184 const sect_index = decl_metadata.section;
11261185 const code_len = @intCast(u32, code.len);
1127 const atom = &decl.link.coff;
11281186
11291187 if (atom.size != 0) {
11301188 const sym = atom.getSymbolPtr(self);
......@@ -1135,7 +1193,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
11351193 const capacity = atom.capacity(self);
11361194 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
11371195 if (need_realloc) {
1138 const vaddr = try self.growAtom(atom, code_len, required_alignment);
1196 const vaddr = try self.growAtom(atom_index, code_len, required_alignment);
11391197 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });
11401198 log.debug(" (required alignment 0x{x}", .{required_alignment});
11411199
......@@ -1143,49 +1201,43 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
11431201 sym.value = vaddr;
11441202 log.debug(" (updating GOT entry)", .{});
11451203 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };
1146 const got_atom = self.getGotAtomForSymbol(got_target).?;
1204 const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?;
11471205 self.markRelocsDirtyByTarget(got_target);
1148 try self.writePtrWidthAtom(got_atom);
1206 try self.writePtrWidthAtom(got_atom_index);
11491207 }
11501208 } else if (code_len < atom.size) {
1151 self.shrinkAtom(atom, code_len);
1209 self.shrinkAtom(atom_index, code_len);
11521210 }
1153 atom.size = code_len;
1211 self.getAtomPtr(atom_index).size = code_len;
11541212 } else {
11551213 const sym = atom.getSymbolPtr(self);
11561214 try self.setSymbolName(sym, decl_name);
11571215 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
11581216 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
11591217
1160 const vaddr = try self.allocateAtom(atom, code_len, required_alignment);
1161 errdefer self.freeAtom(atom);
1218 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
1219 errdefer self.freeAtom(atom_index);
11621220 log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr });
1163 atom.size = code_len;
1221 self.getAtomPtr(atom_index).size = code_len;
11641222 sym.value = vaddr;
11651223
11661224 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };
11671225 const got_index = try self.allocateGotEntry(got_target);
1168 const got_atom = try self.createGotAtom(got_target);
1226 const got_atom_index = try self.createGotAtom(got_target);
1227 const got_atom = self.getAtom(got_atom_index);
11691228 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
1170 try self.writePtrWidthAtom(got_atom);
1229 try self.writePtrWidthAtom(got_atom_index);
11711230 }
11721231
11731232 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
1174 try self.writeAtom(atom, code);
1175}
1176
1177fn freeRelocationsForAtom(self: *Coff, atom: *Atom) void {
1178 var removed_relocs = self.relocs.fetchRemove(atom);
1179 if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator);
1180 var removed_base_relocs = self.base_relocs.fetchRemove(atom);
1181 if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(self.base.allocator);
1233 try self.writeAtom(atom_index, code);
11821234}
11831235
11841236fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void {
11851237 const gpa = self.base.allocator;
11861238 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
1187 for (unnamed_consts.items) |atom| {
1188 self.freeAtom(atom);
1239 for (unnamed_consts.items) |atom_index| {
1240 self.freeAtom(atom_index);
11891241 }
11901242 unnamed_consts.clearAndFree(gpa);
11911243}
......@@ -1200,11 +1252,11 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
12001252
12011253 log.debug("freeDecl {*}", .{decl});
12021254
1203 if (self.decls.fetchRemove(decl_index)) |kv| {
1204 if (kv.value) |_| {
1205 self.freeAtom(&decl.link.coff);
1206 self.freeUnnamedConsts(decl_index);
1207 }
1255 if (self.decls.fetchRemove(decl_index)) |const_kv| {
1256 var kv = const_kv;
1257 self.freeAtom(kv.value.atom);
1258 self.freeUnnamedConsts(decl_index);
1259 kv.value.exports.deinit(self.base.allocator);
12081260 }
12091261}
12101262
......@@ -1257,16 +1309,10 @@ pub fn updateDeclExports(
12571309 const gpa = self.base.allocator;
12581310
12591311 const decl = module.declPtr(decl_index);
1260 const atom = &decl.link.coff;
1261
1262 if (atom.getSymbolIndex() == null) return;
1263
1264 const gop = try self.decls.getOrPut(gpa, decl_index);
1265 if (!gop.found_existing) {
1266 gop.value_ptr.* = self.getDeclOutputSection(decl);
1267 }
1268
1312 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
1313 const atom = self.getAtom(atom_index);
12691314 const decl_sym = atom.getSymbol(self);
1315 const decl_metadata = self.decls.getPtr(decl_index).?;
12701316
12711317 for (exports) |exp| {
12721318 log.debug("adding new export '{s}'", .{exp.options.name});
......@@ -1301,9 +1347,9 @@ pub fn updateDeclExports(
13011347 continue;
13021348 }
13031349
1304 const sym_index = exp.link.coff.sym_index orelse blk: {
1350 const sym_index = decl_metadata.getExport(self, exp.options.name) orelse blk: {
13051351 const sym_index = try self.allocateSymbol();
1306 exp.link.coff.sym_index = sym_index;
1352 try decl_metadata.exports.append(gpa, sym_index);
13071353 break :blk sym_index;
13081354 };
13091355 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
......@@ -1326,16 +1372,15 @@ pub fn updateDeclExports(
13261372 }
13271373}
13281374
1329pub fn deleteExport(self: *Coff, exp: Export) void {
1375pub fn deleteDeclExport(self: *Coff, decl_index: Module.Decl.Index, name: []const u8) void {
13301376 if (self.llvm_object) |_| return;
1331 const sym_index = exp.sym_index orelse return;
1377 const metadata = self.decls.getPtr(decl_index) orelse return;
1378 const sym_index = metadata.getExportPtr(self, name) orelse return;
13321379
13331380 const gpa = self.base.allocator;
1334
1335 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1381 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
13361382 const sym = self.getSymbolPtr(sym_loc);
1337 const sym_name = self.getSymbolName(sym_loc);
1338 log.debug("deleting export '{s}'", .{sym_name});
1383 log.debug("deleting export '{s}'", .{name});
13391384 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
13401385 sym.* = .{
13411386 .name = [_]u8{0} ** 8,
......@@ -1345,9 +1390,9 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
13451390 .storage_class = .NULL,
13461391 .number_of_aux_symbols = 0,
13471392 };
1348 self.locals_free_list.append(gpa, sym_index) catch {};
1393 self.locals_free_list.append(gpa, sym_index.*) catch {};
13491394
1350 if (self.resolver.fetchRemove(sym_name)) |entry| {
1395 if (self.resolver.fetchRemove(name)) |entry| {
13511396 defer gpa.free(entry.key);
13521397 self.globals_free_list.append(gpa, entry.value) catch {};
13531398 self.globals.items[entry.value] = .{
......@@ -1355,6 +1400,8 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
13551400 .file = null,
13561401 };
13571402 }
1403
1404 sym_index.* = 0;
13581405}
13591406
13601407fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
......@@ -1419,9 +1466,10 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
14191466 if (self.imports_table.contains(global)) continue;
14201467
14211468 const import_index = try self.allocateImportEntry(global);
1422 const import_atom = try self.createImportAtom();
1469 const import_atom_index = try self.createImportAtom();
1470 const import_atom = self.getAtom(import_atom_index);
14231471 self.imports.items[import_index].sym_index = import_atom.getSymbolIndex().?;
1424 try self.writePtrWidthAtom(import_atom);
1472 try self.writePtrWidthAtom(import_atom_index);
14251473 }
14261474
14271475 if (build_options.enable_logging) {
......@@ -1455,22 +1503,14 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
14551503 }
14561504}
14571505
1458pub fn getDeclVAddr(
1459 self: *Coff,
1460 decl_index: Module.Decl.Index,
1461 reloc_info: link.File.RelocInfo,
1462) !u64 {
1463 const mod = self.base.options.module.?;
1464 const decl = mod.declPtr(decl_index);
1465
1506pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
14661507 assert(self.llvm_object == null);
14671508
1468 try decl.link.coff.ensureInitialized(self);
1469 const sym_index = decl.link.coff.getSymbolIndex().?;
1470
1471 const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
1509 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
1510 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
1511 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
14721512 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1473 try atom.addRelocation(self, .{
1513 try Atom.addRelocation(self, atom_index, .{
14741514 .type = .direct,
14751515 .target = target,
14761516 .offset = @intCast(u32, reloc_info.offset),
......@@ -1478,7 +1518,7 @@ pub fn getDeclVAddr(
14781518 .pcrel = false,
14791519 .length = 3,
14801520 });
1481 try atom.addBaseRelocation(self, @intCast(u32, reloc_info.offset));
1521 try Atom.addBaseRelocation(self, atom_index, @intCast(u32, reloc_info.offset));
14821522
14831523 return 0;
14841524}
......@@ -1529,7 +1569,8 @@ fn writeBaseRelocations(self: *Coff) !void {
15291569
15301570 var it = self.base_relocs.iterator();
15311571 while (it.next()) |entry| {
1532 const atom = entry.key_ptr.*;
1572 const atom_index = entry.key_ptr.*;
1573 const atom = self.getAtom(atom_index);
15331574 const offsets = entry.value_ptr.*;
15341575
15351576 for (offsets.items) |offset| {
......@@ -1613,7 +1654,8 @@ fn writeImportTable(self: *Coff) !void {
16131654 const gpa = self.base.allocator;
16141655
16151656 const section = self.sections.get(self.idata_section_index.?);
1616 const last_atom = section.last_atom orelse return;
1657 const last_atom_index = section.last_atom_index orelse return;
1658 const last_atom = self.getAtom(last_atom_index);
16171659
16181660 const iat_rva = section.header.virtual_address;
16191661 const iat_size = last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer
......@@ -2051,27 +2093,37 @@ pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult
20512093 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
20522094}
20532095
2096pub fn getAtom(self: *const Coff, atom_index: Atom.Index) Atom {
2097 assert(atom_index < self.atoms.items.len);
2098 return self.atoms.items[atom_index];
2099}
2100
2101pub fn getAtomPtr(self: *Coff, atom_index: Atom.Index) *Atom {
2102 assert(atom_index < self.atoms.items.len);
2103 return &self.atoms.items[atom_index];
2104}
2105
20542106/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.
20552107/// Returns null on failure.
2056pub fn getAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
2108pub fn getAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
20572109 assert(sym_loc.file == null); // TODO linking with object files
20582110 return self.atom_by_index_table.get(sym_loc.sym_index);
20592111}
20602112
20612113/// Returns GOT atom that references `sym_loc` if one exists.
20622114/// Returns null otherwise.
2063pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
2115pub fn getGotAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
20642116 const got_index = self.got_entries_table.get(sym_loc) orelse return null;
20652117 const got_entry = self.got_entries.items[got_index];
2066 return self.getAtomForSymbol(.{ .sym_index = got_entry.sym_index, .file = null });
2118 return self.getAtomIndexForSymbol(.{ .sym_index = got_entry.sym_index, .file = null });
20672119}
20682120
20692121/// Returns import atom that references `sym_loc` if one exists.
20702122/// Returns null otherwise.
2071pub fn getImportAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
2123pub fn getImportAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
20722124 const imports_index = self.imports_table.get(sym_loc) orelse return null;
20732125 const imports_entry = self.imports.items[imports_index];
2074 return self.getAtomForSymbol(.{ .sym_index = imports_entry.sym_index, .file = null });
2126 return self.getAtomIndexForSymbol(.{ .sym_index = imports_entry.sym_index, .file = null });
20752127}
20762128
20772129fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {
src/link/Coff/Atom.zig+24-24
......@@ -27,23 +27,10 @@ alignment: u32,
2727
2828/// Points to the previous and next neighbors, based on the `text_offset`.
2929/// This can be used to find, for example, the capacity of this `Atom`.
30prev: ?*Atom,
31next: ?*Atom,
32
33pub const empty = Atom{
34 .sym_index = 0,
35 .file = null,
36 .size = 0,
37 .alignment = 0,
38 .prev = null,
39 .next = null,
40};
41
42pub fn ensureInitialized(self: *Atom, coff_file: *Coff) !void {
43 if (self.getSymbolIndex() != null) return; // Already initialized
44 self.sym_index = try coff_file.allocateSymbol();
45 try coff_file.atom_by_index_table.putNoClobber(coff_file.base.allocator, self.sym_index, self);
46}
30prev_index: ?Index,
31next_index: ?Index,
32
33pub const Index = u32;
4734
4835pub fn getSymbolIndex(self: Atom) ?u32 {
4936 if (self.sym_index == 0) return null;
......@@ -85,7 +72,8 @@ pub fn getName(self: Atom, coff_file: *const Coff) []const u8 {
8572/// Returns how much room there is to grow in virtual address space.
8673pub fn capacity(self: Atom, coff_file: *const Coff) u32 {
8774 const self_sym = self.getSymbol(coff_file);
88 if (self.next) |next| {
75 if (self.next_index) |next_index| {
76 const next = coff_file.getAtom(next_index);
8977 const next_sym = next.getSymbol(coff_file);
9078 return next_sym.value - self_sym.value;
9179 } else {
......@@ -97,7 +85,8 @@ pub fn capacity(self: Atom, coff_file: *const Coff) u32 {
9785
9886pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
9987 // No need to keep a free list node for the last atom.
100 const next = self.next orelse return false;
88 const next_index = self.next_index orelse return false;
89 const next = coff_file.getAtom(next_index);
10190 const self_sym = self.getSymbol(coff_file);
10291 const next_sym = next.getSymbol(coff_file);
10392 const cap = next_sym.value - self_sym.value;
......@@ -107,22 +96,33 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
10796 return surplus >= Coff.min_text_capacity;
10897}
10998
110pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Relocation) !void {
99pub fn addRelocation(coff_file: *Coff, atom_index: Index, reloc: Relocation) !void {
111100 const gpa = coff_file.base.allocator;
112101 log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.type), reloc.target.sym_index });
113 const gop = try coff_file.relocs.getOrPut(gpa, self);
102 const gop = try coff_file.relocs.getOrPut(gpa, atom_index);
114103 if (!gop.found_existing) {
115104 gop.value_ptr.* = .{};
116105 }
117106 try gop.value_ptr.append(gpa, reloc);
118107}
119108
120pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void {
109pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void {
121110 const gpa = coff_file.base.allocator;
122 log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ offset, self.sym_index });
123 const gop = try coff_file.base_relocs.getOrPut(gpa, self);
111 log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{
112 offset,
113 coff_file.getAtom(atom_index).getSymbolIndex().?,
114 });
115 const gop = try coff_file.base_relocs.getOrPut(gpa, atom_index);
124116 if (!gop.found_existing) {
125117 gop.value_ptr.* = .{};
126118 }
127119 try gop.value_ptr.append(gpa, offset);
128120}
121
122pub fn freeRelocations(coff_file: *Coff, atom_index: Atom.Index) void {
123 const gpa = coff_file.base.allocator;
124 var removed_relocs = coff_file.relocs.fetchRemove(atom_index);
125 if (removed_relocs) |*relocs| relocs.value.deinit(gpa);
126 var removed_base_relocs = coff_file.base_relocs.fetchRemove(atom_index);
127 if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(gpa);
128}
src/link/Coff/Relocation.zig+10-8
......@@ -46,33 +46,35 @@ length: u2,
4646dirty: bool = true,
4747
4848/// Returns an Atom which is the target node of this relocation edge (if any).
49pub fn getTargetAtom(self: Relocation, coff_file: *Coff) ?*Atom {
49pub fn getTargetAtomIndex(self: Relocation, coff_file: *const Coff) ?Atom.Index {
5050 switch (self.type) {
5151 .got,
5252 .got_page,
5353 .got_pageoff,
54 => return coff_file.getGotAtomForSymbol(self.target),
54 => return coff_file.getGotAtomIndexForSymbol(self.target),
5555
5656 .direct,
5757 .page,
5858 .pageoff,
59 => return coff_file.getAtomForSymbol(self.target),
59 => return coff_file.getAtomIndexForSymbol(self.target),
6060
6161 .import,
6262 .import_page,
6363 .import_pageoff,
64 => return coff_file.getImportAtomForSymbol(self.target),
64 => return coff_file.getImportAtomIndexForSymbol(self.target),
6565 }
6666}
6767
68pub fn resolve(self: *Relocation, atom: *Atom, coff_file: *Coff) !void {
68pub fn resolve(self: *Relocation, atom_index: Atom.Index, coff_file: *Coff) !void {
69 const atom = coff_file.getAtom(atom_index);
6970 const source_sym = atom.getSymbol(coff_file);
7071 const source_section = coff_file.sections.get(@enumToInt(source_sym.section_number) - 1).header;
7172 const source_vaddr = source_sym.value + self.offset;
7273
7374 const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address;
7475
75 const target_atom = self.getTargetAtom(coff_file) orelse return;
76 const target_atom_index = self.getTargetAtomIndex(coff_file) orelse return;
77 const target_atom = coff_file.getAtom(target_atom_index);
7678 const target_vaddr = target_atom.getSymbol(coff_file).value;
7779 const target_vaddr_with_addend = target_vaddr + self.addend;
7880
......@@ -107,7 +109,7 @@ const Context = struct {
107109 image_base: u64,
108110};
109111
110fn resolveAarch64(self: *Relocation, ctx: Context, coff_file: *Coff) !void {
112fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {
111113 var buffer: [@sizeOf(u64)]u8 = undefined;
112114 switch (self.length) {
113115 2 => {
......@@ -197,7 +199,7 @@ fn resolveAarch64(self: *Relocation, ctx: Context, coff_file: *Coff) !void {
197199 }
198200}
199201
200fn resolveX86(self: *Relocation, ctx: Context, coff_file: *Coff) !void {
202fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void {
201203 switch (self.type) {
202204 .got_page => unreachable,
203205 .got_pageoff => unreachable,
src/link/Elf.zig+8-2
......@@ -71,14 +71,14 @@ const DeclMetadata = struct {
7171
7272 fn getExport(m: DeclMetadata, elf_file: *const Elf, name: []const u8) ?u32 {
7373 for (m.exports.items) |exp| {
74 if (mem.eql(u8, name, elf_file.getSymbolName(exp))) return exp;
74 if (mem.eql(u8, name, elf_file.getGlobalName(exp))) return exp;
7575 }
7676 return null;
7777 }
7878
7979 fn getExportPtr(m: *DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 {
8080 for (m.exports.items) |*exp| {
81 if (mem.eql(u8, name, elf_file.getSymbolName(exp.*))) return exp;
81 if (mem.eql(u8, name, elf_file.getGlobalName(exp.*))) return exp;
8282 }
8383 return null;
8484 }
......@@ -3276,6 +3276,12 @@ pub fn getSymbolName(self: *const Elf, sym_index: u32) []const u8 {
32763276 return self.shstrtab.get(sym.st_name).?;
32773277}
32783278
3279/// Returns name of the global symbol at index.
3280pub fn getGlobalName(self: *const Elf, index: u32) []const u8 {
3281 const sym = self.global_symbols.items[index];
3282 return self.shstrtab.get(sym.st_name).?;
3283}
3284
32793285pub fn getAtom(self: *const Elf, atom_index: Atom.Index) Atom {
32803286 assert(atom_index < self.atoms.items.len);
32813287 return self.atoms.items[atom_index];
src/link/MachO.zig+5
......@@ -3015,6 +3015,11 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
30153015 if (header.@"align" < align_pow) {
30163016 header.@"align" = align_pow;
30173017 }
3018 {
3019 const atom_ptr = self.getAtomPtr(atom_index);
3020 atom_ptr.size = new_atom_size;
3021 atom_ptr.alignment = @intCast(u32, alignment);
3022 }
30183023
30193024 if (atom.prev_index) |prev_index| {
30203025 const prev = self.getAtomPtr(prev_index);