authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-02-02 01:39:01+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-02-02 01:39:01+01:00
log304420b99ced44e1b7ebd34d7c3917879cb78648
treef66f23cc66418fa2ac3f7d7f9a080f991de3ec7d
parent1fba88450db12f184d76f0651f7ca933322c1fc0
parentbeb20d29db3fe945746581eba5d2f2cae1403cdb
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14502 from ziglang/link-owned-atoms

link: move ownership of linker atom from frontend to the linkers

31 files changed, 2376 insertions(+), 2167 deletions(-)

src/Compilation.zig+1-1
......@@ -3299,7 +3299,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
32993299 const gpa = comp.gpa;
33003300 const module = comp.bin_file.options.module.?;
33013301 const decl = module.declPtr(decl_index);
3302 comp.bin_file.updateDeclLineNumber(module, decl) catch |err| {
3302 comp.bin_file.updateDeclLineNumber(module, decl_index) catch |err| {
33033303 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
33043304 module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
33053305 gpa,
src/Module.zig+14-71
......@@ -328,8 +328,6 @@ pub const ErrorInt = u32;
328328pub const Export = struct {
329329 options: std.builtin.ExportOptions,
330330 src: LazySrcLoc,
331 /// Represents the position of the export, if any, in the output file.
332 link: link.File.Export,
333331 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
334332 owner_decl: Decl.Index,
335333 /// The Decl containing the export statement. Inline function calls
......@@ -533,16 +531,8 @@ pub const Decl = struct {
533531 /// What kind of a declaration is this.
534532 kind: Kind,
535533
536 /// Represents the position of the code in the output file.
537 /// This is populated regardless of semantic analysis and code generation.
538 link: link.File.LinkBlock,
539
540 /// Represents the function in the linked output file, if the `Decl` is a function.
541 /// This is stored here and not in `Fn` because `Decl` survives across updates but
542 /// `Fn` does not.
543 /// TODO Look into making `Fn` a longer lived structure and moving this field there
544 /// to save on memory usage.
545 fn_link: link.File.LinkFn,
534 /// TODO remove this once Wasm backend catches up
535 fn_link: ?link.File.Wasm.FnData = null,
546536
547537 /// The shallow set of other decls whose typed_value could possibly change if this Decl's
548538 /// typed_value is modified.
......@@ -4098,7 +4088,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
40984088
40994089 // The exports this Decl performs will be re-discovered, so we remove them here
41004090 // prior to re-analysis.
4101 mod.deleteDeclExports(decl_index);
4091 try mod.deleteDeclExports(decl_index);
41024092
41034093 // Similarly, `@setAlignStack` invocations will be re-discovered.
41044094 if (decl.getFunction()) |func| {
......@@ -5183,20 +5173,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
51835173 decl.zir_decl_index = @intCast(u32, decl_sub_index);
51845174 if (decl.getFunction()) |_| {
51855175 switch (comp.bin_file.tag) {
5186 .coff => {
5187 // TODO Implement for COFF
5188 },
5189 .elf => if (decl.fn_link.elf.len != 0) {
5190 // TODO Look into detecting when this would be unnecessary by storing enough state
5191 // in `Decl` to notice that the line number did not change.
5192 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
5193 },
5194 .macho => if (decl.fn_link.macho.len != 0) {
5195 // TODO Look into detecting when this would be unnecessary by storing enough state
5196 // in `Decl` to notice that the line number did not change.
5197 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
5198 },
5199 .plan9 => {
5176 .coff, .elf, .macho, .plan9 => {
52005177 // TODO Look into detecting when this would be unnecessary by storing enough state
52015178 // in `Decl` to notice that the line number did not change.
52025179 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
......@@ -5265,33 +5242,15 @@ pub fn clearDecl(
52655242 assert(emit_h.decl_table.swapRemove(decl_index));
52665243 }
52675244 _ = mod.compile_log_decls.swapRemove(decl_index);
5268 mod.deleteDeclExports(decl_index);
5245 try mod.deleteDeclExports(decl_index);
52695246
52705247 if (decl.has_tv) {
52715248 if (decl.ty.isFnOrHasRuntimeBits()) {
52725249 mod.comp.bin_file.freeDecl(decl_index);
52735250
5274 // TODO instead of a union, put this memory trailing Decl objects,
5275 // and allow it to be variably sized.
5276 decl.link = switch (mod.comp.bin_file.tag) {
5277 .coff => .{ .coff = link.File.Coff.Atom.empty },
5278 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
5279 .macho => .{ .macho = link.File.MachO.Atom.empty },
5280 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
5281 .c => .{ .c = {} },
5282 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
5283 .spirv => .{ .spirv = {} },
5284 .nvptx => .{ .nvptx = {} },
5285 };
52865251 decl.fn_link = switch (mod.comp.bin_file.tag) {
5287 .coff => .{ .coff = {} },
5288 .elf => .{ .elf = link.File.Dwarf.SrcFn.empty },
5289 .macho => .{ .macho = link.File.Dwarf.SrcFn.empty },
5290 .plan9 => .{ .plan9 = {} },
5291 .c => .{ .c = {} },
5292 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
5293 .spirv => .{ .spirv = .{} },
5294 .nvptx => .{ .nvptx = {} },
5252 .wasm => link.File.Wasm.FnData.empty,
5253 else => null,
52955254 };
52965255 }
52975256 if (decl.getInnerNamespace()) |namespace| {
......@@ -5358,7 +5317,7 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {
53585317
53595318/// Delete all the Export objects that are caused by this Decl. Re-analysis of
53605319/// this Decl will cause them to be re-created (or not).
5361fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {
5320fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {
53625321 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
53635322
53645323 for (export_owners.items) |exp| {
......@@ -5381,16 +5340,16 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {
53815340 }
53825341 }
53835342 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
5384 elf.deleteExport(exp.link.elf);
5343 elf.deleteDeclExport(decl_index, exp.options.name);
53855344 }
53865345 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {
5387 macho.deleteExport(exp.link.macho);
5346 try macho.deleteDeclExport(decl_index, exp.options.name);
53885347 }
53895348 if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {
5390 wasm.deleteExport(exp.link.wasm);
5349 wasm.deleteDeclExport(decl_index);
53915350 }
53925351 if (mod.comp.bin_file.cast(link.File.Coff)) |coff| {
5393 coff.deleteExport(exp.link.coff);
5352 coff.deleteDeclExport(decl_index, exp.options.name);
53945353 }
53955354 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
53965355 failed_kv.value.destroy(mod.gpa);
......@@ -5693,25 +5652,9 @@ pub fn allocateNewDecl(
56935652 .deletion_flag = false,
56945653 .zir_decl_index = 0,
56955654 .src_scope = src_scope,
5696 .link = switch (mod.comp.bin_file.tag) {
5697 .coff => .{ .coff = link.File.Coff.Atom.empty },
5698 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
5699 .macho => .{ .macho = link.File.MachO.Atom.empty },
5700 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
5701 .c => .{ .c = {} },
5702 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
5703 .spirv => .{ .spirv = {} },
5704 .nvptx => .{ .nvptx = {} },
5705 },
57065655 .fn_link = switch (mod.comp.bin_file.tag) {
5707 .coff => .{ .coff = {} },
5708 .elf => .{ .elf = link.File.Dwarf.SrcFn.empty },
5709 .macho => .{ .macho = link.File.Dwarf.SrcFn.empty },
5710 .plan9 => .{ .plan9 = {} },
5711 .c => .{ .c = {} },
5712 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
5713 .spirv => .{ .spirv = .{} },
5714 .nvptx => .{ .nvptx = {} },
5656 .wasm => link.File.Wasm.FnData.empty,
5657 else => null,
57155658 },
57165659 .generation = 0,
57175660 .is_pub = false,
src/Sema.zig-10
......@@ -5564,16 +5564,6 @@ pub fn analyzeExport(
55645564 .visibility = borrowed_options.visibility,
55655565 },
55665566 .src = src,
5567 .link = switch (mod.comp.bin_file.tag) {
5568 .coff => .{ .coff = .{} },
5569 .elf => .{ .elf = .{} },
5570 .macho => .{ .macho = .{} },
5571 .plan9 => .{ .plan9 = null },
5572 .c => .{ .c = {} },
5573 .wasm => .{ .wasm = .{} },
5574 .spirv => .{ .spirv = {} },
5575 .nvptx => .{ .nvptx = {} },
5576 },
55775567 .owner_decl = sema.owner_decl_index,
55785568 .src_decl = block.src_decl,
55795569 .exported_decl = exported_decl_index,
src/arch/aarch64/CodeGen.zig+70-51
......@@ -203,13 +203,7 @@ const DbgInfoReloc = struct {
203203 else => unreachable, // not a possible argument
204204
205205 };
206 try dw.genArgDbgInfo(
207 reloc.name,
208 reloc.ty,
209 function.bin_file.tag,
210 function.mod_fn.owner_decl,
211 loc,
212 );
206 try dw.genArgDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, loc);
213207 },
214208 .plan9 => {},
215209 .none => {},
......@@ -255,14 +249,7 @@ const DbgInfoReloc = struct {
255249 break :blk .nop;
256250 },
257251 };
258 try dw.genVarDbgInfo(
259 reloc.name,
260 reloc.ty,
261 function.bin_file.tag,
262 function.mod_fn.owner_decl,
263 is_ptr,
264 loc,
265 );
252 try dw.genVarDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, is_ptr, loc);
266253 },
267254 .plan9 => {},
268255 .none => {},
......@@ -4019,11 +4006,17 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
40194006 .direct => .load_memory_ptr_direct,
40204007 .import => unreachable,
40214008 };
4022 const mod = self.bin_file.options.module.?;
4023 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
40244009 const atom_index = switch (self.bin_file.tag) {
4025 .macho => owner_decl.link.macho.getSymbolIndex().?,
4026 .coff => owner_decl.link.coff.getSymbolIndex().?,
4010 .macho => blk: {
4011 const macho_file = self.bin_file.cast(link.File.MachO).?;
4012 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4013 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
4014 },
4015 .coff => blk: {
4016 const coff_file = self.bin_file.cast(link.File.Coff).?;
4017 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4018 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
4019 },
40274020 else => unreachable, // unsupported target format
40284021 };
40294022 _ = try self.addInst(.{
......@@ -4301,34 +4294,37 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
43014294 if (self.air.value(callee)) |func_value| {
43024295 if (func_value.castTag(.function)) |func_payload| {
43034296 const func = func_payload.data;
4304 const fn_owner_decl = mod.declPtr(func.owner_decl);
43054297
43064298 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4307 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4308 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4299 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4300 const atom = elf_file.getAtom(atom_index);
4301 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
43094302 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
43104303 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4311 try fn_owner_decl.link.macho.ensureInitialized(macho_file);
4304 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
4305 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
43124306 try self.genSetReg(Type.initTag(.u64), .x30, .{
43134307 .linker_load = .{
43144308 .type = .got,
4315 .sym_index = fn_owner_decl.link.macho.getSymbolIndex().?,
4309 .sym_index = sym_index,
43164310 },
43174311 });
43184312 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4319 try fn_owner_decl.link.coff.ensureInitialized(coff_file);
4313 const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
4314 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
43204315 try self.genSetReg(Type.initTag(.u64), .x30, .{
43214316 .linker_load = .{
43224317 .type = .got,
4323 .sym_index = fn_owner_decl.link.coff.getSymbolIndex().?,
4318 .sym_index = sym_index,
43244319 },
43254320 });
43264321 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4327 try p9.seeDecl(func.owner_decl);
4322 const decl_block_index = try p9.seeDecl(func.owner_decl);
4323 const decl_block = p9.getDeclBlock(decl_block_index);
43284324 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
43294325 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
43304326 const got_addr = p9.bases.data;
4331 const got_index = fn_owner_decl.link.plan9.got_index.?;
4327 const got_index = decl_block.got_index.?;
43324328 const fn_got_addr = got_addr + got_index * ptr_bytes;
43334329 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr });
43344330 } else unreachable;
......@@ -4349,11 +4345,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
43494345
43504346 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
43514347 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4348 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4349 const atom_index = macho_file.getAtom(atom).getSymbolIndex().?;
43524350 _ = try self.addInst(.{
43534351 .tag = .call_extern,
43544352 .data = .{
43554353 .relocation = .{
4356 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?,
4354 .atom_index = atom_index,
43574355 .sym_index = sym_index,
43584356 },
43594357 },
......@@ -5488,11 +5486,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
54885486 .direct => .load_memory_ptr_direct,
54895487 .import => unreachable,
54905488 };
5491 const mod = self.bin_file.options.module.?;
5492 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
54935489 const atom_index = switch (self.bin_file.tag) {
5494 .macho => owner_decl.link.macho.getSymbolIndex().?,
5495 .coff => owner_decl.link.coff.getSymbolIndex().?,
5490 .macho => blk: {
5491 const macho_file = self.bin_file.cast(link.File.MachO).?;
5492 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5493 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
5494 },
5495 .coff => blk: {
5496 const coff_file = self.bin_file.cast(link.File.Coff).?;
5497 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5498 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
5499 },
54965500 else => unreachable, // unsupported target format
54975501 };
54985502 _ = try self.addInst(.{
......@@ -5602,11 +5606,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
56025606 .direct => .load_memory_direct,
56035607 .import => .load_memory_import,
56045608 };
5605 const mod = self.bin_file.options.module.?;
5606 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
56075609 const atom_index = switch (self.bin_file.tag) {
5608 .macho => owner_decl.link.macho.getSymbolIndex().?,
5609 .coff => owner_decl.link.coff.getSymbolIndex().?,
5610 .macho => blk: {
5611 const macho_file = self.bin_file.cast(link.File.MachO).?;
5612 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5613 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
5614 },
5615 .coff => blk: {
5616 const coff_file = self.bin_file.cast(link.File.Coff).?;
5617 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5618 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
5619 },
56105620 else => unreachable, // unsupported target format
56115621 };
56125622 _ = try self.addInst(.{
......@@ -5796,11 +5806,17 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
57965806 .direct => .load_memory_ptr_direct,
57975807 .import => unreachable,
57985808 };
5799 const mod = self.bin_file.options.module.?;
5800 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
58015809 const atom_index = switch (self.bin_file.tag) {
5802 .macho => owner_decl.link.macho.getSymbolIndex().?,
5803 .coff => owner_decl.link.coff.getSymbolIndex().?,
5810 .macho => blk: {
5811 const macho_file = self.bin_file.cast(link.File.MachO).?;
5812 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5813 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
5814 },
5815 .coff => blk: {
5816 const coff_file = self.bin_file.cast(link.File.Coff).?;
5817 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5818 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
5819 },
58045820 else => unreachable, // unsupported target format
58055821 };
58065822 _ = try self.addInst(.{
......@@ -6119,23 +6135,27 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
61196135 mod.markDeclAlive(decl);
61206136
61216137 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6122 try decl.link.elf.ensureInitialized(elf_file);
6123 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6138 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6139 const atom = elf_file.getAtom(atom_index);
6140 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
61246141 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6125 try decl.link.macho.ensureInitialized(macho_file);
6142 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
6143 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
61266144 return MCValue{ .linker_load = .{
61276145 .type = .got,
6128 .sym_index = decl.link.macho.getSymbolIndex().?,
6146 .sym_index = sym_index,
61296147 } };
61306148 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6131 try decl.link.coff.ensureInitialized(coff_file);
6149 const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index);
6150 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
61326151 return MCValue{ .linker_load = .{
61336152 .type = .got,
6134 .sym_index = decl.link.coff.getSymbolIndex().?,
6153 .sym_index = sym_index,
61356154 } };
61366155 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6137 try p9.seeDecl(decl_index);
6138 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
6156 const decl_block_index = try p9.seeDecl(decl_index);
6157 const decl_block = p9.getDeclBlock(decl_block_index);
6158 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
61396159 return MCValue{ .memory = got_addr };
61406160 } else {
61416161 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
......@@ -6148,8 +6168,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
61486168 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
61496169 };
61506170 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6151 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
6152 return MCValue{ .memory = vaddr };
6171 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
61536172 } else if (self.bin_file.cast(link.File.MachO)) |_| {
61546173 return MCValue{ .linker_load = .{
61556174 .type = .direct,
src/arch/aarch64/Emit.zig+8-8
......@@ -670,9 +670,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
670670
671671 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
672672 // Add relocation to the decl.
673 const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
673 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
674674 const target = macho_file.getGlobalByIndex(relocation.sym_index);
675 try atom.addRelocation(macho_file, .{
675 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
676676 .type = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),
677677 .target = target,
678678 .offset = offset,
......@@ -883,10 +883,10 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
883883 }
884884
885885 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
886 const atom = macho_file.getAtomForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
886 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
887887 // TODO this causes segfault in stage1
888888 // try atom.addRelocations(macho_file, 2, .{
889 try atom.addRelocation(macho_file, .{
889 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
890890 .target = .{ .sym_index = data.sym_index, .file = null },
891891 .offset = offset,
892892 .addend = 0,
......@@ -902,7 +902,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
902902 else => unreachable,
903903 },
904904 });
905 try atom.addRelocation(macho_file, .{
905 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
906906 .target = .{ .sym_index = data.sym_index, .file = null },
907907 .offset = offset + 4,
908908 .addend = 0,
......@@ -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/arm/CodeGen.zig+12-25
......@@ -282,13 +282,7 @@ const DbgInfoReloc = struct {
282282 else => unreachable, // not a possible argument
283283 };
284284
285 try dw.genArgDbgInfo(
286 reloc.name,
287 reloc.ty,
288 function.bin_file.tag,
289 function.mod_fn.owner_decl,
290 loc,
291 );
285 try dw.genArgDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, loc);
292286 },
293287 .plan9 => {},
294288 .none => {},
......@@ -331,14 +325,7 @@ const DbgInfoReloc = struct {
331325 break :blk .nop;
332326 },
333327 };
334 try dw.genVarDbgInfo(
335 reloc.name,
336 reloc.ty,
337 function.bin_file.tag,
338 function.mod_fn.owner_decl,
339 is_ptr,
340 loc,
341 );
328 try dw.genVarDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, is_ptr, loc);
342329 },
343330 .plan9 => {},
344331 .none => {},
......@@ -4256,12 +4243,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
42564243 if (self.air.value(callee)) |func_value| {
42574244 if (func_value.castTag(.function)) |func_payload| {
42584245 const func = func_payload.data;
4259 const mod = self.bin_file.options.module.?;
4260 const fn_owner_decl = mod.declPtr(func.owner_decl);
42614246
42624247 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4263 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4264 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4248 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4249 const atom = elf_file.getAtom(atom_index);
4250 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
42654251 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
42664252 } else if (self.bin_file.cast(link.File.MachO)) |_| {
42674253 unreachable; // unsupported architecture for MachO
......@@ -6084,15 +6070,17 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
60846070 mod.markDeclAlive(decl);
60856071
60866072 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6087 try decl.link.elf.ensureInitialized(elf_file);
6088 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6073 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6074 const atom = elf_file.getAtom(atom_index);
6075 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
60896076 } else if (self.bin_file.cast(link.File.MachO)) |_| {
60906077 unreachable; // unsupported architecture for MachO
60916078 } else if (self.bin_file.cast(link.File.Coff)) |_| {
60926079 return self.fail("TODO codegen COFF const Decl pointer", .{});
60936080 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6094 try p9.seeDecl(decl_index);
6095 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
6081 const decl_block_index = try p9.seeDecl(decl_index);
6082 const decl_block = p9.getDeclBlock(decl_block_index);
6083 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
60966084 return MCValue{ .memory = got_addr };
60976085 } else {
60986086 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
......@@ -6106,8 +6094,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
61066094 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
61076095 };
61086096 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6109 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
6110 return MCValue{ .memory = vaddr };
6097 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
61116098 } else if (self.bin_file.cast(link.File.MachO)) |_| {
61126099 unreachable;
61136100 } else if (self.bin_file.cast(link.File.Coff)) |_| {
src/arch/riscv64/CodeGen.zig+13-20
......@@ -1615,13 +1615,9 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
16151615
16161616 switch (self.debug_output) {
16171617 .dwarf => |dw| switch (mcv) {
1618 .register => |reg| try dw.genArgDbgInfo(
1619 name,
1620 ty,
1621 self.bin_file.tag,
1622 self.mod_fn.owner_decl,
1623 .{ .register = reg.dwarfLocOp() },
1624 ),
1618 .register => |reg| try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, .{
1619 .register = reg.dwarfLocOp(),
1620 }),
16251621 .stack_offset => {},
16261622 else => {},
16271623 },
......@@ -1721,12 +1717,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
17211717 if (self.air.value(callee)) |func_value| {
17221718 if (func_value.castTag(.function)) |func_payload| {
17231719 const func = func_payload.data;
1724
1725 const mod = self.bin_file.options.module.?;
1726 const fn_owner_decl = mod.declPtr(func.owner_decl);
1727 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
1728 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
1729
1720 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1721 const atom = elf_file.getAtom(atom_index);
1722 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
17301723 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
17311724 _ = try self.addInst(.{
17321725 .tag = .jalr,
......@@ -2553,17 +2546,17 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
25532546 const decl = mod.declPtr(decl_index);
25542547 mod.markDeclAlive(decl);
25552548 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2556 try decl.link.elf.ensureInitialized(elf_file);
2557 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
2549 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
2550 const atom = elf_file.getAtom(atom_index);
2551 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
25582552 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2559 // TODO I'm hacking my way through here by repurposing .memory for storing
2560 // index to the GOT target symbol index.
2561 return MCValue{ .memory = decl.link.macho.sym_index };
2553 unreachable;
25622554 } else if (self.bin_file.cast(link.File.Coff)) |_| {
25632555 return self.fail("TODO codegen COFF const Decl pointer", .{});
25642556 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2565 try p9.seeDecl(decl_index);
2566 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2557 const decl_block_index = try p9.seeDecl(decl_index);
2558 const decl_block = p9.getDeclBlock(decl_block_index);
2559 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
25672560 return MCValue{ .memory = got_addr };
25682561 } else {
25692562 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
src/arch/sparc64/CodeGen.zig+9-13
......@@ -1216,11 +1216,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
12161216 if (self.bin_file.tag == link.File.Elf.base_tag) {
12171217 if (func_value.castTag(.function)) |func_payload| {
12181218 const func = func_payload.data;
1219 const mod = self.bin_file.options.module.?;
1220 const fn_owner_decl = mod.declPtr(func.owner_decl);
12211219 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1222 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
1223 break :blk @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
1220 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1221 const atom = elf_file.getAtom(atom_index);
1222 break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file));
12241223 } else unreachable;
12251224
12261225 try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr });
......@@ -3413,13 +3412,9 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
34133412
34143413 switch (self.debug_output) {
34153414 .dwarf => |dw| switch (mcv) {
3416 .register => |reg| try dw.genArgDbgInfo(
3417 name,
3418 ty,
3419 self.bin_file.tag,
3420 self.mod_fn.owner_decl,
3421 .{ .register = reg.dwarfLocOp() },
3422 ),
3415 .register => |reg| try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, .{
3416 .register = reg.dwarfLocOp(),
3417 }),
34233418 else => {},
34243419 },
34253420 else => {},
......@@ -4205,8 +4200,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
42054200
42064201 mod.markDeclAlive(decl);
42074202 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4208 try decl.link.elf.ensureInitialized(elf_file);
4209 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
4203 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
4204 const atom = elf_file.getAtom(atom_index);
4205 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
42104206 } else {
42114207 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
42124208 }
src/arch/wasm/CodeGen.zig+20-20
......@@ -1194,7 +1194,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
11941194 const fn_info = func.decl.ty.fnInfo();
11951195 var func_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type, func.target);
11961196 defer func_type.deinit(func.gpa);
1197 func.decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type);
1197 func.decl.fn_link.?.type_index = try func.bin_file.putOrGetFuncType(func_type);
11981198
11991199 var cc_result = try func.resolveCallingConventionValues(func.decl.ty);
12001200 defer cc_result.deinit(func.gpa);
......@@ -1269,10 +1269,10 @@ fn genFunc(func: *CodeGen) InnerError!void {
12691269
12701270 var emit: Emit = .{
12711271 .mir = mir,
1272 .bin_file = &func.bin_file.base,
1272 .bin_file = func.bin_file,
12731273 .code = func.code,
12741274 .locals = func.locals.items,
1275 .decl = func.decl,
1275 .decl_index = func.decl_index,
12761276 .dbg_output = func.debug_output,
12771277 .prev_di_line = 0,
12781278 .prev_di_column = 0,
......@@ -2117,33 +2117,31 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
21172117 const fn_info = fn_ty.fnInfo();
21182118 const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type, func.target);
21192119
2120 const callee: ?*Decl = blk: {
2120 const callee: ?Decl.Index = blk: {
21212121 const func_val = func.air.value(pl_op.operand) orelse break :blk null;
21222122 const module = func.bin_file.base.options.module.?;
21232123
21242124 if (func_val.castTag(.function)) |function| {
2125 const decl = module.declPtr(function.data.owner_decl);
2126 try decl.link.wasm.ensureInitialized(func.bin_file);
2127 break :blk decl;
2125 _ = try func.bin_file.getOrCreateAtomForDecl(function.data.owner_decl);
2126 break :blk function.data.owner_decl;
21282127 } else if (func_val.castTag(.extern_fn)) |extern_fn| {
21292128 const ext_decl = module.declPtr(extern_fn.data.owner_decl);
21302129 const ext_info = ext_decl.ty.fnInfo();
21312130 var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target);
21322131 defer func_type.deinit(func.gpa);
2133 const atom = &ext_decl.link.wasm;
2134 try atom.ensureInitialized(func.bin_file);
2135 ext_decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type);
2132 const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_fn.data.owner_decl);
2133 const atom = func.bin_file.getAtomPtr(atom_index);
2134 ext_decl.fn_link.?.type_index = try func.bin_file.putOrGetFuncType(func_type);
21362135 try func.bin_file.addOrUpdateImport(
21372136 mem.sliceTo(ext_decl.name, 0),
21382137 atom.getSymbolIndex().?,
21392138 ext_decl.getExternFn().?.lib_name,
2140 ext_decl.fn_link.wasm.type_index,
2139 ext_decl.fn_link.?.type_index,
21412140 );
2142 break :blk ext_decl;
2141 break :blk extern_fn.data.owner_decl;
21432142 } else if (func_val.castTag(.decl_ref)) |decl_ref| {
2144 const decl = module.declPtr(decl_ref.data);
2145 try decl.link.wasm.ensureInitialized(func.bin_file);
2146 break :blk decl;
2143 _ = try func.bin_file.getOrCreateAtomForDecl(decl_ref.data);
2144 break :blk decl_ref.data;
21472145 }
21482146 return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()});
21492147 };
......@@ -2164,7 +2162,8 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
21642162 }
21652163
21662164 if (callee) |direct| {
2167 try func.addLabel(.call, direct.link.wasm.sym_index);
2165 const atom_index = func.bin_file.decls.get(direct).?;
2166 try func.addLabel(.call, func.bin_file.getAtom(atom_index).sym_index);
21682167 } else {
21692168 // in this case we call a function pointer
21702169 // so load its value onto the stack
......@@ -2477,7 +2476,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
24772476 .dwarf => |dwarf| {
24782477 const src_index = func.air.instructions.items(.data)[inst].arg.src_index;
24792478 const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, src_index);
2480 try dwarf.genArgDbgInfo(name, arg_ty, .wasm, func.mod_fn.owner_decl, .{
2479 try dwarf.genArgDbgInfo(name, arg_ty, func.mod_fn.owner_decl, .{
24812480 .wasm_local = arg.local.value,
24822481 });
24832482 },
......@@ -2760,9 +2759,10 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind
27602759 }
27612760
27622761 module.markDeclAlive(decl);
2763 try decl.link.wasm.ensureInitialized(func.bin_file);
2762 const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index);
2763 const atom = func.bin_file.getAtom(atom_index);
27642764
2765 const target_sym_index = decl.link.wasm.sym_index;
2765 const target_sym_index = atom.sym_index;
27662766 if (decl.ty.zigTypeTag() == .Fn) {
27672767 try func.bin_file.addTableFunction(target_sym_index);
27682768 return WValue{ .function_index = target_sym_index };
......@@ -5547,7 +5547,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void {
55475547 break :blk .nop;
55485548 },
55495549 };
5550 try func.debug_output.dwarf.genVarDbgInfo(name, ty, .wasm, func.mod_fn.owner_decl, is_ptr, loc);
5550 try func.debug_output.dwarf.genVarDbgInfo(name, ty, func.mod_fn.owner_decl, is_ptr, loc);
55515551
55525552 func.finishAir(inst, .none, &.{});
55535553}
src/arch/wasm/Emit.zig+18-11
......@@ -11,8 +11,8 @@ const leb128 = std.leb;
1111
1212/// Contains our list of instructions
1313mir: Mir,
14/// Reference to the file handler
15bin_file: *link.File,
14/// Reference to the Wasm module linker
15bin_file: *link.File.Wasm,
1616/// Possible error message. When set, the value is allocated and
1717/// must be freed manually.
1818error_msg: ?*Module.ErrorMsg = null,
......@@ -21,7 +21,7 @@ code: *std.ArrayList(u8),
2121/// List of allocated locals.
2222locals: []const u8,
2323/// The declaration that code is being generated for.
24decl: *Module.Decl,
24decl_index: Module.Decl.Index,
2525
2626// Debug information
2727/// Holds the debug information for this emission
......@@ -252,8 +252,8 @@ fn offset(self: Emit) u32 {
252252fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
253253 @setCold(true);
254254 std.debug.assert(emit.error_msg == null);
255 // TODO: Determine the source location.
256 emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.allocator, emit.decl.srcLoc(), format, args);
255 const mod = emit.bin_file.base.options.module.?;
256 emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.base.allocator, mod.declPtr(emit.decl_index).srcLoc(), format, args);
257257 return error.EmitFail;
258258}
259259
......@@ -304,8 +304,9 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {
304304 const global_offset = emit.offset();
305305 try emit.code.appendSlice(&buf);
306306
307 // globals can have index 0 as it represents the stack pointer
308 try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
307 const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
308 const atom = emit.bin_file.getAtomPtr(atom_index);
309 try atom.relocs.append(emit.bin_file.base.allocator, .{
309310 .index = label,
310311 .offset = global_offset,
311312 .relocation_type = .R_WASM_GLOBAL_INDEX_LEB,
......@@ -361,7 +362,9 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {
361362 try emit.code.appendSlice(&buf);
362363
363364 if (label != 0) {
364 try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
365 const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
366 const atom = emit.bin_file.getAtomPtr(atom_index);
367 try atom.relocs.append(emit.bin_file.base.allocator, .{
365368 .offset = call_offset,
366369 .index = label,
367370 .relocation_type = .R_WASM_FUNCTION_INDEX_LEB,
......@@ -387,7 +390,9 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
387390 try emit.code.appendSlice(&buf);
388391
389392 if (symbol_index != 0) {
390 try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
393 const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
394 const atom = emit.bin_file.getAtomPtr(atom_index);
395 try atom.relocs.append(emit.bin_file.base.allocator, .{
391396 .offset = index_offset,
392397 .index = symbol_index,
393398 .relocation_type = .R_WASM_TABLE_INDEX_SLEB,
......@@ -399,7 +404,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
399404 const extra_index = emit.mir.instructions.items(.data)[inst].payload;
400405 const mem = emit.mir.extraData(Mir.Memory, extra_index).data;
401406 const mem_offset = emit.offset() + 1;
402 const is_wasm32 = emit.bin_file.options.target.cpu.arch == .wasm32;
407 const is_wasm32 = emit.bin_file.base.options.target.cpu.arch == .wasm32;
403408 if (is_wasm32) {
404409 try emit.code.append(std.wasm.opcode(.i32_const));
405410 var buf: [5]u8 = undefined;
......@@ -413,7 +418,9 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
413418 }
414419
415420 if (mem.pointer != 0) {
416 try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
421 const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
422 const atom = emit.bin_file.getAtomPtr(atom_index);
423 try atom.relocs.append(emit.bin_file.base.allocator, .{
417424 .offset = mem_offset,
418425 .index = mem.pointer,
419426 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_LEB else .R_WASM_MEMORY_ADDR_LEB64,
src/arch/x86_64/CodeGen.zig+38-33
......@@ -2668,12 +2668,13 @@ 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);
2673 const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag)
2674 fn_owner_decl.link.macho.getSymbolIndex().?
2675 else
2676 fn_owner_decl.link.coff.getSymbolIndex().?;
2671 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
2672 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
2673 break :blk macho_file.getAtom(atom).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().?;
2677 } else unreachable;
26772678 const flags: u2 = switch (load_struct.type) {
26782679 .got => 0b00,
26792680 .direct => 0b01,
......@@ -3835,7 +3836,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
38353836 },
38363837 else => unreachable, // not a valid function parameter
38373838 };
3838 try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc);
3839 try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, loc);
38393840 },
38403841 .plan9 => {},
38413842 .none => {},
......@@ -3875,7 +3876,7 @@ fn genVarDbgInfo(
38753876 break :blk .nop;
38763877 },
38773878 };
3878 try dw.genVarDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, is_ptr, loc);
3879 try dw.genVarDbgInfo(name, ty, self.mod_fn.owner_decl, is_ptr, loc);
38793880 },
38803881 .plan9 => {},
38813882 .none => {},
......@@ -3995,19 +3996,19 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
39953996 if (self.air.value(callee)) |func_value| {
39963997 if (func_value.castTag(.function)) |func_payload| {
39973998 const func = func_payload.data;
3998 const fn_owner_decl = mod.declPtr(func.owner_decl);
39993999
40004000 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4001 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4002 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4001 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4002 const atom = elf_file.getAtom(atom_index);
4003 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
40034004 _ = try self.addInst(.{
40044005 .tag = .call,
40054006 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
40064007 .data = .{ .imm = got_addr },
40074008 });
40084009 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4009 try fn_owner_decl.link.coff.ensureInitialized(coff_file);
4010 const sym_index = fn_owner_decl.link.coff.getSymbolIndex().?;
4010 const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
4011 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
40114012 try self.genSetReg(Type.initTag(.usize), .rax, .{
40124013 .linker_load = .{
40134014 .type = .got,
......@@ -4023,8 +4024,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
40234024 .data = undefined,
40244025 });
40254026 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4026 try fn_owner_decl.link.macho.ensureInitialized(macho_file);
4027 const sym_index = fn_owner_decl.link.macho.getSymbolIndex().?;
4027 const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
4028 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
40284029 try self.genSetReg(Type.initTag(.usize), .rax, .{
40294030 .linker_load = .{
40304031 .type = .got,
......@@ -4040,11 +4041,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
40404041 .data = undefined,
40414042 });
40424043 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4043 try p9.seeDecl(func.owner_decl);
4044 const decl_block_index = try p9.seeDecl(func.owner_decl);
4045 const decl_block = p9.getDeclBlock(decl_block_index);
40444046 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
40454047 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
40464048 const got_addr = p9.bases.data;
4047 const got_index = fn_owner_decl.link.plan9.got_index.?;
4049 const got_index = decl_block.got_index.?;
40484050 const fn_got_addr = got_addr + got_index * ptr_bytes;
40494051 _ = try self.addInst(.{
40504052 .tag = .call,
......@@ -4080,15 +4082,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
40804082 });
40814083 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
40824084 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4085 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4086 const atom_index = macho_file.getAtom(atom).getSymbolIndex().?;
40834087 _ = try self.addInst(.{
40844088 .tag = .call_extern,
40854089 .ops = undefined,
4086 .data = .{
4087 .relocation = .{
4088 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?,
4089 .sym_index = sym_index,
4090 },
4091 },
4090 .data = .{ .relocation = .{
4091 .atom_index = atom_index,
4092 .sym_index = sym_index,
4093 } },
40924094 });
40934095 } else {
40944096 return self.fail("TODO implement calling extern functions", .{});
......@@ -6719,23 +6721,27 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
67196721 module.markDeclAlive(decl);
67206722
67216723 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6722 try decl.link.elf.ensureInitialized(elf_file);
6723 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6724 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6725 const atom = elf_file.getAtom(atom_index);
6726 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
67246727 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6725 try decl.link.macho.ensureInitialized(macho_file);
6728 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
6729 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
67266730 return MCValue{ .linker_load = .{
67276731 .type = .got,
6728 .sym_index = decl.link.macho.getSymbolIndex().?,
6732 .sym_index = sym_index,
67296733 } };
67306734 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6731 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().?;
67326737 return MCValue{ .linker_load = .{
67336738 .type = .got,
6734 .sym_index = decl.link.coff.getSymbolIndex().?,
6739 .sym_index = sym_index,
67356740 } };
67366741 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6737 try p9.seeDecl(decl_index);
6738 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
6742 const decl_block_index = try p9.seeDecl(decl_index);
6743 const decl_block = p9.getDeclBlock(decl_block_index);
6744 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
67396745 return MCValue{ .memory = got_addr };
67406746 } else {
67416747 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
......@@ -6748,8 +6754,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
67486754 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
67496755 };
67506756 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6751 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
6752 return MCValue{ .memory = vaddr };
6757 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
67536758 } else if (self.bin_file.cast(link.File.MachO)) |_| {
67546759 return MCValue{ .linker_load = .{
67556760 .type = .direct,
src/arch/x86_64/Emit.zig+8-8
......@@ -1001,8 +1001,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
10011001 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
10021002 else => unreachable,
10031003 };
1004 const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
1005 try atom.addRelocation(macho_file, .{
1004 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
1005 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
10061006 .type = reloc_type,
10071007 .target = .{ .sym_index = relocation.sym_index, .file = null },
10081008 .offset = @intCast(u32, end_offset - 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,
......@@ -1140,9 +1140,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
11401140
11411141 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
11421142 // Add relocation to the decl.
1143 const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
1143 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
11441144 const target = macho_file.getGlobalByIndex(relocation.sym_index);
1145 try atom.addRelocation(macho_file, .{
1145 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
11461146 .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
11471147 .target = target,
11481148 .offset = offset,
......@@ -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/codegen/spirv.zig+19-11
......@@ -49,7 +49,7 @@ pub const DeclGen = struct {
4949 spv: *SpvModule,
5050
5151 /// The decl we are currently generating code for.
52 decl: *Decl,
52 decl_index: Decl.Index,
5353
5454 /// The intermediate code of the declaration we are currently generating. Note: If
5555 /// the declaration is not a function, this value will be undefined!
......@@ -59,6 +59,8 @@ pub const DeclGen = struct {
5959 /// Note: If the declaration is not a function, this value will be undefined!
6060 liveness: Liveness,
6161
62 ids: *const std.AutoHashMap(Decl.Index, IdResult),
63
6264 /// An array of function argument result-ids. Each index corresponds with the
6365 /// function argument of the same index.
6466 args: std.ArrayListUnmanaged(IdRef) = .{},
......@@ -133,14 +135,20 @@ pub const DeclGen = struct {
133135
134136 /// Initialize the common resources of a DeclGen. Some fields are left uninitialized,
135137 /// only set when `gen` is called.
136 pub fn init(allocator: Allocator, module: *Module, spv: *SpvModule) DeclGen {
138 pub fn init(
139 allocator: Allocator,
140 module: *Module,
141 spv: *SpvModule,
142 ids: *const std.AutoHashMap(Decl.Index, IdResult),
143 ) DeclGen {
137144 return .{
138145 .gpa = allocator,
139146 .module = module,
140147 .spv = spv,
141 .decl = undefined,
148 .decl_index = undefined,
142149 .air = undefined,
143150 .liveness = undefined,
151 .ids = ids,
144152 .next_arg_index = undefined,
145153 .current_block_label_id = undefined,
146154 .error_msg = undefined,
......@@ -150,9 +158,9 @@ pub const DeclGen = struct {
150158 /// Generate the code for `decl`. If a reportable error occurred during code generation,
151159 /// a message is returned by this function. Callee owns the memory. If this function
152160 /// returns such a reportable error, it is valid to be called again for a different decl.
153 pub fn gen(self: *DeclGen, decl: *Decl, air: Air, liveness: Liveness) !?*Module.ErrorMsg {
161 pub fn gen(self: *DeclGen, decl_index: Decl.Index, air: Air, liveness: Liveness) !?*Module.ErrorMsg {
154162 // Reset internal resources, we don't want to re-allocate these.
155 self.decl = decl;
163 self.decl_index = decl_index;
156164 self.air = air;
157165 self.liveness = liveness;
158166 self.args.items.len = 0;
......@@ -194,7 +202,7 @@ pub const DeclGen = struct {
194202 pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
195203 @setCold(true);
196204 const src = LazySrcLoc.nodeOffset(0);
197 const src_loc = src.toSrcLoc(self.decl);
205 const src_loc = src.toSrcLoc(self.module.declPtr(self.decl_index));
198206 assert(self.error_msg == null);
199207 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);
200208 return error.CodegenFail;
......@@ -332,7 +340,7 @@ pub const DeclGen = struct {
332340 };
333341 const decl = self.module.declPtr(fn_decl_index);
334342 self.module.markDeclAlive(decl);
335 return decl.fn_link.spirv.id.toRef();
343 return self.ids.get(fn_decl_index).?.toRef();
336344 }
337345
338346 const target = self.getTarget();
......@@ -553,8 +561,8 @@ pub const DeclGen = struct {
553561 }
554562
555563 fn genDecl(self: *DeclGen) !void {
556 const decl = self.decl;
557 const result_id = decl.fn_link.spirv.id;
564 const result_id = self.ids.get(self.decl_index).?;
565 const decl = self.module.declPtr(self.decl_index);
558566
559567 if (decl.val.castTag(.function)) |_| {
560568 assert(decl.ty.zigTypeTag() == .Fn);
......@@ -945,7 +953,7 @@ pub const DeclGen = struct {
945953
946954 fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void {
947955 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
948 const src_fname_id = try self.spv.resolveSourceFileName(self.decl);
956 const src_fname_id = try self.spv.resolveSourceFileName(self.module.declPtr(self.decl_index));
949957 try self.func.body.emit(self.spv.gpa, .OpLine, .{
950958 .file = src_fname_id,
951959 .line = dbg_stmt.line,
......@@ -1106,7 +1114,7 @@ pub const DeclGen = struct {
11061114 assert(as.errors.items.len != 0);
11071115 assert(self.error_msg == null);
11081116 const loc = LazySrcLoc.nodeOffset(0);
1109 const src_loc = loc.toSrcLoc(self.decl);
1117 const src_loc = loc.toSrcLoc(self.module.declPtr(self.decl_index));
11101118 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});
11111119 const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len);
11121120
src/link.zig+9-41
......@@ -261,39 +261,6 @@ pub const File = struct {
261261 /// of this linking operation.
262262 lock: ?Cache.Lock = null,
263263
264 pub const LinkBlock = union {
265 elf: Elf.TextBlock,
266 coff: Coff.Atom,
267 macho: MachO.Atom,
268 plan9: Plan9.DeclBlock,
269 c: void,
270 wasm: Wasm.DeclBlock,
271 spirv: void,
272 nvptx: void,
273 };
274
275 pub const LinkFn = union {
276 elf: Dwarf.SrcFn,
277 coff: Coff.SrcFn,
278 macho: Dwarf.SrcFn,
279 plan9: void,
280 c: void,
281 wasm: Wasm.FnData,
282 spirv: SpirV.FnData,
283 nvptx: void,
284 };
285
286 pub const Export = union {
287 elf: Elf.Export,
288 coff: Coff.Export,
289 macho: MachO.Export,
290 plan9: Plan9.Export,
291 c: void,
292 wasm: Wasm.Export,
293 spirv: void,
294 nvptx: void,
295 };
296
297264 /// Attempts incremental linking, if the file already exists. If
298265 /// incremental linking fails, falls back to truncating the file and
299266 /// rewriting it. A malicious file is detected as incremental link failure
......@@ -580,22 +547,23 @@ pub const File = struct {
580547 }
581548 }
582549
583 pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) UpdateDeclError!void {
550 pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
551 const decl = module.declPtr(decl_index);
584552 log.debug("updateDeclLineNumber {*} ({s}), line={}", .{
585553 decl, decl.name, decl.src_line + 1,
586554 });
587555 assert(decl.has_tv);
588556 if (build_options.only_c) {
589557 assert(base.tag == .c);
590 return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl);
558 return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index);
591559 }
592560 switch (base.tag) {
593 .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl),
594 .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl),
595 .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl),
596 .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl),
597 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl),
598 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl),
561 .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl_index),
562 .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl_index),
563 .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl_index),
564 .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index),
565 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl_index),
566 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl_index),
599567 .spirv, .nvptx => {},
600568 }
601569 }
src/link/C.zig+2-2
......@@ -219,12 +219,12 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
219219 code.shrinkAndFree(module.gpa, code.items.len);
220220}
221221
222pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void {
222pub fn updateDeclLineNumber(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
223223 // The C backend does not have the ability to fix line numbers without re-generating
224224 // the entire Decl.
225225 _ = self;
226226 _ = module;
227 _ = decl;
227 _ = decl_index;
228228}
229229
230230pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void {
src/link/Coff.zig+265-210
......@@ -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 {
......@@ -168,11 +195,6 @@ pub const PtrWidth = enum {
168195 };
169196 }
170197};
171pub const SrcFn = void;
172
173pub const Export = struct {
174 sym_index: ?u32 = null,
175};
176198
177199pub const SymbolWithLoc = struct {
178200 // Index into the respective symbol table.
......@@ -271,11 +293,7 @@ pub fn deinit(self: *Coff) void {
271293 }
272294 self.sections.deinit(gpa);
273295
274 for (self.managed_atoms.items) |atom| {
275 gpa.destroy(atom);
276 }
277 self.managed_atoms.deinit(gpa);
278
296 self.atoms.deinit(gpa);
279297 self.locals.deinit(gpa);
280298 self.globals.deinit(gpa);
281299
......@@ -297,7 +315,15 @@ pub fn deinit(self: *Coff) void {
297315 self.imports.deinit(gpa);
298316 self.imports_free_list.deinit(gpa);
299317 self.imports_table.deinit(gpa);
300 self.decls.deinit(gpa);
318
319 {
320 var it = self.decls.iterator();
321 while (it.next()) |entry| {
322 entry.value_ptr.exports.deinit(gpa);
323 }
324 self.decls.deinit(gpa);
325 }
326
301327 self.atom_by_index_table.deinit(gpa);
302328
303329 {
......@@ -461,17 +487,18 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {
461487 // TODO: enforce order by increasing VM addresses in self.sections container.
462488 // This is required by the loader anyhow as far as I can tell.
463489 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];
490 const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id + 1 + next_sect_id];
465491 next_header.virtual_address += diff;
466492
467 if (maybe_last_atom.*) |last_atom| {
468 var atom = last_atom;
493 if (maybe_last_atom_index) |last_atom_index| {
494 var atom_index = last_atom_index;
469495 while (true) {
496 const atom = self.getAtom(atom_index);
470497 const sym = atom.getSymbolPtr(self);
471498 sym.value += diff;
472499
473 if (atom.prev) |prev| {
474 atom = prev;
500 if (atom.prev_index) |prev_index| {
501 atom_index = prev_index;
475502 } else break;
476503 }
477504 }
......@@ -480,14 +507,15 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {
480507 header.virtual_size = increased_size;
481508}
482509
483fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 {
510fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
484511 const tracy = trace(@src());
485512 defer tracy.end();
486513
514 const atom = self.getAtom(atom_index);
487515 const sect_id = @enumToInt(atom.getSymbol(self).section_number) - 1;
488516 const header = &self.sections.items(.header)[sect_id];
489517 const free_list = &self.sections.items(.free_list)[sect_id];
490 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];
518 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
491519 const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size;
492520
493521 // We use these to indicate our intention to update metadata, placing the new atom,
......@@ -495,7 +523,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
495523 // It would be simpler to do it inside the for loop below, but that would cause a
496524 // problem if an error was returned later in the function. So this action
497525 // is actually carried out at the end of the function, when errors are no longer possible.
498 var atom_placement: ?*Atom = null;
526 var atom_placement: ?Atom.Index = null;
499527 var free_list_removal: ?usize = null;
500528
501529 // First we look for an appropriately sized free list node.
......@@ -503,7 +531,8 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
503531 var vaddr = blk: {
504532 var i: usize = 0;
505533 while (i < free_list.items.len) {
506 const big_atom = free_list.items[i];
534 const big_atom_index = free_list.items[i];
535 const big_atom = self.getAtom(big_atom_index);
507536 // We now have a pointer to a live atom that has too much capacity.
508537 // Is it enough that we could fit this new atom?
509538 const sym = big_atom.getSymbol(self);
......@@ -531,34 +560,43 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
531560 const keep_free_list_node = remaining_capacity >= min_text_capacity;
532561
533562 // Set up the metadata to be updated, after errors are no longer possible.
534 atom_placement = big_atom;
563 atom_placement = big_atom_index;
535564 if (!keep_free_list_node) {
536565 free_list_removal = i;
537566 }
538567 break :blk new_start_vaddr;
539 } else if (maybe_last_atom.*) |last| {
568 } else if (maybe_last_atom_index.*) |last_index| {
569 const last = self.getAtom(last_index);
540570 const last_symbol = last.getSymbol(self);
541571 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
542572 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;
543573 const new_start_vaddr = mem.alignForwardGeneric(u32, ideal_capacity_end_vaddr, alignment);
544 atom_placement = last;
574 atom_placement = last_index;
545575 break :blk new_start_vaddr;
546576 } else {
547577 break :blk mem.alignForwardGeneric(u32, header.virtual_address, alignment);
548578 }
549579 };
550580
551 const expand_section = atom_placement == null or atom_placement.?.next == null;
581 const expand_section = if (atom_placement) |placement_index|
582 self.getAtom(placement_index).next_index == null
583 else
584 true;
552585 if (expand_section) {
553586 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
554587 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;
555588 if (needed_size > sect_capacity) {
556589 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
557 const current_size = if (maybe_last_atom.*) |last_atom| blk: {
590 const current_size = if (maybe_last_atom_index.*) |last_atom_index| blk: {
591 const last_atom = self.getAtom(last_atom_index);
558592 const sym = last_atom.getSymbol(self);
559593 break :blk (sym.value + last_atom.size) - header.virtual_address;
560594 } else 0;
561 log.debug("moving {s} from 0x{x} to 0x{x}", .{ self.getSectionName(header), header.pointer_to_raw_data, new_offset });
595 log.debug("moving {s} from 0x{x} to 0x{x}", .{
596 self.getSectionName(header),
597 header.pointer_to_raw_data,
598 new_offset,
599 });
562600 const amt = try self.base.file.?.copyRangeAll(
563601 header.pointer_to_raw_data,
564602 self.base.file.?,
......@@ -577,26 +615,34 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
577615
578616 header.virtual_size = @max(header.virtual_size, needed_size);
579617 header.size_of_raw_data = needed_size;
580 maybe_last_atom.* = atom;
618 maybe_last_atom_index.* = atom_index;
581619 }
582620
583 atom.size = new_atom_size;
584 atom.alignment = alignment;
621 {
622 const atom_ptr = self.getAtomPtr(atom_index);
623 atom_ptr.size = new_atom_size;
624 atom_ptr.alignment = alignment;
625 }
585626
586 if (atom.prev) |prev| {
587 prev.next = atom.next;
627 if (atom.prev_index) |prev_index| {
628 const prev = self.getAtomPtr(prev_index);
629 prev.next_index = atom.next_index;
588630 }
589 if (atom.next) |next| {
590 next.prev = atom.prev;
631 if (atom.next_index) |next_index| {
632 const next = self.getAtomPtr(next_index);
633 next.prev_index = atom.prev_index;
591634 }
592635
593 if (atom_placement) |big_atom| {
594 atom.prev = big_atom;
595 atom.next = big_atom.next;
596 big_atom.next = atom;
636 if (atom_placement) |big_atom_index| {
637 const big_atom = self.getAtomPtr(big_atom_index);
638 const atom_ptr = self.getAtomPtr(atom_index);
639 atom_ptr.prev_index = big_atom_index;
640 atom_ptr.next_index = big_atom.next_index;
641 big_atom.next_index = atom_index;
597642 } else {
598 atom.prev = null;
599 atom.next = null;
643 const atom_ptr = self.getAtomPtr(atom_index);
644 atom_ptr.prev_index = null;
645 atom_ptr.next_index = null;
600646 }
601647 if (free_list_removal) |i| {
602648 _ = free_list.swapRemove(i);
......@@ -701,24 +747,37 @@ pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 {
701747 return index;
702748}
703749
704fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
750pub fn createAtom(self: *Coff) !Atom.Index {
705751 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);
752 const atom_index = @intCast(Atom.Index, self.atoms.items.len);
753 const atom = try self.atoms.addOne(gpa);
754 const sym_index = try self.allocateSymbol();
755 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
756 atom.* = .{
757 .sym_index = sym_index,
758 .file = null,
759 .size = 0,
760 .alignment = 0,
761 .prev_index = null,
762 .next_index = null,
763 };
764 log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index });
765 return atom_index;
766}
767
768fn createGotAtom(self: *Coff, target: SymbolWithLoc) !Atom.Index {
769 const atom_index = try self.createAtom();
770 const atom = self.getAtomPtr(atom_index);
710771 atom.size = @sizeOf(u64);
711772 atom.alignment = @alignOf(u64);
712773
713 try self.managed_atoms.append(gpa, atom);
714
715774 const sym = atom.getSymbolPtr(self);
716775 sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1);
717 sym.value = try self.allocateAtom(atom, atom.size, atom.alignment);
776 sym.value = try self.allocateAtom(atom_index, atom.size, atom.alignment);
718777
719778 log.debug("allocated GOT atom at 0x{x}", .{sym.value});
720779
721 try atom.addRelocation(self, .{
780 try Atom.addRelocation(self, atom_index, .{
722781 .type = .direct,
723782 .target = target,
724783 .offset = 0,
......@@ -732,49 +791,46 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
732791 .UNDEFINED => @panic("TODO generate a binding for undefined GOT target"),
733792 .ABSOLUTE => {},
734793 .DEBUG => unreachable, // not possible
735 else => try atom.addBaseRelocation(self, 0),
794 else => try Atom.addBaseRelocation(self, atom_index, 0),
736795 }
737796
738 return atom;
797 return atom_index;
739798}
740799
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);
800fn createImportAtom(self: *Coff) !Atom.Index {
801 const atom_index = try self.createAtom();
802 const atom = self.getAtomPtr(atom_index);
747803 atom.size = @sizeOf(u64);
748804 atom.alignment = @alignOf(u64);
749805
750 try self.managed_atoms.append(gpa, atom);
751
752806 const sym = atom.getSymbolPtr(self);
753807 sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1);
754 sym.value = try self.allocateAtom(atom, atom.size, atom.alignment);
808 sym.value = try self.allocateAtom(atom_index, atom.size, atom.alignment);
755809
756810 log.debug("allocated import atom at 0x{x}", .{sym.value});
757811
758 return atom;
812 return atom_index;
759813}
760814
761fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 {
815fn growAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
816 const atom = self.getAtom(atom_index);
762817 const sym = atom.getSymbol(self);
763818 const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value;
764819 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
765820 if (!need_realloc) return sym.value;
766 return self.allocateAtom(atom, new_atom_size, alignment);
821 return self.allocateAtom(atom_index, new_atom_size, alignment);
767822}
768823
769fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u32) void {
824fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void {
770825 _ = self;
771 _ = atom;
826 _ = atom_index;
772827 _ = new_block_size;
773828 // TODO check the new capacity, and if it crosses the size threshold into a big enough
774829 // capacity, insert a free list node for it.
775830}
776831
777fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void {
832fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void {
833 const atom = self.getAtom(atom_index);
778834 const sym = atom.getSymbol(self);
779835 const section = self.sections.get(@enumToInt(sym.section_number) - 1);
780836 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
......@@ -784,18 +840,18 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void {
784840 file_offset + code.len,
785841 });
786842 try self.base.file.?.pwriteAll(code, file_offset);
787 try self.resolveRelocs(atom);
843 try self.resolveRelocs(atom_index);
788844}
789845
790fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void {
846fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {
791847 switch (self.ptr_width) {
792848 .p32 => {
793849 var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32);
794 try self.writeAtom(atom, &buffer);
850 try self.writeAtom(atom_index, &buffer);
795851 },
796852 .p64 => {
797853 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
798 try self.writeAtom(atom, &buffer);
854 try self.writeAtom(atom_index, &buffer);
799855 },
800856 }
801857}
......@@ -815,7 +871,8 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
815871 var it = self.relocs.valueIterator();
816872 while (it.next()) |relocs| {
817873 for (relocs.items) |*reloc| {
818 const target_atom = reloc.getTargetAtom(self) orelse continue;
874 const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;
875 const target_atom = self.getAtom(target_atom_index);
819876 const target_sym = target_atom.getSymbol(self);
820877 if (target_sym.value < addr) continue;
821878 reloc.dirty = true;
......@@ -823,24 +880,26 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
823880 }
824881}
825882
826fn resolveRelocs(self: *Coff, atom: *Atom) !void {
827 const relocs = self.relocs.get(atom) orelse return;
883fn resolveRelocs(self: *Coff, atom_index: Atom.Index) !void {
884 const relocs = self.relocs.get(atom_index) orelse return;
828885
829 log.debug("relocating '{s}'", .{atom.getName(self)});
886 log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)});
830887
831888 for (relocs.items) |*reloc| {
832889 if (!reloc.dirty) continue;
833 try reloc.resolve(atom, self);
890 try reloc.resolve(atom_index, self);
834891 }
835892}
836893
837fn freeAtom(self: *Coff, atom: *Atom) void {
838 log.debug("freeAtom {*}", .{atom});
894fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
895 log.debug("freeAtom {d}", .{atom_index});
896
897 const gpa = self.base.allocator;
839898
840899 // Remove any relocs and base relocs associated with this Atom
841 self.freeRelocationsForAtom(atom);
900 Atom.freeRelocations(self, atom_index);
842901
843 const gpa = self.base.allocator;
902 const atom = self.getAtom(atom_index);
844903 const sym = atom.getSymbol(self);
845904 const sect_id = @enumToInt(sym.section_number) - 1;
846905 const free_list = &self.sections.items(.free_list)[sect_id];
......@@ -849,45 +908,46 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
849908 var i: usize = 0;
850909 // TODO turn free_list into a hash map
851910 while (i < free_list.items.len) {
852 if (free_list.items[i] == atom) {
911 if (free_list.items[i] == atom_index) {
853912 _ = free_list.swapRemove(i);
854913 continue;
855914 }
856 if (free_list.items[i] == atom.prev) {
915 if (free_list.items[i] == atom.prev_index) {
857916 already_have_free_list_node = true;
858917 }
859918 i += 1;
860919 }
861920 }
862921
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| {
922 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
923 if (maybe_last_atom_index.*) |last_atom_index| {
924 if (last_atom_index == atom_index) {
925 if (atom.prev_index) |prev_index| {
867926 // TODO shrink the section size here
868 maybe_last_atom.* = prev;
927 maybe_last_atom_index.* = prev_index;
869928 } else {
870 maybe_last_atom.* = null;
929 maybe_last_atom_index.* = null;
871930 }
872931 }
873932 }
874933
875 if (atom.prev) |prev| {
876 prev.next = atom.next;
934 if (atom.prev_index) |prev_index| {
935 const prev = self.getAtomPtr(prev_index);
936 prev.next_index = atom.next_index;
877937
878 if (!already_have_free_list_node and prev.freeListEligible(self)) {
938 if (!already_have_free_list_node and prev.*.freeListEligible(self)) {
879939 // The free list is heuristics, it doesn't have to be perfect, so we can
880940 // ignore the OOM here.
881 free_list.append(gpa, prev) catch {};
941 free_list.append(gpa, prev_index) catch {};
882942 }
883943 } else {
884 atom.prev = null;
944 self.getAtomPtr(atom_index).prev_index = null;
885945 }
886946
887 if (atom.next) |next| {
888 next.prev = atom.prev;
947 if (atom.next_index) |next_index| {
948 self.getAtomPtr(next_index).prev_index = atom.prev_index;
889949 } else {
890 atom.next = null;
950 self.getAtomPtr(atom_index).next_index = null;
891951 }
892952
893953 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
......@@ -910,7 +970,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
910970 self.locals.items[sym_index].section_number = .UNDEFINED;
911971 _ = self.atom_by_index_table.remove(sym_index);
912972 log.debug(" adding local symbol index {d} to free list", .{sym_index});
913 atom.sym_index = 0;
973 self.getAtomPtr(atom_index).sym_index = 0;
914974}
915975
916976pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
......@@ -927,15 +987,10 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
927987
928988 const decl_index = func.owner_decl;
929989 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 }
990
991 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
992 self.freeUnnamedConsts(decl_index);
993 Atom.freeRelocations(self, atom_index);
939994
940995 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
941996 defer code_buffer.deinit();
......@@ -979,11 +1034,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
9791034 }
9801035 const unnamed_consts = gop.value_ptr;
9811036
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);
1037 const atom_index = try self.createAtom();
9871038
9881039 const sym_name = blk: {
9891040 const decl_name = try decl.getFullyQualifiedName(mod);
......@@ -993,11 +1044,15 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
9931044 break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
9941045 };
9951046 defer gpa.free(sym_name);
996 try self.setSymbolName(atom.getSymbolPtr(self), sym_name);
997 atom.getSymbolPtr(self).section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1);
1047 {
1048 const atom = self.getAtom(atom_index);
1049 const sym = atom.getSymbolPtr(self);
1050 try self.setSymbolName(sym, sym_name);
1051 sym.section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1);
1052 }
9981053
9991054 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{
1000 .parent_atom_index = atom.getSymbolIndex().?,
1055 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
10011056 });
10021057 const code = switch (res) {
10031058 .ok => code_buffer.items,
......@@ -1010,17 +1065,18 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
10101065 };
10111066
10121067 const required_alignment = tv.ty.abiAlignment(self.base.options.target);
1068 const atom = self.getAtomPtr(atom_index);
10131069 atom.alignment = required_alignment;
10141070 atom.size = @intCast(u32, code.len);
1015 atom.getSymbolPtr(self).value = try self.allocateAtom(atom, atom.size, atom.alignment);
1016 errdefer self.freeAtom(atom);
1071 atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, atom.alignment);
1072 errdefer self.freeAtom(atom_index);
10171073
1018 try unnamed_consts.append(gpa, atom);
1074 try unnamed_consts.append(gpa, atom_index);
10191075
10201076 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value });
10211077 log.debug(" (required alignment 0x{x})", .{required_alignment});
10221078
1023 try self.writeAtom(atom, code);
1079 try self.writeAtom(atom_index, code);
10241080
10251081 return atom.getSymbolIndex().?;
10261082}
......@@ -1047,14 +1103,9 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
10471103 }
10481104 }
10491105
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 }
1106 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
1107 Atom.freeRelocations(self, atom_index);
1108 const atom = self.getAtom(atom_index);
10581109
10591110 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
10601111 defer code_buffer.deinit();
......@@ -1064,7 +1115,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
10641115 .ty = decl.ty,
10651116 .val = decl_val,
10661117 }, &code_buffer, .none, .{
1067 .parent_atom_index = decl.link.coff.getSymbolIndex().?,
1118 .parent_atom_index = atom.getSymbolIndex().?,
10681119 });
10691120 const code = switch (res) {
10701121 .ok => code_buffer.items,
......@@ -1082,7 +1133,20 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
10821133 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
10831134}
10841135
1085fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 {
1136pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {
1137 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1138 if (!gop.found_existing) {
1139 gop.value_ptr.* = .{
1140 .atom = try self.createAtom(),
1141 .section = self.getDeclOutputSection(decl_index),
1142 .exports = .{},
1143 };
1144 }
1145 return gop.value_ptr.atom;
1146}
1147
1148fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 {
1149 const decl = self.base.options.module.?.declPtr(decl_index);
10861150 const ty = decl.ty;
10871151 const zig_ty = ty.zigTypeTag();
10881152 const val = decl.val;
......@@ -1117,14 +1181,11 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
11171181 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
11181182 const required_alignment = decl.getAlignment(self.base.options.target);
11191183
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
1184 const decl_metadata = self.decls.get(decl_index).?;
1185 const atom_index = decl_metadata.atom;
1186 const atom = self.getAtom(atom_index);
1187 const sect_index = decl_metadata.section;
11261188 const code_len = @intCast(u32, code.len);
1127 const atom = &decl.link.coff;
11281189
11291190 if (atom.size != 0) {
11301191 const sym = atom.getSymbolPtr(self);
......@@ -1135,7 +1196,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
11351196 const capacity = atom.capacity(self);
11361197 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
11371198 if (need_realloc) {
1138 const vaddr = try self.growAtom(atom, code_len, required_alignment);
1199 const vaddr = try self.growAtom(atom_index, code_len, required_alignment);
11391200 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });
11401201 log.debug(" (required alignment 0x{x}", .{required_alignment});
11411202
......@@ -1143,49 +1204,43 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
11431204 sym.value = vaddr;
11441205 log.debug(" (updating GOT entry)", .{});
11451206 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };
1146 const got_atom = self.getGotAtomForSymbol(got_target).?;
1207 const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?;
11471208 self.markRelocsDirtyByTarget(got_target);
1148 try self.writePtrWidthAtom(got_atom);
1209 try self.writePtrWidthAtom(got_atom_index);
11491210 }
11501211 } else if (code_len < atom.size) {
1151 self.shrinkAtom(atom, code_len);
1212 self.shrinkAtom(atom_index, code_len);
11521213 }
1153 atom.size = code_len;
1214 self.getAtomPtr(atom_index).size = code_len;
11541215 } else {
11551216 const sym = atom.getSymbolPtr(self);
11561217 try self.setSymbolName(sym, decl_name);
11571218 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
11581219 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
11591220
1160 const vaddr = try self.allocateAtom(atom, code_len, required_alignment);
1161 errdefer self.freeAtom(atom);
1221 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
1222 errdefer self.freeAtom(atom_index);
11621223 log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr });
1163 atom.size = code_len;
1224 self.getAtomPtr(atom_index).size = code_len;
11641225 sym.value = vaddr;
11651226
11661227 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };
11671228 const got_index = try self.allocateGotEntry(got_target);
1168 const got_atom = try self.createGotAtom(got_target);
1229 const got_atom_index = try self.createGotAtom(got_target);
1230 const got_atom = self.getAtom(got_atom_index);
11691231 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
1170 try self.writePtrWidthAtom(got_atom);
1232 try self.writePtrWidthAtom(got_atom_index);
11711233 }
11721234
11731235 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);
1236 try self.writeAtom(atom_index, code);
11821237}
11831238
11841239fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void {
11851240 const gpa = self.base.allocator;
11861241 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
1187 for (unnamed_consts.items) |atom| {
1188 self.freeAtom(atom);
1242 for (unnamed_consts.items) |atom_index| {
1243 self.freeAtom(atom_index);
11891244 }
11901245 unnamed_consts.clearAndFree(gpa);
11911246}
......@@ -1200,11 +1255,11 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
12001255
12011256 log.debug("freeDecl {*}", .{decl});
12021257
1203 if (self.decls.fetchRemove(decl_index)) |kv| {
1204 if (kv.value) |_| {
1205 self.freeAtom(&decl.link.coff);
1206 self.freeUnnamedConsts(decl_index);
1207 }
1258 if (self.decls.fetchRemove(decl_index)) |const_kv| {
1259 var kv = const_kv;
1260 self.freeAtom(kv.value.atom);
1261 self.freeUnnamedConsts(decl_index);
1262 kv.value.exports.deinit(self.base.allocator);
12081263 }
12091264}
12101265
......@@ -1257,16 +1312,10 @@ pub fn updateDeclExports(
12571312 const gpa = self.base.allocator;
12581313
12591314 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
1315 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
1316 const atom = self.getAtom(atom_index);
12691317 const decl_sym = atom.getSymbol(self);
1318 const decl_metadata = self.decls.getPtr(decl_index).?;
12701319
12711320 for (exports) |exp| {
12721321 log.debug("adding new export '{s}'", .{exp.options.name});
......@@ -1301,9 +1350,9 @@ pub fn updateDeclExports(
13011350 continue;
13021351 }
13031352
1304 const sym_index = exp.link.coff.sym_index orelse blk: {
1353 const sym_index = decl_metadata.getExport(self, exp.options.name) orelse blk: {
13051354 const sym_index = try self.allocateSymbol();
1306 exp.link.coff.sym_index = sym_index;
1355 try decl_metadata.exports.append(gpa, sym_index);
13071356 break :blk sym_index;
13081357 };
13091358 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
......@@ -1326,16 +1375,15 @@ pub fn updateDeclExports(
13261375 }
13271376}
13281377
1329pub fn deleteExport(self: *Coff, exp: Export) void {
1378pub fn deleteDeclExport(self: *Coff, decl_index: Module.Decl.Index, name: []const u8) void {
13301379 if (self.llvm_object) |_| return;
1331 const sym_index = exp.sym_index orelse return;
1380 const metadata = self.decls.getPtr(decl_index) orelse return;
1381 const sym_index = metadata.getExportPtr(self, name) orelse return;
13321382
13331383 const gpa = self.base.allocator;
1334
1335 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1384 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
13361385 const sym = self.getSymbolPtr(sym_loc);
1337 const sym_name = self.getSymbolName(sym_loc);
1338 log.debug("deleting export '{s}'", .{sym_name});
1386 log.debug("deleting export '{s}'", .{name});
13391387 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
13401388 sym.* = .{
13411389 .name = [_]u8{0} ** 8,
......@@ -1345,9 +1393,9 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
13451393 .storage_class = .NULL,
13461394 .number_of_aux_symbols = 0,
13471395 };
1348 self.locals_free_list.append(gpa, sym_index) catch {};
1396 self.locals_free_list.append(gpa, sym_index.*) catch {};
13491397
1350 if (self.resolver.fetchRemove(sym_name)) |entry| {
1398 if (self.resolver.fetchRemove(name)) |entry| {
13511399 defer gpa.free(entry.key);
13521400 self.globals_free_list.append(gpa, entry.value) catch {};
13531401 self.globals.items[entry.value] = .{
......@@ -1355,6 +1403,8 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
13551403 .file = null,
13561404 };
13571405 }
1406
1407 sym_index.* = 0;
13581408}
13591409
13601410fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
......@@ -1419,9 +1469,10 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
14191469 if (self.imports_table.contains(global)) continue;
14201470
14211471 const import_index = try self.allocateImportEntry(global);
1422 const import_atom = try self.createImportAtom();
1472 const import_atom_index = try self.createImportAtom();
1473 const import_atom = self.getAtom(import_atom_index);
14231474 self.imports.items[import_index].sym_index = import_atom.getSymbolIndex().?;
1424 try self.writePtrWidthAtom(import_atom);
1475 try self.writePtrWidthAtom(import_atom_index);
14251476 }
14261477
14271478 if (build_options.enable_logging) {
......@@ -1455,22 +1506,14 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
14551506 }
14561507}
14571508
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
1509pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
14661510 assert(self.llvm_object == null);
14671511
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 }).?;
1512 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
1513 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
1514 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
14721515 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1473 try atom.addRelocation(self, .{
1516 try Atom.addRelocation(self, atom_index, .{
14741517 .type = .direct,
14751518 .target = target,
14761519 .offset = @intCast(u32, reloc_info.offset),
......@@ -1478,7 +1521,7 @@ pub fn getDeclVAddr(
14781521 .pcrel = false,
14791522 .length = 3,
14801523 });
1481 try atom.addBaseRelocation(self, @intCast(u32, reloc_info.offset));
1524 try Atom.addBaseRelocation(self, atom_index, @intCast(u32, reloc_info.offset));
14821525
14831526 return 0;
14841527}
......@@ -1505,10 +1548,10 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
15051548 return global_index;
15061549}
15071550
1508pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !void {
1551pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void {
15091552 _ = self;
15101553 _ = module;
1511 _ = decl;
1554 _ = decl_index;
15121555 log.debug("TODO implement updateDeclLineNumber", .{});
15131556}
15141557
......@@ -1529,7 +1572,8 @@ fn writeBaseRelocations(self: *Coff) !void {
15291572
15301573 var it = self.base_relocs.iterator();
15311574 while (it.next()) |entry| {
1532 const atom = entry.key_ptr.*;
1575 const atom_index = entry.key_ptr.*;
1576 const atom = self.getAtom(atom_index);
15331577 const offsets = entry.value_ptr.*;
15341578
15351579 for (offsets.items) |offset| {
......@@ -1613,7 +1657,8 @@ fn writeImportTable(self: *Coff) !void {
16131657 const gpa = self.base.allocator;
16141658
16151659 const section = self.sections.get(self.idata_section_index.?);
1616 const last_atom = section.last_atom orelse return;
1660 const last_atom_index = section.last_atom_index orelse return;
1661 const last_atom = self.getAtom(last_atom_index);
16171662
16181663 const iat_rva = section.header.virtual_address;
16191664 const iat_size = last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer
......@@ -2051,27 +2096,37 @@ pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult
20512096 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
20522097}
20532098
2099pub fn getAtom(self: *const Coff, atom_index: Atom.Index) Atom {
2100 assert(atom_index < self.atoms.items.len);
2101 return self.atoms.items[atom_index];
2102}
2103
2104pub fn getAtomPtr(self: *Coff, atom_index: Atom.Index) *Atom {
2105 assert(atom_index < self.atoms.items.len);
2106 return &self.atoms.items[atom_index];
2107}
2108
20542109/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.
20552110/// Returns null on failure.
2056pub fn getAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
2111pub fn getAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
20572112 assert(sym_loc.file == null); // TODO linking with object files
20582113 return self.atom_by_index_table.get(sym_loc.sym_index);
20592114}
20602115
20612116/// Returns GOT atom that references `sym_loc` if one exists.
20622117/// Returns null otherwise.
2063pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
2118pub fn getGotAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
20642119 const got_index = self.got_entries_table.get(sym_loc) orelse return null;
20652120 const got_entry = self.got_entries.items[got_index];
2066 return self.getAtomForSymbol(.{ .sym_index = got_entry.sym_index, .file = null });
2121 return self.getAtomIndexForSymbol(.{ .sym_index = got_entry.sym_index, .file = null });
20672122}
20682123
20692124/// Returns import atom that references `sym_loc` if one exists.
20702125/// Returns null otherwise.
2071pub fn getImportAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
2126pub fn getImportAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
20722127 const imports_index = self.imports_table.get(sym_loc) orelse return null;
20732128 const imports_entry = self.imports.items[imports_index];
2074 return self.getAtomForSymbol(.{ .sym_index = imports_entry.sym_index, .file = null });
2129 return self.getAtomIndexForSymbol(.{ .sym_index = imports_entry.sym_index, .file = null });
20752130}
20762131
20772132fn 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: 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/Dwarf.zig+320-259
......@@ -18,31 +18,36 @@ const LinkBlock = File.LinkBlock;
1818const LinkFn = File.LinkFn;
1919const LinkerLoad = @import("../codegen.zig").LinkerLoad;
2020const Module = @import("../Module.zig");
21const Value = @import("../value.zig").Value;
21const StringTable = @import("strtab.zig").StringTable;
2222const Type = @import("../type.zig").Type;
23const Value = @import("../value.zig").Value;
2324
2425allocator: Allocator,
2526bin_file: *File,
2627ptr_width: PtrWidth,
2728target: std.Target,
2829
29/// A list of `File.LinkFn` whose Line Number Programs have surplus capacity.
30/// This is the same concept as `text_block_free_list`; see those doc comments.
31dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{},
32dbg_line_fn_first: ?*SrcFn = null,
33dbg_line_fn_last: ?*SrcFn = null,
30/// A list of `Atom`s whose Line Number Programs have surplus capacity.
31/// This is the same concept as `Section.free_list` in Elf; see those doc comments.
32src_fn_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},
33src_fn_first_index: ?Atom.Index = null,
34src_fn_last_index: ?Atom.Index = null,
35src_fns: std.ArrayListUnmanaged(Atom) = .{},
36src_fn_decls: AtomTable = .{},
3437
3538/// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity.
3639/// This is the same concept as `text_block_free_list`; see those doc comments.
37atom_free_list: std.AutoHashMapUnmanaged(*Atom, void) = .{},
38atom_first: ?*Atom = null,
39atom_last: ?*Atom = null,
40di_atom_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},
41di_atom_first_index: ?Atom.Index = null,
42di_atom_last_index: ?Atom.Index = null,
43di_atoms: std.ArrayListUnmanaged(Atom) = .{},
44di_atom_decls: AtomTable = .{},
4045
4146abbrev_table_offset: ?u64 = null,
4247
4348/// TODO replace with InternPool
4449/// Table of debug symbol names.
45strtab: std.ArrayListUnmanaged(u8) = .{},
50strtab: StringTable(.strtab) = .{},
4651
4752/// Quick lookup array of all defined source files referenced by at least one Decl.
4853/// They will end up in the DWARF debug_line header as two lists:
......@@ -50,22 +55,23 @@ strtab: std.ArrayListUnmanaged(u8) = .{},
5055/// * []file_names
5156di_files: std.AutoArrayHashMapUnmanaged(*const Module.File, void) = .{},
5257
53/// List of atoms that are owned directly by the DWARF module.
54/// TODO convert links in DebugInfoAtom into indices and make
55/// sure every atom is owned by this module.
56managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
57
5858global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
5959
60pub const Atom = struct {
61 /// Previous/next linked list pointers.
62 /// This is the linked list node for this Decl's corresponding .debug_info tag.
63 prev: ?*Atom,
64 next: ?*Atom,
65 /// Offset into .debug_info pointing to the tag for this Decl.
60const AtomTable = std.AutoHashMapUnmanaged(Module.Decl.Index, Atom.Index);
61
62const Atom = struct {
63 /// Offset into .debug_info pointing to the tag for this Decl, or
64 /// offset from the beginning of the Debug Line Program header that contains this function.
6665 off: u32,
67 /// Size of the .debug_info tag for this Decl, not including padding.
66 /// Size of the .debug_info tag for this Decl, not including padding, or
67 /// size of the line number program component belonging to this function, not
68 /// including padding.
6869 len: u32,
70
71 prev_index: ?Index,
72 next_index: ?Index,
73
74 pub const Index = u32;
6975};
7076
7177/// Represents state of the analysed Decl.
......@@ -75,6 +81,7 @@ pub const Atom = struct {
7581pub const DeclState = struct {
7682 gpa: Allocator,
7783 mod: *Module,
84 di_atom_decls: *const AtomTable,
7885 dbg_line: std.ArrayList(u8),
7986 dbg_info: std.ArrayList(u8),
8087 abbrev_type_arena: std.heap.ArenaAllocator,
......@@ -88,10 +95,11 @@ pub const DeclState = struct {
8895 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
8996 exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{},
9097
91 fn init(gpa: Allocator, mod: *Module) DeclState {
98 fn init(gpa: Allocator, mod: *Module, di_atom_decls: *const AtomTable) DeclState {
9299 return .{
93100 .gpa = gpa,
94101 .mod = mod,
102 .di_atom_decls = di_atom_decls,
95103 .dbg_line = std.ArrayList(u8).init(gpa),
96104 .dbg_info = std.ArrayList(u8).init(gpa),
97105 .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),
......@@ -119,11 +127,11 @@ pub const DeclState = struct {
119127
120128 /// Adds local type relocation of the form: @offset => @this + addend
121129 /// @this signifies the offset within the .debug_abbrev section of the containing atom.
122 fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void {
130 fn addTypeRelocLocal(self: *DeclState, atom_index: Atom.Index, offset: u32, addend: u32) !void {
123131 log.debug("{x}: @this + {x}", .{ offset, addend });
124132 try self.abbrev_relocs.append(self.gpa, .{
125133 .target = null,
126 .atom = atom,
134 .atom_index = atom_index,
127135 .offset = offset,
128136 .addend = addend,
129137 });
......@@ -132,13 +140,13 @@ pub const DeclState = struct {
132140 /// Adds global type relocation of the form: @offset => @symbol + 0
133141 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section
134142 /// which we use as our target of the relocation.
135 fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void {
143 fn addTypeRelocGlobal(self: *DeclState, atom_index: Atom.Index, ty: Type, offset: u32) !void {
136144 const resolv = self.abbrev_resolver.getContext(ty, .{
137145 .mod = self.mod,
138146 }) orelse blk: {
139147 const sym_index = @intCast(u32, self.abbrev_table.items.len);
140148 try self.abbrev_table.append(self.gpa, .{
141 .atom = atom,
149 .atom_index = atom_index,
142150 .type = ty,
143151 .offset = undefined,
144152 });
......@@ -153,7 +161,7 @@ pub const DeclState = struct {
153161 log.debug("{x}: %{d} + 0", .{ offset, resolv });
154162 try self.abbrev_relocs.append(self.gpa, .{
155163 .target = resolv,
156 .atom = atom,
164 .atom_index = atom_index,
157165 .offset = offset,
158166 .addend = 0,
159167 });
......@@ -162,7 +170,7 @@ pub const DeclState = struct {
162170 fn addDbgInfoType(
163171 self: *DeclState,
164172 module: *Module,
165 atom: *Atom,
173 atom_index: Atom.Index,
166174 ty: Type,
167175 ) error{OutOfMemory}!void {
168176 const arena = self.abbrev_type_arena.allocator();
......@@ -227,7 +235,7 @@ pub const DeclState = struct {
227235 // DW.AT.type, DW.FORM.ref4
228236 var index = dbg_info_buffer.items.len;
229237 try dbg_info_buffer.resize(index + 4);
230 try self.addTypeRelocGlobal(atom, Type.bool, @intCast(u32, index));
238 try self.addTypeRelocGlobal(atom_index, Type.bool, @intCast(u32, index));
231239 // DW.AT.data_member_location, DW.FORM.sdata
232240 try dbg_info_buffer.ensureUnusedCapacity(6);
233241 dbg_info_buffer.appendAssumeCapacity(0);
......@@ -239,7 +247,7 @@ pub const DeclState = struct {
239247 // DW.AT.type, DW.FORM.ref4
240248 index = dbg_info_buffer.items.len;
241249 try dbg_info_buffer.resize(index + 4);
242 try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index));
250 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index));
243251 // DW.AT.data_member_location, DW.FORM.sdata
244252 const offset = abi_size - payload_ty.abiSize(target);
245253 try leb128.writeULEB128(dbg_info_buffer.writer(), offset);
......@@ -270,7 +278,7 @@ pub const DeclState = struct {
270278 try dbg_info_buffer.resize(index + 4);
271279 var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
272280 const ptr_ty = ty.slicePtrFieldType(buf);
273 try self.addTypeRelocGlobal(atom, ptr_ty, @intCast(u32, index));
281 try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(u32, index));
274282 // DW.AT.data_member_location, DW.FORM.sdata
275283 try dbg_info_buffer.ensureUnusedCapacity(6);
276284 dbg_info_buffer.appendAssumeCapacity(0);
......@@ -282,7 +290,7 @@ pub const DeclState = struct {
282290 // DW.AT.type, DW.FORM.ref4
283291 index = dbg_info_buffer.items.len;
284292 try dbg_info_buffer.resize(index + 4);
285 try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index));
293 try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index));
286294 // DW.AT.data_member_location, DW.FORM.sdata
287295 try dbg_info_buffer.ensureUnusedCapacity(2);
288296 dbg_info_buffer.appendAssumeCapacity(ptr_bytes);
......@@ -294,7 +302,7 @@ pub const DeclState = struct {
294302 // DW.AT.type, DW.FORM.ref4
295303 const index = dbg_info_buffer.items.len;
296304 try dbg_info_buffer.resize(index + 4);
297 try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index));
305 try self.addTypeRelocGlobal(atom_index, ty.childType(), @intCast(u32, index));
298306 }
299307 },
300308 .Array => {
......@@ -305,13 +313,13 @@ pub const DeclState = struct {
305313 // DW.AT.type, DW.FORM.ref4
306314 var index = dbg_info_buffer.items.len;
307315 try dbg_info_buffer.resize(index + 4);
308 try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index));
316 try self.addTypeRelocGlobal(atom_index, ty.childType(), @intCast(u32, index));
309317 // DW.AT.subrange_type
310318 try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim));
311319 // DW.AT.type, DW.FORM.ref4
312320 index = dbg_info_buffer.items.len;
313321 try dbg_info_buffer.resize(index + 4);
314 try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index));
322 try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index));
315323 // DW.AT.count, DW.FORM.udata
316324 const len = ty.arrayLenIncludingSentinel();
317325 try leb128.writeULEB128(dbg_info_buffer.writer(), len);
......@@ -339,7 +347,7 @@ pub const DeclState = struct {
339347 // DW.AT.type, DW.FORM.ref4
340348 var index = dbg_info_buffer.items.len;
341349 try dbg_info_buffer.resize(index + 4);
342 try self.addTypeRelocGlobal(atom, field, @intCast(u32, index));
350 try self.addTypeRelocGlobal(atom_index, field, @intCast(u32, index));
343351 // DW.AT.data_member_location, DW.FORM.sdata
344352 const field_off = ty.structFieldOffset(field_index, target);
345353 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
......@@ -371,7 +379,7 @@ pub const DeclState = struct {
371379 // DW.AT.type, DW.FORM.ref4
372380 var index = dbg_info_buffer.items.len;
373381 try dbg_info_buffer.resize(index + 4);
374 try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index));
382 try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index));
375383 // DW.AT.data_member_location, DW.FORM.sdata
376384 const field_off = ty.structFieldOffset(field_index, target);
377385 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
......@@ -454,7 +462,7 @@ pub const DeclState = struct {
454462 // DW.AT.type, DW.FORM.ref4
455463 const inner_union_index = dbg_info_buffer.items.len;
456464 try dbg_info_buffer.resize(inner_union_index + 4);
457 try self.addTypeRelocLocal(atom, @intCast(u32, inner_union_index), 5);
465 try self.addTypeRelocLocal(atom_index, @intCast(u32, inner_union_index), 5);
458466 // DW.AT.data_member_location, DW.FORM.sdata
459467 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
460468 }
......@@ -481,7 +489,7 @@ pub const DeclState = struct {
481489 // DW.AT.type, DW.FORM.ref4
482490 const index = dbg_info_buffer.items.len;
483491 try dbg_info_buffer.resize(index + 4);
484 try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index));
492 try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index));
485493 // DW.AT.data_member_location, DW.FORM.sdata
486494 try dbg_info_buffer.append(0);
487495 }
......@@ -498,7 +506,7 @@ pub const DeclState = struct {
498506 // DW.AT.type, DW.FORM.ref4
499507 const index = dbg_info_buffer.items.len;
500508 try dbg_info_buffer.resize(index + 4);
501 try self.addTypeRelocGlobal(atom, union_obj.tag_ty, @intCast(u32, index));
509 try self.addTypeRelocGlobal(atom_index, union_obj.tag_ty, @intCast(u32, index));
502510 // DW.AT.data_member_location, DW.FORM.sdata
503511 try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
504512
......@@ -541,7 +549,7 @@ pub const DeclState = struct {
541549 // DW.AT.type, DW.FORM.ref4
542550 var index = dbg_info_buffer.items.len;
543551 try dbg_info_buffer.resize(index + 4);
544 try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index));
552 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index));
545553 // DW.AT.data_member_location, DW.FORM.sdata
546554 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
547555
......@@ -554,7 +562,7 @@ pub const DeclState = struct {
554562 // DW.AT.type, DW.FORM.ref4
555563 index = dbg_info_buffer.items.len;
556564 try dbg_info_buffer.resize(index + 4);
557 try self.addTypeRelocGlobal(atom, error_ty, @intCast(u32, index));
565 try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(u32, index));
558566 // DW.AT.data_member_location, DW.FORM.sdata
559567 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
560568
......@@ -587,12 +595,11 @@ pub const DeclState = struct {
587595 self: *DeclState,
588596 name: [:0]const u8,
589597 ty: Type,
590 tag: File.Tag,
591598 owner_decl: Module.Decl.Index,
592599 loc: DbgInfoLoc,
593600 ) error{OutOfMemory}!void {
594601 const dbg_info = &self.dbg_info;
595 const atom = getDbgInfoAtom(tag, self.mod, owner_decl);
602 const atom_index = self.di_atom_decls.get(owner_decl).?;
596603 const name_with_null = name.ptr[0 .. name.len + 1];
597604
598605 switch (loc) {
......@@ -637,7 +644,7 @@ pub const DeclState = struct {
637644 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
638645 const index = dbg_info.items.len;
639646 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
640 try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4
647 try self.addTypeRelocGlobal(atom_index, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4
641648 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
642649 }
643650
......@@ -645,13 +652,12 @@ pub const DeclState = struct {
645652 self: *DeclState,
646653 name: [:0]const u8,
647654 ty: Type,
648 tag: File.Tag,
649655 owner_decl: Module.Decl.Index,
650656 is_ptr: bool,
651657 loc: DbgInfoLoc,
652658 ) error{OutOfMemory}!void {
653659 const dbg_info = &self.dbg_info;
654 const atom = getDbgInfoAtom(tag, self.mod, owner_decl);
660 const atom_index = self.di_atom_decls.get(owner_decl).?;
655661 const name_with_null = name.ptr[0 .. name.len + 1];
656662 try dbg_info.append(@enumToInt(AbbrevKind.variable));
657663 const target = self.mod.getTarget();
......@@ -781,7 +787,7 @@ pub const DeclState = struct {
781787 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
782788 const index = dbg_info.items.len;
783789 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
784 try self.addTypeRelocGlobal(atom, child_ty, @intCast(u32, index));
790 try self.addTypeRelocGlobal(atom_index, child_ty, @intCast(u32, index));
785791 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
786792 }
787793
......@@ -814,7 +820,7 @@ pub const DeclState = struct {
814820};
815821
816822pub const AbbrevEntry = struct {
817 atom: *const Atom,
823 atom_index: Atom.Index,
818824 type: Type,
819825 offset: u32,
820826};
......@@ -823,7 +829,7 @@ pub const AbbrevRelocation = struct {
823829 /// If target is null, we deal with a local relocation that is based on simple offset + addend
824830 /// only.
825831 target: ?u32,
826 atom: *const Atom,
832 atom_index: Atom.Index,
827833 offset: u32,
828834 addend: u32,
829835};
......@@ -840,26 +846,6 @@ pub const ExprlocRelocation = struct {
840846 offset: u32,
841847};
842848
843pub const SrcFn = struct {
844 /// Offset from the beginning of the Debug Line Program header that contains this function.
845 off: u32,
846 /// Size of the line number program component belonging to this function, not
847 /// including padding.
848 len: u32,
849
850 /// Points to the previous and next neighbors, based on the offset from .debug_line.
851 /// This can be used to find, for example, the capacity of this `SrcFn`.
852 prev: ?*SrcFn,
853 next: ?*SrcFn,
854
855 pub const empty: SrcFn = .{
856 .off = 0,
857 .len = 0,
858 .prev = null,
859 .next = null,
860 };
861};
862
863849pub const PtrWidth = enum { p32, p64 };
864850
865851pub const AbbrevKind = enum(u8) {
......@@ -909,16 +895,18 @@ pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf {
909895
910896pub fn deinit(self: *Dwarf) void {
911897 const gpa = self.allocator;
912 self.dbg_line_fn_free_list.deinit(gpa);
913 self.atom_free_list.deinit(gpa);
898
899 self.src_fn_free_list.deinit(gpa);
900 self.src_fns.deinit(gpa);
901 self.src_fn_decls.deinit(gpa);
902
903 self.di_atom_free_list.deinit(gpa);
904 self.di_atoms.deinit(gpa);
905 self.di_atom_decls.deinit(gpa);
906
914907 self.strtab.deinit(gpa);
915908 self.di_files.deinit(gpa);
916909 self.global_abbrev_relocs.deinit(gpa);
917
918 for (self.managed_atoms.items) |atom| {
919 gpa.destroy(atom);
920 }
921 self.managed_atoms.deinit(gpa);
922910}
923911
924912/// Initializes Decl's state and its matching output buffers.
......@@ -934,15 +922,19 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
934922 log.debug("initDeclState {s}{*}", .{ decl_name, decl });
935923
936924 const gpa = self.allocator;
937 var decl_state = DeclState.init(gpa, mod);
925 var decl_state = DeclState.init(gpa, mod, &self.di_atom_decls);
938926 errdefer decl_state.deinit();
939927 const dbg_line_buffer = &decl_state.dbg_line;
940928 const dbg_info_buffer = &decl_state.dbg_info;
941929
930 const di_atom_index = try self.getOrCreateAtomForDecl(.di_atom, decl_index);
931
942932 assert(decl.has_tv);
943933
944934 switch (decl.ty.zigTypeTag()) {
945935 .Fn => {
936 _ = try self.getOrCreateAtomForDecl(.src_fn, decl_index);
937
946938 // For functions we need to add a prologue to the debug line program.
947939 try dbg_line_buffer.ensureTotalCapacity(26);
948940
......@@ -1002,8 +994,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
1002994 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
1003995 //
1004996 if (fn_ret_has_bits) {
1005 const atom = getDbgInfoAtom(self.bin_file.tag, mod, decl_index);
1006 try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
997 try decl_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
1007998 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
1008999 }
10091000
......@@ -1075,31 +1066,28 @@ pub fn commitDeclState(
10751066 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
10761067 // `TextBlock` and the .debug_info. If you are editing this logic, you
10771068 // probably need to edit that logic too.
1078 const src_fn = switch (self.bin_file.tag) {
1079 .elf => &decl.fn_link.elf,
1080 .macho => &decl.fn_link.macho,
1081 .wasm => &decl.fn_link.wasm.src_fn,
1082 else => unreachable, // TODO
1083 };
1069 const src_fn_index = self.src_fn_decls.get(decl_index).?;
1070 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
10841071 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
10851072
1086 if (self.dbg_line_fn_last) |last| blk: {
1087 if (src_fn == last) break :blk;
1088 if (src_fn.next) |next| {
1073 if (self.src_fn_last_index) |last_index| blk: {
1074 if (src_fn_index == last_index) break :blk;
1075 if (src_fn.next_index) |next_index| {
1076 const next = self.getAtomPtr(.src_fn, next_index);
10891077 // Update existing function - non-last item.
10901078 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
10911079 // It grew too big, so we move it to a new location.
1092 if (src_fn.prev) |prev| {
1093 self.dbg_line_fn_free_list.put(gpa, prev, {}) catch {};
1094 prev.next = src_fn.next;
1080 if (src_fn.prev_index) |prev_index| {
1081 self.src_fn_free_list.put(gpa, prev_index, {}) catch {};
1082 self.getAtomPtr(.src_fn, prev_index).next_index = src_fn.next_index;
10951083 }
1096 next.prev = src_fn.prev;
1097 src_fn.next = null;
1084 next.prev_index = src_fn.prev_index;
1085 src_fn.next_index = null;
10981086 // Populate where it used to be with NOPs.
10991087 switch (self.bin_file.tag) {
11001088 .elf => {
11011089 const elf_file = self.bin_file.cast(File.Elf).?;
1102 const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?];
1090 const debug_line_sect = &elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
11031091 const file_pos = debug_line_sect.sh_offset + src_fn.off;
11041092 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
11051093 },
......@@ -1111,39 +1099,48 @@ pub fn commitDeclState(
11111099 },
11121100 .wasm => {
11131101 const wasm_file = self.bin_file.cast(File.Wasm).?;
1114 const debug_line = wasm_file.debug_line_atom.?.code;
1102 const debug_line = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
11151103 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);
11161104 },
11171105 else => unreachable,
11181106 }
11191107 // TODO Look at the free list before appending at the end.
1120 src_fn.prev = last;
1121 last.next = src_fn;
1122 self.dbg_line_fn_last = src_fn;
1108 src_fn.prev_index = last_index;
1109 const last = self.getAtomPtr(.src_fn, last_index);
1110 last.next_index = src_fn_index;
1111 self.src_fn_last_index = src_fn_index;
11231112
11241113 src_fn.off = last.off + padToIdeal(last.len);
11251114 }
1126 } else if (src_fn.prev == null) {
1115 } else if (src_fn.prev_index == null) {
11271116 // Append new function.
11281117 // TODO Look at the free list before appending at the end.
1129 src_fn.prev = last;
1130 last.next = src_fn;
1131 self.dbg_line_fn_last = src_fn;
1118 src_fn.prev_index = last_index;
1119 const last = self.getAtomPtr(.src_fn, last_index);
1120 last.next_index = src_fn_index;
1121 self.src_fn_last_index = src_fn_index;
11321122
11331123 src_fn.off = last.off + padToIdeal(last.len);
11341124 }
11351125 } else {
11361126 // This is the first function of the Line Number Program.
1137 self.dbg_line_fn_first = src_fn;
1138 self.dbg_line_fn_last = src_fn;
1127 self.src_fn_first_index = src_fn_index;
1128 self.src_fn_last_index = src_fn_index;
11391129
11401130 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));
11411131 }
11421132
1143 const last_src_fn = self.dbg_line_fn_last.?;
1133 const last_src_fn_index = self.src_fn_last_index.?;
1134 const last_src_fn = self.getAtom(.src_fn, last_src_fn_index);
11441135 const needed_size = last_src_fn.off + last_src_fn.len;
1145 const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
1146 const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
1136 const prev_padding_size: u32 = if (src_fn.prev_index) |prev_index| blk: {
1137 const prev = self.getAtom(.src_fn, prev_index);
1138 break :blk src_fn.off - (prev.off + prev.len);
1139 } else 0;
1140 const next_padding_size: u32 = if (src_fn.next_index) |next_index| blk: {
1141 const next = self.getAtom(.src_fn, next_index);
1142 break :blk next.off - (src_fn.off + src_fn.len);
1143 } else 0;
11471144
11481145 // We only have support for one compilation unit so far, so the offsets are directly
11491146 // from the .debug_line section.
......@@ -1152,7 +1149,7 @@ pub fn commitDeclState(
11521149 const elf_file = self.bin_file.cast(File.Elf).?;
11531150 const shdr_index = elf_file.debug_line_section_index.?;
11541151 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1155 const debug_line_sect = elf_file.sections.items[shdr_index];
1152 const debug_line_sect = elf_file.sections.items(.shdr)[shdr_index];
11561153 const file_pos = debug_line_sect.sh_offset + src_fn.off;
11571154 try pwriteDbgLineNops(
11581155 elf_file.base.file.?,
......@@ -1180,7 +1177,7 @@ pub fn commitDeclState(
11801177
11811178 .wasm => {
11821179 const wasm_file = self.bin_file.cast(File.Wasm).?;
1183 const atom = wasm_file.debug_line_atom.?;
1180 const atom = wasm_file.getAtomPtr(wasm_file.debug_line_atom.?);
11841181 const debug_line = &atom.code;
11851182 const segment_size = debug_line.items.len;
11861183 if (needed_size != segment_size) {
......@@ -1212,7 +1209,7 @@ pub fn commitDeclState(
12121209 if (dbg_info_buffer.items.len == 0)
12131210 return;
12141211
1215 const atom = getDbgInfoAtom(self.bin_file.tag, module, decl_index);
1212 const di_atom_index = self.di_atom_decls.get(decl_index).?;
12161213 if (decl_state.abbrev_table.items.len > 0) {
12171214 // Now we emit the .debug_info types of the Decl. These will count towards the size of
12181215 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
......@@ -1234,12 +1231,12 @@ pub fn commitDeclState(
12341231 if (deferred) continue;
12351232
12361233 symbol.offset = @intCast(u32, dbg_info_buffer.items.len);
1237 try decl_state.addDbgInfoType(module, atom, ty);
1234 try decl_state.addDbgInfoType(module, di_atom_index, ty);
12381235 }
12391236 }
12401237
12411238 log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name});
1242 try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len));
1239 try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len));
12431240
12441241 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
12451242 if (reloc.target) |target| {
......@@ -1260,11 +1257,12 @@ pub fn commitDeclState(
12601257 try self.global_abbrev_relocs.append(gpa, .{
12611258 .target = null,
12621259 .offset = reloc.offset,
1263 .atom = reloc.atom,
1260 .atom_index = reloc.atom_index,
12641261 .addend = reloc.addend,
12651262 });
12661263 } else {
1267 const value = symbol.atom.off + symbol.offset + reloc.addend;
1264 const atom = self.getAtom(.di_atom, symbol.atom_index);
1265 const value = atom.off + symbol.offset + reloc.addend;
12681266 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() });
12691267 mem.writeInt(
12701268 u32,
......@@ -1274,10 +1272,11 @@ pub fn commitDeclState(
12741272 );
12751273 }
12761274 } else {
1275 const atom = self.getAtom(.di_atom, reloc.atom_index);
12771276 mem.writeInt(
12781277 u32,
12791278 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
1280 reloc.atom.off + reloc.offset + reloc.addend,
1279 atom.off + reloc.offset + reloc.addend,
12811280 target_endian,
12821281 );
12831282 }
......@@ -1293,7 +1292,7 @@ pub fn commitDeclState(
12931292 .got_load => .got_load,
12941293 },
12951294 .target = reloc.target,
1296 .offset = reloc.offset + atom.off,
1295 .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
12971296 .addend = 0,
12981297 .prev_vaddr = 0,
12991298 });
......@@ -1303,10 +1302,10 @@ pub fn commitDeclState(
13031302 }
13041303
13051304 log.debug("writeDeclDebugInfo for '{s}", .{decl.name});
1306 try self.writeDeclDebugInfo(atom, dbg_info_buffer.items);
1305 try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items);
13071306}
13081307
1309fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
1308fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) !void {
13101309 const tracy = trace(@src());
13111310 defer tracy.end();
13121311
......@@ -1315,24 +1314,26 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
13151314 // probably need to edit that logic too.
13161315 const gpa = self.allocator;
13171316
1317 const atom = self.getAtomPtr(.di_atom, atom_index);
13181318 atom.len = len;
1319 if (self.atom_last) |last| blk: {
1320 if (atom == last) break :blk;
1321 if (atom.next) |next| {
1319 if (self.di_atom_last_index) |last_index| blk: {
1320 if (atom_index == last_index) break :blk;
1321 if (atom.next_index) |next_index| {
1322 const next = self.getAtomPtr(.di_atom, next_index);
13221323 // Update existing Decl - non-last item.
13231324 if (atom.off + atom.len + min_nop_size > next.off) {
13241325 // It grew too big, so we move it to a new location.
1325 if (atom.prev) |prev| {
1326 self.atom_free_list.put(gpa, prev, {}) catch {};
1327 prev.next = atom.next;
1326 if (atom.prev_index) |prev_index| {
1327 self.di_atom_free_list.put(gpa, prev_index, {}) catch {};
1328 self.getAtomPtr(.di_atom, prev_index).next_index = atom.next_index;
13281329 }
1329 next.prev = atom.prev;
1330 atom.next = null;
1330 next.prev_index = atom.prev_index;
1331 atom.next_index = null;
13311332 // Populate where it used to be with NOPs.
13321333 switch (self.bin_file.tag) {
13331334 .elf => {
13341335 const elf_file = self.bin_file.cast(File.Elf).?;
1335 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
1336 const debug_info_sect = &elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
13361337 const file_pos = debug_info_sect.sh_offset + atom.off;
13371338 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
13381339 },
......@@ -1344,37 +1345,40 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
13441345 },
13451346 .wasm => {
13461347 const wasm_file = self.bin_file.cast(File.Wasm).?;
1347 const debug_info = &wasm_file.debug_info_atom.?.code;
1348 const debug_info_index = wasm_file.debug_info_atom.?;
1349 const debug_info = &wasm_file.getAtomPtr(debug_info_index).code;
13481350 try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);
13491351 },
13501352 else => unreachable,
13511353 }
13521354 // TODO Look at the free list before appending at the end.
1353 atom.prev = last;
1354 last.next = atom;
1355 self.atom_last = atom;
1355 atom.prev_index = last_index;
1356 const last = self.getAtomPtr(.di_atom, last_index);
1357 last.next_index = atom_index;
1358 self.di_atom_last_index = atom_index;
13561359
13571360 atom.off = last.off + padToIdeal(last.len);
13581361 }
1359 } else if (atom.prev == null) {
1362 } else if (atom.prev_index == null) {
13601363 // Append new Decl.
13611364 // TODO Look at the free list before appending at the end.
1362 atom.prev = last;
1363 last.next = atom;
1364 self.atom_last = atom;
1365 atom.prev_index = last_index;
1366 const last = self.getAtomPtr(.di_atom, last_index);
1367 last.next_index = atom_index;
1368 self.di_atom_last_index = atom_index;
13651369
13661370 atom.off = last.off + padToIdeal(last.len);
13671371 }
13681372 } else {
13691373 // This is the first Decl of the .debug_info
1370 self.atom_first = atom;
1371 self.atom_last = atom;
1374 self.di_atom_first_index = atom_index;
1375 self.di_atom_last_index = atom_index;
13721376
13731377 atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes()));
13741378 }
13751379}
13761380
1377fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void {
1381fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []const u8) !void {
13781382 const tracy = trace(@src());
13791383 defer tracy.end();
13801384
......@@ -1383,14 +1387,22 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
13831387 // probably need to edit that logic too.
13841388 const gpa = self.allocator;
13851389
1386 const last_decl = self.atom_last.?;
1390 const atom = self.getAtom(.di_atom, atom_index);
1391 const last_decl_index = self.di_atom_last_index.?;
1392 const last_decl = self.getAtom(.di_atom, last_decl_index);
13871393 // +1 for a trailing zero to end the children of the decl tag.
13881394 const needed_size = last_decl.off + last_decl.len + 1;
1389 const prev_padding_size: u32 = if (atom.prev) |prev| atom.off - (prev.off + prev.len) else 0;
1390 const next_padding_size: u32 = if (atom.next) |next| next.off - (atom.off + atom.len) else 0;
1395 const prev_padding_size: u32 = if (atom.prev_index) |prev_index| blk: {
1396 const prev = self.getAtom(.di_atom, prev_index);
1397 break :blk atom.off - (prev.off + prev.len);
1398 } else 0;
1399 const next_padding_size: u32 = if (atom.next_index) |next_index| blk: {
1400 const next = self.getAtom(.di_atom, next_index);
1401 break :blk next.off - (atom.off + atom.len);
1402 } else 0;
13911403
13921404 // To end the children of the decl tag.
1393 const trailing_zero = atom.next == null;
1405 const trailing_zero = atom.next_index == null;
13941406
13951407 // We only have support for one compilation unit so far, so the offsets are directly
13961408 // from the .debug_info section.
......@@ -1399,7 +1411,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
13991411 const elf_file = self.bin_file.cast(File.Elf).?;
14001412 const shdr_index = elf_file.debug_info_section_index.?;
14011413 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1402 const debug_info_sect = elf_file.sections.items[shdr_index];
1414 const debug_info_sect = elf_file.sections.items(.shdr)[shdr_index];
14031415 const file_pos = debug_info_sect.sh_offset + atom.off;
14041416 try pwriteDbgInfoNops(
14051417 elf_file.base.file.?,
......@@ -1430,7 +1442,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
14301442 .wasm => {
14311443 const wasm_file = self.bin_file.cast(File.Wasm).?;
14321444 const info_atom = wasm_file.debug_info_atom.?;
1433 const debug_info = &info_atom.code;
1445 const debug_info = &wasm_file.getAtomPtr(info_atom).code;
14341446 const segment_size = debug_info.items.len;
14351447 if (needed_size != segment_size) {
14361448 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});
......@@ -1458,10 +1470,15 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
14581470 }
14591471}
14601472
1461pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {
1473pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.Decl.Index) !void {
14621474 const tracy = trace(@src());
14631475 defer tracy.end();
14641476
1477 const atom_index = try self.getOrCreateAtomForDecl(.src_fn, decl_index);
1478 const atom = self.getAtom(.src_fn, atom_index);
1479 if (atom.len == 0) return;
1480
1481 const decl = module.declPtr(decl_index);
14651482 const func = decl.val.castTag(.function).?.data;
14661483 log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{
14671484 decl.src_line,
......@@ -1475,79 +1492,81 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {
14751492 switch (self.bin_file.tag) {
14761493 .elf => {
14771494 const elf_file = self.bin_file.cast(File.Elf).?;
1478 const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?];
1479 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
1495 const shdr = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
1496 const file_pos = shdr.sh_offset + atom.off + self.getRelocDbgLineOff();
14801497 try elf_file.base.file.?.pwriteAll(&data, file_pos);
14811498 },
14821499 .macho => {
14831500 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
14841501 const sect = d_sym.getSection(d_sym.debug_line_section_index.?);
1485 const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff();
1502 const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
14861503 try d_sym.file.pwriteAll(&data, file_pos);
14871504 },
14881505 .wasm => {
14891506 const wasm_file = self.bin_file.cast(File.Wasm).?;
1490 const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff();
1491 const atom = wasm_file.debug_line_atom.?;
1492 mem.copy(u8, atom.code.items[offset..], &data);
1507 const offset = atom.off + self.getRelocDbgLineOff();
1508 const line_atom_index = wasm_file.debug_line_atom.?;
1509 mem.copy(u8, wasm_file.getAtomPtr(line_atom_index).code.items[offset..], &data);
14931510 },
14941511 else => unreachable,
14951512 }
14961513}
14971514
1498pub fn freeAtom(self: *Dwarf, atom: *Atom) void {
1499 if (self.atom_first == atom) {
1500 self.atom_first = atom.next;
1501 }
1502 if (self.atom_last == atom) {
1503 // TODO shrink the .debug_info section size here
1504 self.atom_last = atom.prev;
1505 }
1506
1507 if (atom.prev) |prev| {
1508 prev.next = atom.next;
1515pub fn freeDecl(self: *Dwarf, decl_index: Module.Decl.Index) void {
1516 const gpa = self.allocator;
15091517
1510 // TODO the free list logic like we do for text blocks above
1511 } else {
1512 atom.prev = null;
1518 // Free SrcFn atom
1519 if (self.src_fn_decls.fetchRemove(decl_index)) |kv| {
1520 const src_fn_index = kv.value;
1521 const src_fn = self.getAtom(.src_fn, src_fn_index);
1522 _ = self.src_fn_free_list.remove(src_fn_index);
1523
1524 if (src_fn.prev_index) |prev_index| {
1525 self.src_fn_free_list.put(gpa, prev_index, {}) catch {};
1526 const prev = self.getAtomPtr(.src_fn, prev_index);
1527 prev.next_index = src_fn.next_index;
1528 if (src_fn.next_index) |next_index| {
1529 self.getAtomPtr(.src_fn, next_index).prev_index = prev_index;
1530 } else {
1531 self.src_fn_last_index = prev_index;
1532 }
1533 } else if (src_fn.next_index) |next_index| {
1534 self.src_fn_first_index = next_index;
1535 self.getAtomPtr(.src_fn, next_index).prev_index = null;
1536 }
1537 if (self.src_fn_first_index == src_fn_index) {
1538 self.src_fn_first_index = src_fn.next_index;
1539 }
1540 if (self.src_fn_last_index == src_fn_index) {
1541 self.src_fn_last_index = src_fn.prev_index;
1542 }
15131543 }
15141544
1515 if (atom.next) |next| {
1516 next.prev = atom.prev;
1517 } else {
1518 atom.next = null;
1519 }
1520}
1545 // Free DI atom
1546 if (self.di_atom_decls.fetchRemove(decl_index)) |kv| {
1547 const di_atom_index = kv.value;
1548 const di_atom = self.getAtomPtr(.di_atom, di_atom_index);
15211549
1522pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {
1523 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
1524 // is desired for both.
1525 const gpa = self.allocator;
1526 const fn_link = switch (self.bin_file.tag) {
1527 .elf => &decl.fn_link.elf,
1528 .macho => &decl.fn_link.macho,
1529 .wasm => &decl.fn_link.wasm.src_fn,
1530 else => unreachable,
1531 };
1532 _ = self.dbg_line_fn_free_list.remove(fn_link);
1550 if (self.di_atom_first_index == di_atom_index) {
1551 self.di_atom_first_index = di_atom.next_index;
1552 }
1553 if (self.di_atom_last_index == di_atom_index) {
1554 // TODO shrink the .debug_info section size here
1555 self.di_atom_last_index = di_atom.prev_index;
1556 }
15331557
1534 if (fn_link.prev) |prev| {
1535 self.dbg_line_fn_free_list.put(gpa, prev, {}) catch {};
1536 prev.next = fn_link.next;
1537 if (fn_link.next) |next| {
1538 next.prev = prev;
1558 if (di_atom.prev_index) |prev_index| {
1559 self.getAtomPtr(.di_atom, prev_index).next_index = di_atom.next_index;
1560 // TODO the free list logic like we do for SrcFn above
15391561 } else {
1540 self.dbg_line_fn_last = prev;
1562 di_atom.prev_index = null;
1563 }
1564
1565 if (di_atom.next_index) |next_index| {
1566 self.getAtomPtr(.di_atom, next_index).prev_index = di_atom.prev_index;
1567 } else {
1568 di_atom.next_index = null;
15411569 }
1542 } else if (fn_link.next) |next| {
1543 self.dbg_line_fn_first = next;
1544 next.prev = null;
1545 }
1546 if (self.dbg_line_fn_first == fn_link) {
1547 self.dbg_line_fn_first = fn_link.next;
1548 }
1549 if (self.dbg_line_fn_last == fn_link) {
1550 self.dbg_line_fn_last = fn_link.prev;
15511570 }
15521571}
15531572
......@@ -1690,7 +1709,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
16901709 const elf_file = self.bin_file.cast(File.Elf).?;
16911710 const shdr_index = elf_file.debug_abbrev_section_index.?;
16921711 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false);
1693 const debug_abbrev_sect = elf_file.sections.items[shdr_index];
1712 const debug_abbrev_sect = elf_file.sections.items(.shdr)[shdr_index];
16941713 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;
16951714 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
16961715 },
......@@ -1704,7 +1723,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
17041723 },
17051724 .wasm => {
17061725 const wasm_file = self.bin_file.cast(File.Wasm).?;
1707 const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code;
1726 const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code;
17081727 try debug_abbrev.resize(wasm_file.base.allocator, needed_size);
17091728 mem.copy(u8, debug_abbrev.items, &abbrev_buf);
17101729 },
......@@ -1770,11 +1789,11 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
17701789 },
17711790 }
17721791 // Write the form for the compile unit, which must match the abbrev table above.
1773 const name_strp = try self.makeString(module.root_pkg.root_src_path);
1792 const name_strp = try self.strtab.insert(self.allocator, module.root_pkg.root_src_path);
17741793 var compile_unit_dir_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
17751794 const compile_unit_dir = resolveCompilationDir(module, &compile_unit_dir_buffer);
1776 const comp_dir_strp = try self.makeString(compile_unit_dir);
1777 const producer_strp = try self.makeString(link.producer_string);
1795 const comp_dir_strp = try self.strtab.insert(self.allocator, compile_unit_dir);
1796 const producer_strp = try self.strtab.insert(self.allocator, link.producer_string);
17781797
17791798 di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit));
17801799 if (self.bin_file.tag == .macho) {
......@@ -1805,7 +1824,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
18051824 switch (self.bin_file.tag) {
18061825 .elf => {
18071826 const elf_file = self.bin_file.cast(File.Elf).?;
1808 const debug_info_sect = elf_file.sections.items[elf_file.debug_info_section_index.?];
1827 const debug_info_sect = elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
18091828 const file_pos = debug_info_sect.sh_offset;
18101829 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
18111830 },
......@@ -1817,7 +1836,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
18171836 },
18181837 .wasm => {
18191838 const wasm_file = self.bin_file.cast(File.Wasm).?;
1820 const debug_info = &wasm_file.debug_info_atom.?.code;
1839 const debug_info = &wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
18211840 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
18221841 },
18231842 else => unreachable,
......@@ -2124,7 +2143,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
21242143 const elf_file = self.bin_file.cast(File.Elf).?;
21252144 const shdr_index = elf_file.debug_aranges_section_index.?;
21262145 try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false);
2127 const debug_aranges_sect = elf_file.sections.items[shdr_index];
2146 const debug_aranges_sect = elf_file.sections.items(.shdr)[shdr_index];
21282147 const file_pos = debug_aranges_sect.sh_offset;
21292148 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
21302149 },
......@@ -2138,7 +2157,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
21382157 },
21392158 .wasm => {
21402159 const wasm_file = self.bin_file.cast(File.Wasm).?;
2141 const debug_ranges = &wasm_file.debug_ranges_atom.?.code;
2160 const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code;
21422161 try debug_ranges.resize(wasm_file.base.allocator, needed_size);
21432162 mem.copy(u8, debug_ranges.items, di_buf.items);
21442163 },
......@@ -2275,19 +2294,23 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
22752294 const needed_with_padding = padToIdeal(needed_bytes);
22762295 const delta = needed_with_padding - dbg_line_prg_off;
22772296
2278 var src_fn = self.dbg_line_fn_first.?;
2279 const last_fn = self.dbg_line_fn_last.?;
2297 const first_fn_index = self.src_fn_first_index.?;
2298 const first_fn = self.getAtom(.src_fn, first_fn_index);
2299 const last_fn_index = self.src_fn_last_index.?;
2300 const last_fn = self.getAtom(.src_fn, last_fn_index);
2301
2302 var src_fn_index = first_fn_index;
22802303
2281 var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - src_fn.off);
2304 var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - first_fn.off);
22822305 defer gpa.free(buffer);
22832306
22842307 switch (self.bin_file.tag) {
22852308 .elf => {
22862309 const elf_file = self.bin_file.cast(File.Elf).?;
22872310 const shdr_index = elf_file.debug_line_section_index.?;
2288 const needed_size = elf_file.sections.items[shdr_index].sh_size + delta;
2311 const needed_size = elf_file.sections.items(.shdr)[shdr_index].sh_size + delta;
22892312 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
2290 const file_pos = elf_file.sections.items[shdr_index].sh_offset + src_fn.off;
2313 const file_pos = elf_file.sections.items(.shdr)[shdr_index].sh_offset + first_fn.off;
22912314
22922315 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
22932316 if (amt != buffer.len) return error.InputOutput;
......@@ -2299,7 +2322,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
22992322 const sect_index = d_sym.debug_line_section_index.?;
23002323 const needed_size = @intCast(u32, d_sym.getSection(sect_index).size + delta);
23012324 try d_sym.growSection(sect_index, needed_size, true);
2302 const file_pos = d_sym.getSection(sect_index).offset + src_fn.off;
2325 const file_pos = d_sym.getSection(sect_index).offset + first_fn.off;
23032326
23042327 const amt = try d_sym.file.preadAll(buffer, file_pos);
23052328 if (amt != buffer.len) return error.InputOutput;
......@@ -2308,19 +2331,20 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
23082331 },
23092332 .wasm => {
23102333 const wasm_file = self.bin_file.cast(File.Wasm).?;
2311 const debug_line = &wasm_file.debug_line_atom.?.code;
2312 mem.copy(u8, buffer, debug_line.items[src_fn.off..]);
2334 const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
2335 mem.copy(u8, buffer, debug_line.items[first_fn.off..]);
23132336 try debug_line.resize(self.allocator, debug_line.items.len + delta);
2314 mem.copy(u8, debug_line.items[src_fn.off + delta ..], buffer);
2337 mem.copy(u8, debug_line.items[first_fn.off + delta ..], buffer);
23152338 },
23162339 else => unreachable,
23172340 }
23182341
23192342 while (true) {
2343 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
23202344 src_fn.off += delta;
23212345
2322 if (src_fn.next) |next| {
2323 src_fn = next;
2346 if (src_fn.next_index) |next_index| {
2347 src_fn_index = next_index;
23242348 } else break;
23252349 }
23262350 }
......@@ -2346,7 +2370,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
23462370 switch (self.bin_file.tag) {
23472371 .elf => {
23482372 const elf_file = self.bin_file.cast(File.Elf).?;
2349 const debug_line_sect = elf_file.sections.items[elf_file.debug_line_section_index.?];
2373 const debug_line_sect = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
23502374 const file_pos = debug_line_sect.sh_offset;
23512375 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
23522376 },
......@@ -2358,7 +2382,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
23582382 },
23592383 .wasm => {
23602384 const wasm_file = self.bin_file.cast(File.Wasm).?;
2361 const debug_line = wasm_file.debug_line_atom.?.code;
2385 const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
23622386 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);
23632387 },
23642388 else => unreachable,
......@@ -2366,22 +2390,26 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
23662390}
23672391
23682392fn getDebugInfoOff(self: Dwarf) ?u32 {
2369 const first = self.atom_first orelse return null;
2393 const first_index = self.di_atom_first_index orelse return null;
2394 const first = self.getAtom(.di_atom, first_index);
23702395 return first.off;
23712396}
23722397
23732398fn getDebugInfoEnd(self: Dwarf) ?u32 {
2374 const last = self.atom_last orelse return null;
2399 const last_index = self.di_atom_last_index orelse return null;
2400 const last = self.getAtom(.di_atom, last_index);
23752401 return last.off + last.len;
23762402}
23772403
23782404fn getDebugLineProgramOff(self: Dwarf) ?u32 {
2379 const first = self.dbg_line_fn_first orelse return null;
2405 const first_index = self.src_fn_first_index orelse return null;
2406 const first = self.getAtom(.src_fn, first_index);
23802407 return first.off;
23812408}
23822409
23832410fn getDebugLineProgramEnd(self: Dwarf) ?u32 {
2384 const last = self.dbg_line_fn_last orelse return null;
2411 const last_index = self.src_fn_last_index orelse return null;
2412 const last = self.getAtom(.src_fn, last_index);
23852413 return last.off + last.len;
23862414}
23872415
......@@ -2435,15 +2463,6 @@ fn getRelocDbgInfoSubprogramHighPC(self: Dwarf) u32 {
24352463 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();
24362464}
24372465
2438/// TODO Improve this to use a table.
2439fn makeString(self: *Dwarf, bytes: []const u8) !u32 {
2440 try self.strtab.ensureUnusedCapacity(self.allocator, bytes.len + 1);
2441 const result = self.strtab.items.len;
2442 self.strtab.appendSliceAssumeCapacity(bytes);
2443 self.strtab.appendAssumeCapacity(0);
2444 return @intCast(u32, result);
2445}
2446
24472466fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
24482467 return actual_size +| (actual_size / ideal_factor);
24492468}
......@@ -2465,29 +2484,20 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
24652484 }
24662485 error_set.names = names;
24672486
2468 const atom = try gpa.create(Atom);
2469 errdefer gpa.destroy(atom);
2470 atom.* = .{
2471 .prev = null,
2472 .next = null,
2473 .off = 0,
2474 .len = 0,
2475 };
2476
24772487 var dbg_info_buffer = std.ArrayList(u8).init(arena);
24782488 try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer);
24792489
2480 try self.managed_atoms.append(gpa, atom);
2490 const di_atom_index = try self.createAtom(.di_atom);
24812491 log.debug("updateDeclDebugInfoAllocation in flushModule", .{});
2482 try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len));
2492 try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len));
24832493 log.debug("writeDeclDebugInfo in flushModule", .{});
2484 try self.writeDeclDebugInfo(atom, dbg_info_buffer.items);
2494 try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items);
24852495
24862496 const file_pos = blk: {
24872497 switch (self.bin_file.tag) {
24882498 .elf => {
24892499 const elf_file = self.bin_file.cast(File.Elf).?;
2490 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
2500 const debug_info_sect = &elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
24912501 break :blk debug_info_sect.sh_offset;
24922502 },
24932503 .macho => {
......@@ -2502,22 +2512,23 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
25022512 };
25032513
25042514 var buf: [@sizeOf(u32)]u8 = undefined;
2505 mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian());
2515 mem.writeInt(u32, &buf, self.getAtom(.di_atom, di_atom_index).off, self.target.cpu.arch.endian());
25062516
25072517 while (self.global_abbrev_relocs.popOrNull()) |reloc| {
2518 const atom = self.getAtom(.di_atom, reloc.atom_index);
25082519 switch (self.bin_file.tag) {
25092520 .elf => {
25102521 const elf_file = self.bin_file.cast(File.Elf).?;
2511 try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
2522 try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
25122523 },
25132524 .macho => {
25142525 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2515 try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
2526 try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
25162527 },
25172528 .wasm => {
25182529 const wasm_file = self.bin_file.cast(File.Wasm).?;
2519 const debug_info = wasm_file.debug_info_atom.?.code;
2520 mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf);
2530 const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
2531 mem.copy(u8, debug_info.items[atom.off + reloc.offset ..], &buf);
25212532 },
25222533 else => unreachable,
25232534 }
......@@ -2635,12 +2646,62 @@ fn addDbgInfoErrorSet(
26352646 try dbg_info_buffer.append(0);
26362647}
26372648
2638fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *Atom {
2639 const decl = mod.declPtr(decl_index);
2640 return switch (tag) {
2641 .elf => &decl.link.elf.dbg_info_atom,
2642 .macho => &decl.link.macho.dbg_info_atom,
2643 .wasm => &decl.link.wasm.dbg_info_atom,
2644 else => unreachable,
2649const Kind = enum { src_fn, di_atom };
2650
2651fn createAtom(self: *Dwarf, comptime kind: Kind) !Atom.Index {
2652 const index = blk: {
2653 switch (kind) {
2654 .src_fn => {
2655 const index = @intCast(Atom.Index, self.src_fns.items.len);
2656 _ = try self.src_fns.addOne(self.allocator);
2657 break :blk index;
2658 },
2659 .di_atom => {
2660 const index = @intCast(Atom.Index, self.di_atoms.items.len);
2661 _ = try self.di_atoms.addOne(self.allocator);
2662 break :blk index;
2663 },
2664 }
2665 };
2666 const atom = self.getAtomPtr(kind, index);
2667 atom.* = .{
2668 .off = 0,
2669 .len = 0,
2670 .prev_index = null,
2671 .next_index = null,
2672 };
2673 return index;
2674}
2675
2676fn getOrCreateAtomForDecl(self: *Dwarf, comptime kind: Kind, decl_index: Module.Decl.Index) !Atom.Index {
2677 switch (kind) {
2678 .src_fn => {
2679 const gop = try self.src_fn_decls.getOrPut(self.allocator, decl_index);
2680 if (!gop.found_existing) {
2681 gop.value_ptr.* = try self.createAtom(kind);
2682 }
2683 return gop.value_ptr.*;
2684 },
2685 .di_atom => {
2686 const gop = try self.di_atom_decls.getOrPut(self.allocator, decl_index);
2687 if (!gop.found_existing) {
2688 gop.value_ptr.* = try self.createAtom(kind);
2689 }
2690 return gop.value_ptr.*;
2691 },
2692 }
2693}
2694
2695fn getAtom(self: *const Dwarf, comptime kind: Kind, index: Atom.Index) Atom {
2696 return switch (kind) {
2697 .src_fn => self.src_fns.items[index],
2698 .di_atom => self.di_atoms.items[index],
2699 };
2700}
2701
2702fn getAtomPtr(self: *Dwarf, comptime kind: Kind, index: Atom.Index) *Atom {
2703 return switch (kind) {
2704 .src_fn => &self.src_fns.items[index],
2705 .di_atom => &self.di_atoms.items[index],
26452706 };
26462707}
src/link/Elf.zig+636-570
......@@ -1,43 +1,89 @@
11const Elf = @This();
22
33const std = @import("std");
4const build_options = @import("build_options");
45const builtin = @import("builtin");
5const math = std.math;
6const mem = std.mem;
76const assert = std.debug.assert;
8const Allocator = std.mem.Allocator;
9const fs = std.fs;
107const elf = std.elf;
8const fs = std.fs;
119const log = std.log.scoped(.link);
10const math = std.math;
11const mem = std.mem;
1212
13const Atom = @import("Elf/Atom.zig");
14const Module = @import("../Module.zig");
15const Compilation = @import("../Compilation.zig");
16const Dwarf = @import("Dwarf.zig");
1713const codegen = @import("../codegen.zig");
18const lldMain = @import("../main.zig").lldMain;
19const trace = @import("../tracy.zig").trace;
20const Package = @import("../Package.zig");
21const Value = @import("../value.zig").Value;
22const Type = @import("../type.zig").Type;
23const TypedValue = @import("../TypedValue.zig");
24const link = @import("../link.zig");
25const File = link.File;
26const build_options = @import("build_options");
27const target_util = @import("../target.zig");
2814const glibc = @import("../glibc.zig");
15const link = @import("../link.zig");
16const lldMain = @import("../main.zig").lldMain;
2917const musl = @import("../musl.zig");
30const Cache = @import("../Cache.zig");
18const target_util = @import("../target.zig");
19const trace = @import("../tracy.zig").trace;
20
3121const Air = @import("../Air.zig");
22const Allocator = std.mem.Allocator;
23pub const Atom = @import("Elf/Atom.zig");
24const Cache = @import("../Cache.zig");
25const Compilation = @import("../Compilation.zig");
26const Dwarf = @import("Dwarf.zig");
27const File = link.File;
3228const Liveness = @import("../Liveness.zig");
3329const LlvmObject = @import("../codegen/llvm.zig").Object;
34
35pub const TextBlock = Atom;
30const Module = @import("../Module.zig");
31const Package = @import("../Package.zig");
32const StringTable = @import("strtab.zig").StringTable;
33const Type = @import("../type.zig").Type;
34const TypedValue = @import("../TypedValue.zig");
35const Value = @import("../value.zig").Value;
3636
3737const default_entry_addr = 0x8000000;
3838
3939pub const base_tag: File.Tag = .elf;
4040
41const Section = struct {
42 shdr: elf.Elf64_Shdr,
43 phdr_index: u16,
44
45 /// Index of the last allocated atom in this section.
46 last_atom_index: ?Atom.Index = null,
47
48 /// A list of atoms that have surplus capacity. This list can have false
49 /// positives, as functions grow and shrink over time, only sometimes being added
50 /// or removed from the freelist.
51 ///
52 /// An atom has surplus capacity when its overcapacity value is greater than
53 /// padToIdeal(minimum_atom_size). That is, when it has so
54 /// much extra capacity, that we could fit a small new symbol in it, itself with
55 /// ideal_capacity or more.
56 ///
57 /// Ideal capacity is defined by size + (size / ideal_factor)
58 ///
59 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
60 /// overcapacity can be negative. A simple way to have negative overcapacity is to
61 /// allocate a fresh text block, which will have ideal capacity, and then grow it
62 /// by 1 byte. It will then have -1 overcapacity.
63 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
64};
65
66const DeclMetadata = struct {
67 atom: Atom.Index,
68 shdr: u16,
69 /// A list of all exports aliases of this Decl.
70 exports: std.ArrayListUnmanaged(u32) = .{},
71
72 fn getExport(m: DeclMetadata, elf_file: *const Elf, name: []const u8) ?u32 {
73 for (m.exports.items) |exp| {
74 if (mem.eql(u8, name, elf_file.getGlobalName(exp))) return exp;
75 }
76 return null;
77 }
78
79 fn getExportPtr(m: *DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 {
80 for (m.exports.items) |*exp| {
81 if (mem.eql(u8, name, elf_file.getGlobalName(exp.*))) return exp;
82 }
83 return null;
84 }
85};
86
4187base: File,
4288dwarf: ?Dwarf = null,
4389
......@@ -48,12 +94,12 @@ llvm_object: ?*LlvmObject = null,
4894
4995/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
5096/// Same order as in the file.
51sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){},
97sections: std.MultiArrayList(Section) = .{},
5298shdr_table_offset: ?u64 = null,
5399
54100/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
55101/// Same order as in the file.
56program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = std.ArrayListUnmanaged(elf.Elf64_Phdr){},
102program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
57103phdr_table_offset: ?u64 = null,
58104/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
59105phdr_load_re_index: ?u16 = null,
......@@ -65,12 +111,10 @@ phdr_load_ro_index: ?u16 = null,
65111/// The index into the program headers of a PT_LOAD program header with Write flag
66112phdr_load_rw_index: ?u16 = null,
67113
68phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
69
70114entry_addr: ?u64 = null,
71115page_size: u32,
72116
73shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
117shstrtab: StringTable(.strtab) = .{},
74118shstrtab_index: ?u16 = null,
75119
76120symtab_section_index: ?u16 = null,
......@@ -113,39 +157,14 @@ debug_line_header_dirty: bool = false,
113157
114158error_flags: File.ErrorFlags = File.ErrorFlags{},
115159
116/// Pointer to the last allocated atom
117atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{},
118
119/// A list of text blocks that have surplus capacity. This list can have false
120/// positives, as functions grow and shrink over time, only sometimes being added
121/// or removed from the freelist.
122///
123/// A text block has surplus capacity when its overcapacity value is greater than
124/// padToIdeal(minimum_text_block_size). That is, when it has so
125/// much extra capacity, that we could fit a small new symbol in it, itself with
126/// ideal_capacity or more.
127///
128/// Ideal capacity is defined by size + (size / ideal_factor)
129///
130/// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
131/// overcapacity can be negative. A simple way to have negative overcapacity is to
132/// allocate a fresh text block, which will have ideal capacity, and then grow it
133/// by 1 byte. It will then have -1 overcapacity.
134atom_free_lists: std.AutoHashMapUnmanaged(u16, std.ArrayListUnmanaged(*TextBlock)) = .{},
135
136/// Table of Decls that are currently alive.
137/// We store them here so that we can properly dispose of any allocated
138/// memory within the atom in the incremental linker.
139/// TODO consolidate this.
140decls: std.AutoHashMapUnmanaged(Module.Decl.Index, ?u16) = .{},
160/// Table of tracked Decls.
161decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
141162
142163/// List of atoms that are owned directly by the linker.
143/// Currently these are only atoms that are the result of linking
144/// object files. Atoms which take part in incremental linking are
145/// at present owned by Module.Decl.
146/// TODO consolidate this.
147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},
148atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{},
164atoms: std.ArrayListUnmanaged(Atom) = .{},
165
166/// Table of atoms indexed by the symbol index.
167atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
149168
150169/// Table of unnamed constants associated with a parent `Decl`.
151170/// We store them here so that we can free the constants whenever the `Decl`
......@@ -173,15 +192,8 @@ unnamed_const_atoms: UnnamedConstTable = .{},
173192/// this will be a table indexed by index into the list of Atoms.
174193relocs: RelocTable = .{},
175194
176const Reloc = struct {
177 target: u32,
178 offset: u64,
179 addend: u32,
180 prev_vaddr: u64,
181};
182
183const RelocTable = std.AutoHashMapUnmanaged(*TextBlock, std.ArrayListUnmanaged(Reloc));
184const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*TextBlock));
195const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
196const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
185197
186198/// When allocating, the ideal_capacity is calculated by
187199/// actual_capacity + (actual_capacity / ideal_factor)
......@@ -190,15 +202,11 @@ const ideal_factor = 3;
190202/// In order for a slice of bytes to be considered eligible to keep metadata pointing at
191203/// it as a possible place to put new symbols, it must have enough room for this many bytes
192204/// (plus extra for reserved capacity).
193const minimum_text_block_size = 64;
194pub const min_text_capacity = padToIdeal(minimum_text_block_size);
205const minimum_atom_size = 64;
206pub const min_text_capacity = padToIdeal(minimum_atom_size);
195207
196208pub const PtrWidth = enum { p32, p64 };
197209
198pub const Export = struct {
199 sym_index: ?u32 = null,
200};
201
202210pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
203211 assert(options.target.ofmt == .elf);
204212
......@@ -230,16 +238,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
230238
231239 // There must always be a null section in index 0
232240 try self.sections.append(allocator, .{
233 .sh_name = 0,
234 .sh_type = elf.SHT_NULL,
235 .sh_flags = 0,
236 .sh_addr = 0,
237 .sh_offset = 0,
238 .sh_size = 0,
239 .sh_link = 0,
240 .sh_info = 0,
241 .sh_addralign = 0,
242 .sh_entsize = 0,
241 .shdr = .{
242 .sh_name = 0,
243 .sh_type = elf.SHT_NULL,
244 .sh_flags = 0,
245 .sh_addr = 0,
246 .sh_offset = 0,
247 .sh_size = 0,
248 .sh_link = 0,
249 .sh_info = 0,
250 .sh_addralign = 0,
251 .sh_entsize = 0,
252 },
253 .phdr_index = undefined,
243254 });
244255
245256 try self.populateMissingMetadata();
......@@ -286,75 +297,67 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
286297}
287298
288299pub fn deinit(self: *Elf) void {
300 const gpa = self.base.allocator;
301
289302 if (build_options.have_llvm) {
290 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
291 }
292
293 self.sections.deinit(self.base.allocator);
294 self.program_headers.deinit(self.base.allocator);
295 self.shstrtab.deinit(self.base.allocator);
296 self.local_symbols.deinit(self.base.allocator);
297 self.global_symbols.deinit(self.base.allocator);
298 self.global_symbol_free_list.deinit(self.base.allocator);
299 self.local_symbol_free_list.deinit(self.base.allocator);
300 self.offset_table_free_list.deinit(self.base.allocator);
301 self.offset_table.deinit(self.base.allocator);
302 self.phdr_shdr_table.deinit(self.base.allocator);
303 self.decls.deinit(self.base.allocator);
304
305 self.atoms.deinit(self.base.allocator);
303 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
304 }
305
306 for (self.sections.items(.free_list)) |*free_list| {
307 free_list.deinit(gpa);
308 }
309 self.sections.deinit(gpa);
310
311 self.program_headers.deinit(gpa);
312 self.shstrtab.deinit(gpa);
313 self.local_symbols.deinit(gpa);
314 self.global_symbols.deinit(gpa);
315 self.global_symbol_free_list.deinit(gpa);
316 self.local_symbol_free_list.deinit(gpa);
317 self.offset_table_free_list.deinit(gpa);
318 self.offset_table.deinit(gpa);
319
306320 {
307 var it = self.atom_free_lists.valueIterator();
308 while (it.next()) |free_list| {
309 free_list.deinit(self.base.allocator);
321 var it = self.decls.iterator();
322 while (it.next()) |entry| {
323 entry.value_ptr.exports.deinit(gpa);
310324 }
311 self.atom_free_lists.deinit(self.base.allocator);
325 self.decls.deinit(gpa);
312326 }
313327
314 for (self.managed_atoms.items) |atom| {
315 self.base.allocator.destroy(atom);
316 }
317 self.managed_atoms.deinit(self.base.allocator);
328 self.atoms.deinit(gpa);
329 self.atom_by_index_table.deinit(gpa);
318330
319331 {
320332 var it = self.unnamed_const_atoms.valueIterator();
321333 while (it.next()) |atoms| {
322 atoms.deinit(self.base.allocator);
334 atoms.deinit(gpa);
323335 }
324 self.unnamed_const_atoms.deinit(self.base.allocator);
336 self.unnamed_const_atoms.deinit(gpa);
325337 }
326338
327339 {
328340 var it = self.relocs.valueIterator();
329341 while (it.next()) |relocs| {
330 relocs.deinit(self.base.allocator);
342 relocs.deinit(gpa);
331343 }
332 self.relocs.deinit(self.base.allocator);
344 self.relocs.deinit(gpa);
333345 }
334346
335 self.atom_by_index_table.deinit(self.base.allocator);
336
337347 if (self.dwarf) |*dw| {
338348 dw.deinit();
339349 }
340350}
341351
342352pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 {
343 const mod = self.base.options.module.?;
344 const decl = mod.declPtr(decl_index);
345
346353 assert(self.llvm_object == null);
347354
348 try decl.link.elf.ensureInitialized(self);
349 const target = decl.link.elf.getSymbolIndex().?;
350
351 const vaddr = self.local_symbols.items[target].st_value;
352 const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?;
353 const gop = try self.relocs.getOrPut(self.base.allocator, atom);
354 if (!gop.found_existing) {
355 gop.value_ptr.* = .{};
356 }
357 try gop.value_ptr.append(self.base.allocator, .{
355 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
356 const this_atom = self.getAtom(this_atom_index);
357 const target = this_atom.getSymbolIndex().?;
358 const vaddr = this_atom.getSymbol(self).st_value;
359 const atom_index = self.getAtomIndexForSymbol(reloc_info.parent_atom_index).?;
360 try Atom.addRelocation(self, atom_index, .{
358361 .target = target,
359362 .offset = reloc_info.offset,
360363 .addend = reloc_info.addend,
......@@ -375,7 +378,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
375378
376379 if (self.shdr_table_offset) |off| {
377380 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);
378 const tight_size = self.sections.items.len * shdr_size;
381 const tight_size = self.sections.slice().len * shdr_size;
379382 const increased_size = padToIdeal(tight_size);
380383 const test_end = off + increased_size;
381384 if (end > off and start < test_end) {
......@@ -385,7 +388,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
385388
386389 if (self.phdr_table_offset) |off| {
387390 const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);
388 const tight_size = self.sections.items.len * phdr_size;
391 const tight_size = self.sections.slice().len * phdr_size;
389392 const increased_size = padToIdeal(tight_size);
390393 const test_end = off + increased_size;
391394 if (end > off and start < test_end) {
......@@ -393,7 +396,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
393396 }
394397 }
395398
396 for (self.sections.items) |section| {
399 for (self.sections.items(.shdr)) |section| {
397400 const increased_size = padToIdeal(section.sh_size);
398401 const test_end = section.sh_offset + increased_size;
399402 if (end > section.sh_offset and start < test_end) {
......@@ -420,7 +423,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
420423 if (self.phdr_table_offset) |off| {
421424 if (off > start and off < min_pos) min_pos = off;
422425 }
423 for (self.sections.items) |section| {
426 for (self.sections.items(.shdr)) |section| {
424427 if (section.sh_offset <= start) continue;
425428 if (section.sh_offset < min_pos) min_pos = section.sh_offset;
426429 }
......@@ -439,31 +442,10 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
439442 return start;
440443}
441444
442/// TODO Improve this to use a table.
443fn makeString(self: *Elf, bytes: []const u8) !u32 {
444 try self.shstrtab.ensureUnusedCapacity(self.base.allocator, bytes.len + 1);
445 const result = self.shstrtab.items.len;
446 self.shstrtab.appendSliceAssumeCapacity(bytes);
447 self.shstrtab.appendAssumeCapacity(0);
448 return @intCast(u32, result);
449}
450
451pub fn getString(self: Elf, str_off: u32) []const u8 {
452 assert(str_off < self.shstrtab.items.len);
453 return mem.sliceTo(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off), 0);
454}
455
456fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {
457 const existing_name = self.getString(old_str_off);
458 if (mem.eql(u8, existing_name, new_name)) {
459 return old_str_off;
460 }
461 return self.makeString(new_name);
462}
463
464445pub fn populateMissingMetadata(self: *Elf) !void {
465446 assert(self.llvm_object == null);
466447
448 const gpa = self.base.allocator;
467449 const small_ptr = switch (self.ptr_width) {
468450 .p32 => true,
469451 .p64 => false,
......@@ -477,7 +459,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
477459 const off = self.findFreeSpace(file_size, p_align);
478460 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
479461 const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;
480 try self.program_headers.append(self.base.allocator, .{
462 try self.program_headers.append(gpa, .{
481463 .p_type = elf.PT_LOAD,
482464 .p_offset = off,
483465 .p_filesz = file_size,
......@@ -487,7 +469,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
487469 .p_align = p_align,
488470 .p_flags = elf.PF_X | elf.PF_R,
489471 });
490 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_re_index.?, .{});
491472 self.entry_addr = null;
492473 self.phdr_table_dirty = true;
493474 }
......@@ -504,7 +485,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
504485 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
505486 // else in virtual memory.
506487 const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
507 try self.program_headers.append(self.base.allocator, .{
488 try self.program_headers.append(gpa, .{
508489 .p_type = elf.PT_LOAD,
509490 .p_offset = off,
510491 .p_filesz = file_size,
......@@ -527,7 +508,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
527508 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
528509 // TODO Same as for GOT
529510 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
530 try self.program_headers.append(self.base.allocator, .{
511 try self.program_headers.append(gpa, .{
531512 .p_type = elf.PT_LOAD,
532513 .p_offset = off,
533514 .p_filesz = file_size,
......@@ -537,7 +518,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
537518 .p_align = p_align,
538519 .p_flags = elf.PF_R,
539520 });
540 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_ro_index.?, .{});
541521 self.phdr_table_dirty = true;
542522 }
543523
......@@ -551,7 +531,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
551531 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
552532 // TODO Same as for GOT
553533 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
554 try self.program_headers.append(self.base.allocator, .{
534 try self.program_headers.append(gpa, .{
555535 .p_type = elf.PT_LOAD,
556536 .p_offset = off,
557537 .p_filesz = file_size,
......@@ -561,148 +541,145 @@ pub fn populateMissingMetadata(self: *Elf) !void {
561541 .p_align = p_align,
562542 .p_flags = elf.PF_R | elf.PF_W,
563543 });
564 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_rw_index.?, .{});
565544 self.phdr_table_dirty = true;
566545 }
567546
568547 if (self.shstrtab_index == null) {
569 self.shstrtab_index = @intCast(u16, self.sections.items.len);
570 assert(self.shstrtab.items.len == 0);
571 try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0
572 const off = self.findFreeSpace(self.shstrtab.items.len, 1);
573 log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.items.len });
574 try self.sections.append(self.base.allocator, .{
575 .sh_name = try self.makeString(".shstrtab"),
576 .sh_type = elf.SHT_STRTAB,
577 .sh_flags = 0,
578 .sh_addr = 0,
579 .sh_offset = off,
580 .sh_size = self.shstrtab.items.len,
581 .sh_link = 0,
582 .sh_info = 0,
583 .sh_addralign = 1,
584 .sh_entsize = 0,
548 self.shstrtab_index = @intCast(u16, self.sections.slice().len);
549 assert(self.shstrtab.buffer.items.len == 0);
550 try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0
551 const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);
552 log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.buffer.items.len });
553 try self.sections.append(gpa, .{
554 .shdr = .{
555 .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"),
556 .sh_type = elf.SHT_STRTAB,
557 .sh_flags = 0,
558 .sh_addr = 0,
559 .sh_offset = off,
560 .sh_size = self.shstrtab.buffer.items.len,
561 .sh_link = 0,
562 .sh_info = 0,
563 .sh_addralign = 1,
564 .sh_entsize = 0,
565 },
566 .phdr_index = undefined,
585567 });
586568 self.shstrtab_dirty = true;
587569 self.shdr_table_dirty = true;
588570 }
589571
590572 if (self.text_section_index == null) {
591 self.text_section_index = @intCast(u16, self.sections.items.len);
573 self.text_section_index = @intCast(u16, self.sections.slice().len);
592574 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
593575
594 try self.sections.append(self.base.allocator, .{
595 .sh_name = try self.makeString(".text"),
596 .sh_type = elf.SHT_PROGBITS,
597 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
598 .sh_addr = phdr.p_vaddr,
599 .sh_offset = phdr.p_offset,
600 .sh_size = phdr.p_filesz,
601 .sh_link = 0,
602 .sh_info = 0,
603 .sh_addralign = 1,
604 .sh_entsize = 0,
576 try self.sections.append(gpa, .{
577 .shdr = .{
578 .sh_name = try self.shstrtab.insert(gpa, ".text"),
579 .sh_type = elf.SHT_PROGBITS,
580 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
581 .sh_addr = phdr.p_vaddr,
582 .sh_offset = phdr.p_offset,
583 .sh_size = phdr.p_filesz,
584 .sh_link = 0,
585 .sh_info = 0,
586 .sh_addralign = 1,
587 .sh_entsize = 0,
588 },
589 .phdr_index = self.phdr_load_re_index.?,
605590 });
606 try self.phdr_shdr_table.putNoClobber(
607 self.base.allocator,
608 self.phdr_load_re_index.?,
609 self.text_section_index.?,
610 );
611591 self.shdr_table_dirty = true;
612592 }
613593
614594 if (self.got_section_index == null) {
615 self.got_section_index = @intCast(u16, self.sections.items.len);
595 self.got_section_index = @intCast(u16, self.sections.slice().len);
616596 const phdr = &self.program_headers.items[self.phdr_got_index.?];
617597
618 try self.sections.append(self.base.allocator, .{
619 .sh_name = try self.makeString(".got"),
620 .sh_type = elf.SHT_PROGBITS,
621 .sh_flags = elf.SHF_ALLOC,
622 .sh_addr = phdr.p_vaddr,
623 .sh_offset = phdr.p_offset,
624 .sh_size = phdr.p_filesz,
625 .sh_link = 0,
626 .sh_info = 0,
627 .sh_addralign = @as(u16, ptr_size),
628 .sh_entsize = 0,
598 try self.sections.append(gpa, .{
599 .shdr = .{
600 .sh_name = try self.shstrtab.insert(gpa, ".got"),
601 .sh_type = elf.SHT_PROGBITS,
602 .sh_flags = elf.SHF_ALLOC,
603 .sh_addr = phdr.p_vaddr,
604 .sh_offset = phdr.p_offset,
605 .sh_size = phdr.p_filesz,
606 .sh_link = 0,
607 .sh_info = 0,
608 .sh_addralign = @as(u16, ptr_size),
609 .sh_entsize = 0,
610 },
611 .phdr_index = self.phdr_got_index.?,
629612 });
630 try self.phdr_shdr_table.putNoClobber(
631 self.base.allocator,
632 self.phdr_got_index.?,
633 self.got_section_index.?,
634 );
635613 self.shdr_table_dirty = true;
636614 }
637615
638616 if (self.rodata_section_index == null) {
639 self.rodata_section_index = @intCast(u16, self.sections.items.len);
617 self.rodata_section_index = @intCast(u16, self.sections.slice().len);
640618 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];
641619
642 try self.sections.append(self.base.allocator, .{
643 .sh_name = try self.makeString(".rodata"),
644 .sh_type = elf.SHT_PROGBITS,
645 .sh_flags = elf.SHF_ALLOC,
646 .sh_addr = phdr.p_vaddr,
647 .sh_offset = phdr.p_offset,
648 .sh_size = phdr.p_filesz,
649 .sh_link = 0,
650 .sh_info = 0,
651 .sh_addralign = 1,
652 .sh_entsize = 0,
620 try self.sections.append(gpa, .{
621 .shdr = .{
622 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
623 .sh_type = elf.SHT_PROGBITS,
624 .sh_flags = elf.SHF_ALLOC,
625 .sh_addr = phdr.p_vaddr,
626 .sh_offset = phdr.p_offset,
627 .sh_size = phdr.p_filesz,
628 .sh_link = 0,
629 .sh_info = 0,
630 .sh_addralign = 1,
631 .sh_entsize = 0,
632 },
633 .phdr_index = self.phdr_load_ro_index.?,
653634 });
654 try self.phdr_shdr_table.putNoClobber(
655 self.base.allocator,
656 self.phdr_load_ro_index.?,
657 self.rodata_section_index.?,
658 );
659635 self.shdr_table_dirty = true;
660636 }
661637
662638 if (self.data_section_index == null) {
663 self.data_section_index = @intCast(u16, self.sections.items.len);
639 self.data_section_index = @intCast(u16, self.sections.slice().len);
664640 const phdr = &self.program_headers.items[self.phdr_load_rw_index.?];
665641
666 try self.sections.append(self.base.allocator, .{
667 .sh_name = try self.makeString(".data"),
668 .sh_type = elf.SHT_PROGBITS,
669 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
670 .sh_addr = phdr.p_vaddr,
671 .sh_offset = phdr.p_offset,
672 .sh_size = phdr.p_filesz,
673 .sh_link = 0,
674 .sh_info = 0,
675 .sh_addralign = @as(u16, ptr_size),
676 .sh_entsize = 0,
642 try self.sections.append(gpa, .{
643 .shdr = .{
644 .sh_name = try self.shstrtab.insert(gpa, ".data"),
645 .sh_type = elf.SHT_PROGBITS,
646 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
647 .sh_addr = phdr.p_vaddr,
648 .sh_offset = phdr.p_offset,
649 .sh_size = phdr.p_filesz,
650 .sh_link = 0,
651 .sh_info = 0,
652 .sh_addralign = @as(u16, ptr_size),
653 .sh_entsize = 0,
654 },
655 .phdr_index = self.phdr_load_rw_index.?,
677656 });
678 try self.phdr_shdr_table.putNoClobber(
679 self.base.allocator,
680 self.phdr_load_rw_index.?,
681 self.data_section_index.?,
682 );
683657 self.shdr_table_dirty = true;
684658 }
685659
686660 if (self.symtab_section_index == null) {
687 self.symtab_section_index = @intCast(u16, self.sections.items.len);
661 self.symtab_section_index = @intCast(u16, self.sections.slice().len);
688662 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
689663 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
690664 const file_size = self.base.options.symbol_count_hint * each_size;
691665 const off = self.findFreeSpace(file_size, min_align);
692666 log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size });
693667
694 try self.sections.append(self.base.allocator, .{
695 .sh_name = try self.makeString(".symtab"),
696 .sh_type = elf.SHT_SYMTAB,
697 .sh_flags = 0,
698 .sh_addr = 0,
699 .sh_offset = off,
700 .sh_size = file_size,
701 // The section header index of the associated string table.
702 .sh_link = self.shstrtab_index.?,
703 .sh_info = @intCast(u32, self.local_symbols.items.len),
704 .sh_addralign = min_align,
705 .sh_entsize = each_size,
668 try self.sections.append(gpa, .{
669 .shdr = .{
670 .sh_name = try self.shstrtab.insert(gpa, ".symtab"),
671 .sh_type = elf.SHT_SYMTAB,
672 .sh_flags = 0,
673 .sh_addr = 0,
674 .sh_offset = off,
675 .sh_size = file_size,
676 // The section header index of the associated string table.
677 .sh_link = self.shstrtab_index.?,
678 .sh_info = @intCast(u32, self.local_symbols.items.len),
679 .sh_addralign = min_align,
680 .sh_entsize = each_size,
681 },
682 .phdr_index = undefined,
706683 });
707684 self.shdr_table_dirty = true;
708685 try self.writeSymbol(0);
......@@ -710,27 +687,30 @@ pub fn populateMissingMetadata(self: *Elf) !void {
710687
711688 if (self.dwarf) |*dw| {
712689 if (self.debug_str_section_index == null) {
713 self.debug_str_section_index = @intCast(u16, self.sections.items.len);
714 assert(dw.strtab.items.len == 0);
715 try dw.strtab.append(self.base.allocator, 0);
716 try self.sections.append(self.base.allocator, .{
717 .sh_name = try self.makeString(".debug_str"),
718 .sh_type = elf.SHT_PROGBITS,
719 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
720 .sh_addr = 0,
721 .sh_offset = 0,
722 .sh_size = 0,
723 .sh_link = 0,
724 .sh_info = 0,
725 .sh_addralign = 1,
726 .sh_entsize = 1,
690 self.debug_str_section_index = @intCast(u16, self.sections.slice().len);
691 assert(dw.strtab.buffer.items.len == 0);
692 try dw.strtab.buffer.append(gpa, 0);
693 try self.sections.append(gpa, .{
694 .shdr = .{
695 .sh_name = try self.shstrtab.insert(gpa, ".debug_str"),
696 .sh_type = elf.SHT_PROGBITS,
697 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
698 .sh_addr = 0,
699 .sh_offset = 0,
700 .sh_size = 0,
701 .sh_link = 0,
702 .sh_info = 0,
703 .sh_addralign = 1,
704 .sh_entsize = 1,
705 },
706 .phdr_index = undefined,
727707 });
728708 self.debug_strtab_dirty = true;
729709 self.shdr_table_dirty = true;
730710 }
731711
732712 if (self.debug_info_section_index == null) {
733 self.debug_info_section_index = @intCast(u16, self.sections.items.len);
713 self.debug_info_section_index = @intCast(u16, self.sections.slice().len);
734714
735715 const file_size_hint = 200;
736716 const p_align = 1;
......@@ -739,24 +719,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {
739719 off,
740720 off + file_size_hint,
741721 });
742 try self.sections.append(self.base.allocator, .{
743 .sh_name = try self.makeString(".debug_info"),
744 .sh_type = elf.SHT_PROGBITS,
745 .sh_flags = 0,
746 .sh_addr = 0,
747 .sh_offset = off,
748 .sh_size = file_size_hint,
749 .sh_link = 0,
750 .sh_info = 0,
751 .sh_addralign = p_align,
752 .sh_entsize = 0,
722 try self.sections.append(gpa, .{
723 .shdr = .{
724 .sh_name = try self.shstrtab.insert(gpa, ".debug_info"),
725 .sh_type = elf.SHT_PROGBITS,
726 .sh_flags = 0,
727 .sh_addr = 0,
728 .sh_offset = off,
729 .sh_size = file_size_hint,
730 .sh_link = 0,
731 .sh_info = 0,
732 .sh_addralign = p_align,
733 .sh_entsize = 0,
734 },
735 .phdr_index = undefined,
753736 });
754737 self.shdr_table_dirty = true;
755738 self.debug_info_header_dirty = true;
756739 }
757740
758741 if (self.debug_abbrev_section_index == null) {
759 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
742 self.debug_abbrev_section_index = @intCast(u16, self.sections.slice().len);
760743
761744 const file_size_hint = 128;
762745 const p_align = 1;
......@@ -765,24 +748,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {
765748 off,
766749 off + file_size_hint,
767750 });
768 try self.sections.append(self.base.allocator, .{
769 .sh_name = try self.makeString(".debug_abbrev"),
770 .sh_type = elf.SHT_PROGBITS,
771 .sh_flags = 0,
772 .sh_addr = 0,
773 .sh_offset = off,
774 .sh_size = file_size_hint,
775 .sh_link = 0,
776 .sh_info = 0,
777 .sh_addralign = p_align,
778 .sh_entsize = 0,
751 try self.sections.append(gpa, .{
752 .shdr = .{
753 .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"),
754 .sh_type = elf.SHT_PROGBITS,
755 .sh_flags = 0,
756 .sh_addr = 0,
757 .sh_offset = off,
758 .sh_size = file_size_hint,
759 .sh_link = 0,
760 .sh_info = 0,
761 .sh_addralign = p_align,
762 .sh_entsize = 0,
763 },
764 .phdr_index = undefined,
779765 });
780766 self.shdr_table_dirty = true;
781767 self.debug_abbrev_section_dirty = true;
782768 }
783769
784770 if (self.debug_aranges_section_index == null) {
785 self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
771 self.debug_aranges_section_index = @intCast(u16, self.sections.slice().len);
786772
787773 const file_size_hint = 160;
788774 const p_align = 16;
......@@ -791,24 +777,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {
791777 off,
792778 off + file_size_hint,
793779 });
794 try self.sections.append(self.base.allocator, .{
795 .sh_name = try self.makeString(".debug_aranges"),
796 .sh_type = elf.SHT_PROGBITS,
797 .sh_flags = 0,
798 .sh_addr = 0,
799 .sh_offset = off,
800 .sh_size = file_size_hint,
801 .sh_link = 0,
802 .sh_info = 0,
803 .sh_addralign = p_align,
804 .sh_entsize = 0,
780 try self.sections.append(gpa, .{
781 .shdr = .{
782 .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"),
783 .sh_type = elf.SHT_PROGBITS,
784 .sh_flags = 0,
785 .sh_addr = 0,
786 .sh_offset = off,
787 .sh_size = file_size_hint,
788 .sh_link = 0,
789 .sh_info = 0,
790 .sh_addralign = p_align,
791 .sh_entsize = 0,
792 },
793 .phdr_index = undefined,
805794 });
806795 self.shdr_table_dirty = true;
807796 self.debug_aranges_section_dirty = true;
808797 }
809798
810799 if (self.debug_line_section_index == null) {
811 self.debug_line_section_index = @intCast(u16, self.sections.items.len);
800 self.debug_line_section_index = @intCast(u16, self.sections.slice().len);
812801
813802 const file_size_hint = 250;
814803 const p_align = 1;
......@@ -817,17 +806,20 @@ pub fn populateMissingMetadata(self: *Elf) !void {
817806 off,
818807 off + file_size_hint,
819808 });
820 try self.sections.append(self.base.allocator, .{
821 .sh_name = try self.makeString(".debug_line"),
822 .sh_type = elf.SHT_PROGBITS,
823 .sh_flags = 0,
824 .sh_addr = 0,
825 .sh_offset = off,
826 .sh_size = file_size_hint,
827 .sh_link = 0,
828 .sh_info = 0,
829 .sh_addralign = p_align,
830 .sh_entsize = 0,
809 try self.sections.append(gpa, .{
810 .shdr = .{
811 .sh_name = try self.shstrtab.insert(gpa, ".debug_line"),
812 .sh_type = elf.SHT_PROGBITS,
813 .sh_flags = 0,
814 .sh_addr = 0,
815 .sh_offset = off,
816 .sh_size = file_size_hint,
817 .sh_link = 0,
818 .sh_info = 0,
819 .sh_addralign = p_align,
820 .sh_entsize = 0,
821 },
822 .phdr_index = undefined,
831823 });
832824 self.shdr_table_dirty = true;
833825 self.debug_line_header_dirty = true;
......@@ -843,7 +835,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
843835 .p64 => @alignOf(elf.Elf64_Shdr),
844836 };
845837 if (self.shdr_table_offset == null) {
846 self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign);
838 self.shdr_table_offset = self.findFreeSpace(self.sections.slice().len * shsize, shalign);
847839 self.shdr_table_dirty = true;
848840 }
849841
......@@ -874,7 +866,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
874866 // offset + it's filesize.
875867 var max_file_offset: u64 = 0;
876868
877 for (self.sections.items) |shdr| {
869 for (self.sections.items(.shdr)) |shdr| {
878870 if (shdr.sh_offset + shdr.sh_size > max_file_offset) {
879871 max_file_offset = shdr.sh_offset + shdr.sh_size;
880872 }
......@@ -884,15 +876,18 @@ pub fn populateMissingMetadata(self: *Elf) !void {
884876 }
885877}
886878
887fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u64) !void {
879fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
888880 // TODO Also detect virtual address collisions.
889 const shdr = &self.sections.items[shdr_index];
881 const shdr = &self.sections.items(.shdr)[shdr_index];
882 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
890883 const phdr = &self.program_headers.items[phdr_index];
884 const maybe_last_atom_index = self.sections.items(.last_atom_index)[shdr_index];
891885
892886 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
893887 // Must move the entire section.
894888 const new_offset = self.findFreeSpace(needed_size, self.page_size);
895 const existing_size = if (self.atoms.get(phdr_index)) |last| blk: {
889 const existing_size = if (maybe_last_atom_index) |last_atom_index| blk: {
890 const last = self.getAtom(last_atom_index);
896891 const sym = last.getSymbol(self);
897892 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
898893 } else if (shdr_index == self.got_section_index.?) blk: {
......@@ -900,8 +895,8 @@ fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u
900895 } else 0;
901896 shdr.sh_size = 0;
902897
903 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
904 self.getString(shdr.sh_name),
898 log.debug("new '{?s}' file offset 0x{x} to 0x{x}", .{
899 self.shstrtab.get(shdr.sh_name),
905900 new_offset,
906901 new_offset + existing_size,
907902 });
......@@ -927,7 +922,7 @@ pub fn growNonAllocSection(
927922 min_alignment: u32,
928923 requires_file_copy: bool,
929924) !void {
930 const shdr = &self.sections.items[shdr_index];
925 const shdr = &self.sections.items(.shdr)[shdr_index];
931926
932927 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
933928 const existing_size = if (self.symtab_section_index.? == shdr_index) blk: {
......@@ -940,7 +935,7 @@ pub fn growNonAllocSection(
940935 shdr.sh_size = 0;
941936 // Move all the symbols to a new file location.
942937 const new_offset = self.findFreeSpace(needed_size, min_alignment);
943 log.debug("moving '{s}' from 0x{x} to 0x{x}", .{ self.getString(shdr.sh_name), shdr.sh_offset, new_offset });
938 log.debug("moving '{?s}' from 0x{x} to 0x{x}", .{ self.shstrtab.get(shdr.sh_name), shdr.sh_offset, new_offset });
944939
945940 if (requires_file_copy) {
946941 const amt = try self.base.file.?.copyRangeAll(
......@@ -1011,6 +1006,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10111006 }
10121007 }
10131008
1009 const gpa = self.base.allocator;
10141010 var sub_prog_node = prog_node.start("ELF Flush", 0);
10151011 sub_prog_node.activate();
10161012 defer sub_prog_node.end();
......@@ -1029,12 +1025,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10291025 {
10301026 var it = self.relocs.iterator();
10311027 while (it.next()) |entry| {
1032 const atom = entry.key_ptr.*;
1028 const atom_index = entry.key_ptr.*;
10331029 const relocs = entry.value_ptr.*;
1030 const atom = self.getAtom(atom_index);
10341031 const source_sym = atom.getSymbol(self);
1035 const source_shdr = self.sections.items[source_sym.st_shndx];
1032 const source_shdr = self.sections.items(.shdr)[source_sym.st_shndx];
10361033
1037 log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)});
1034 log.debug("relocating '{?s}'", .{self.shstrtab.get(source_sym.st_name)});
10381035
10391036 for (relocs.items) |*reloc| {
10401037 const target_sym = self.local_symbols.items[reloc.target];
......@@ -1045,10 +1042,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10451042 const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr;
10461043 const file_offset = source_shdr.sh_offset + section_offset;
10471044
1048 log.debug(" ({x}: [() => 0x{x}] ({s}))", .{
1045 log.debug(" ({x}: [() => 0x{x}] ({?s}))", .{
10491046 reloc.offset,
10501047 target_vaddr,
1051 self.getString(target_sym.st_name),
1048 self.shstrtab.get(target_sym.st_name),
10521049 });
10531050
10541051 switch (self.ptr_width) {
......@@ -1126,8 +1123,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11261123
11271124 switch (self.ptr_width) {
11281125 .p32 => {
1129 const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
1130 defer self.base.allocator.free(buf);
1126 const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
1127 defer gpa.free(buf);
11311128
11321129 for (buf) |*phdr, i| {
11331130 phdr.* = progHeaderTo32(self.program_headers.items[i]);
......@@ -1138,8 +1135,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11381135 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
11391136 },
11401137 .p64 => {
1141 const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
1142 defer self.base.allocator.free(buf);
1138 const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
1139 defer gpa.free(buf);
11431140
11441141 for (buf) |*phdr, i| {
11451142 phdr.* = self.program_headers.items[i];
......@@ -1155,20 +1152,20 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11551152
11561153 {
11571154 const shdr_index = self.shstrtab_index.?;
1158 if (self.shstrtab_dirty or self.shstrtab.items.len != self.sections.items[shdr_index].sh_size) {
1159 try self.growNonAllocSection(shdr_index, self.shstrtab.items.len, 1, false);
1160 const shstrtab_sect = self.sections.items[shdr_index];
1161 try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
1155 if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
1156 try self.growNonAllocSection(shdr_index, self.shstrtab.buffer.items.len, 1, false);
1157 const shstrtab_sect = self.sections.items(.shdr)[shdr_index];
1158 try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shstrtab_sect.sh_offset);
11621159 self.shstrtab_dirty = false;
11631160 }
11641161 }
11651162
11661163 if (self.dwarf) |dwarf| {
11671164 const shdr_index = self.debug_str_section_index.?;
1168 if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items[shdr_index].sh_size) {
1169 try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false);
1170 const debug_strtab_sect = self.sections.items[shdr_index];
1171 try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset);
1165 if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
1166 try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false);
1167 const debug_strtab_sect = self.sections.items(.shdr)[shdr_index];
1168 try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset);
11721169 self.debug_strtab_dirty = false;
11731170 }
11741171 }
......@@ -1183,7 +1180,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11831180 .p64 => @alignOf(elf.Elf64_Shdr),
11841181 };
11851182 const allocated_size = self.allocatedSize(self.shdr_table_offset.?);
1186 const needed_size = self.sections.items.len * shsize;
1183 const needed_size = self.sections.slice().len * shsize;
11871184
11881185 if (needed_size > allocated_size) {
11891186 self.shdr_table_offset = null; // free the space
......@@ -1192,12 +1189,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11921189
11931190 switch (self.ptr_width) {
11941191 .p32 => {
1195 const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);
1196 defer self.base.allocator.free(buf);
1192 const slice = self.sections.slice();
1193 const buf = try gpa.alloc(elf.Elf32_Shdr, slice.len);
1194 defer gpa.free(buf);
11971195
11981196 for (buf) |*shdr, i| {
1199 shdr.* = sectHeaderTo32(self.sections.items[i]);
1200 log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* });
1197 shdr.* = sectHeaderTo32(slice.items(.shdr)[i]);
1198 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
12011199 if (foreign_endian) {
12021200 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
12031201 }
......@@ -1205,12 +1203,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
12051203 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
12061204 },
12071205 .p64 => {
1208 const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);
1209 defer self.base.allocator.free(buf);
1206 const slice = self.sections.slice();
1207 const buf = try gpa.alloc(elf.Elf64_Shdr, slice.len);
1208 defer gpa.free(buf);
12101209
12111210 for (buf) |*shdr, i| {
1212 shdr.* = self.sections.items[i];
1213 log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* });
1211 shdr.* = slice.items(.shdr)[i];
1212 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
12141213 if (foreign_endian) {
12151214 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
12161215 }
......@@ -2021,7 +2020,7 @@ fn writeElfHeader(self: *Elf) !void {
20212020 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
20222021 index += 2;
20232022
2024 const e_shnum = @intCast(u16, self.sections.items.len);
2023 const e_shnum = @intCast(u16, self.sections.slice().len);
20252024 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
20262025 index += 2;
20272026
......@@ -2033,124 +2032,145 @@ fn writeElfHeader(self: *Elf) !void {
20332032 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
20342033}
20352034
2036fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
2037 const local_sym = text_block.getSymbol(self);
2038 const name_str_index = local_sym.st_name;
2039 const name = self.getString(name_str_index);
2040 log.debug("freeTextBlock {*} ({s})", .{ text_block, name });
2035fn freeAtom(self: *Elf, atom_index: Atom.Index) void {
2036 const atom = self.getAtom(atom_index);
2037 log.debug("freeAtom {d} ({s})", .{ atom_index, atom.getName(self) });
20412038
2042 self.freeRelocationsForTextBlock(text_block);
2039 Atom.freeRelocations(self, atom_index);
20432040
2044 const free_list = self.atom_free_lists.getPtr(phdr_index).?;
2041 const gpa = self.base.allocator;
2042 const shndx = atom.getSymbol(self).st_shndx;
2043 const free_list = &self.sections.items(.free_list)[shndx];
20452044 var already_have_free_list_node = false;
20462045 {
20472046 var i: usize = 0;
20482047 // TODO turn free_list into a hash map
20492048 while (i < free_list.items.len) {
2050 if (free_list.items[i] == text_block) {
2049 if (free_list.items[i] == atom_index) {
20512050 _ = free_list.swapRemove(i);
20522051 continue;
20532052 }
2054 if (free_list.items[i] == text_block.prev) {
2053 if (free_list.items[i] == atom.prev_index) {
20552054 already_have_free_list_node = true;
20562055 }
20572056 i += 1;
20582057 }
20592058 }
20602059
2061 if (self.atoms.getPtr(phdr_index)) |last_block| {
2062 if (last_block.* == text_block) {
2063 if (text_block.prev) |prev| {
2060 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[shndx];
2061 if (maybe_last_atom_index.*) |last_atom_index| {
2062 if (last_atom_index == atom_index) {
2063 if (atom.prev_index) |prev_index| {
20642064 // TODO shrink the section size here
2065 last_block.* = prev;
2065 maybe_last_atom_index.* = prev_index;
20662066 } else {
2067 _ = self.atoms.fetchRemove(phdr_index);
2067 maybe_last_atom_index.* = null;
20682068 }
20692069 }
20702070 }
20712071
2072 if (text_block.prev) |prev| {
2073 prev.next = text_block.next;
2072 if (atom.prev_index) |prev_index| {
2073 const prev = self.getAtomPtr(prev_index);
2074 prev.next_index = atom.next_index;
20742075
2075 if (!already_have_free_list_node and prev.freeListEligible(self)) {
2076 if (!already_have_free_list_node and prev.*.freeListEligible(self)) {
20762077 // The free list is heuristics, it doesn't have to be perfect, so we can
20772078 // ignore the OOM here.
2078 free_list.append(self.base.allocator, prev) catch {};
2079 free_list.append(gpa, prev_index) catch {};
20792080 }
20802081 } else {
2081 text_block.prev = null;
2082 self.getAtomPtr(atom_index).prev_index = null;
20822083 }
20832084
2084 if (text_block.next) |next| {
2085 next.prev = text_block.prev;
2085 if (atom.next_index) |next_index| {
2086 self.getAtomPtr(next_index).prev_index = atom.prev_index;
20862087 } else {
2087 text_block.next = null;
2088 self.getAtomPtr(atom_index).next_index = null;
20882089 }
20892090
20902091 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2091 const local_sym_index = text_block.getSymbolIndex().?;
2092 self.local_symbol_free_list.append(self.base.allocator, local_sym_index) catch {};
2092 const local_sym_index = atom.getSymbolIndex().?;
2093
2094 self.local_symbol_free_list.append(gpa, local_sym_index) catch {};
20932095 self.local_symbols.items[local_sym_index].st_info = 0;
2096 self.local_symbols.items[local_sym_index].st_shndx = 0;
20942097 _ = self.atom_by_index_table.remove(local_sym_index);
2095 text_block.local_sym_index = 0;
2098 self.getAtomPtr(atom_index).local_sym_index = 0;
20962099
2097 self.offset_table_free_list.append(self.base.allocator, text_block.offset_table_index) catch {};
2098
2099 if (self.dwarf) |*dw| {
2100 dw.freeAtom(&text_block.dbg_info_atom);
2101 }
2100 self.offset_table_free_list.append(self.base.allocator, atom.offset_table_index) catch {};
21022101}
21032102
2104fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr_index: u16) void {
2103fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void {
21052104 _ = self;
2106 _ = text_block;
2105 _ = atom_index;
21072106 _ = new_block_size;
2108 _ = phdr_index;
21092107}
21102108
2111fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
2112 const sym = text_block.getSymbol(self);
2109fn growAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 {
2110 const atom = self.getAtom(atom_index);
2111 const sym = atom.getSymbol(self);
21132112 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;
2114 const need_realloc = !align_ok or new_block_size > text_block.capacity(self);
2113 const need_realloc = !align_ok or new_block_size > atom.capacity(self);
21152114 if (!need_realloc) return sym.st_value;
2116 return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index);
2115 return self.allocateAtom(atom_index, new_block_size, alignment);
2116}
2117
2118pub fn createAtom(self: *Elf) !Atom.Index {
2119 const gpa = self.base.allocator;
2120 const atom_index = @intCast(Atom.Index, self.atoms.items.len);
2121 const atom = try self.atoms.addOne(gpa);
2122 const local_sym_index = try self.allocateLocalSymbol();
2123 const offset_table_index = try self.allocateGotOffset();
2124 try self.atom_by_index_table.putNoClobber(gpa, local_sym_index, atom_index);
2125 atom.* = .{
2126 .local_sym_index = local_sym_index,
2127 .offset_table_index = offset_table_index,
2128 .prev_index = null,
2129 .next_index = null,
2130 };
2131 log.debug("creating ATOM(%{d}) at index {d}", .{ local_sym_index, atom_index });
2132 return atom_index;
21172133}
21182134
2119fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
2120 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2135fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 {
2136 const atom = self.getAtom(atom_index);
2137 const sym = atom.getSymbol(self);
2138 const phdr_index = self.sections.items(.phdr_index)[sym.st_shndx];
21212139 const phdr = &self.program_headers.items[phdr_index];
2122 const shdr = &self.sections.items[shdr_index];
2123 const new_block_ideal_capacity = padToIdeal(new_block_size);
2140 const shdr = &self.sections.items(.shdr)[sym.st_shndx];
2141 const free_list = &self.sections.items(.free_list)[sym.st_shndx];
2142 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sym.st_shndx];
2143 const new_atom_ideal_capacity = padToIdeal(new_block_size);
21242144
2125 // We use these to indicate our intention to update metadata, placing the new block,
2145 // We use these to indicate our intention to update metadata, placing the new atom,
21262146 // and possibly removing a free list node.
21272147 // It would be simpler to do it inside the for loop below, but that would cause a
21282148 // problem if an error was returned later in the function. So this action
21292149 // is actually carried out at the end of the function, when errors are no longer possible.
2130 var block_placement: ?*TextBlock = null;
2150 var atom_placement: ?Atom.Index = null;
21312151 var free_list_removal: ?usize = null;
2132 var free_list = self.atom_free_lists.get(phdr_index).?;
21332152
21342153 // First we look for an appropriately sized free list node.
21352154 // The list is unordered. We'll just take the first thing that works.
21362155 const vaddr = blk: {
21372156 var i: usize = 0;
21382157 while (i < free_list.items.len) {
2139 const big_block = free_list.items[i];
2140 // We now have a pointer to a live text block that has too much capacity.
2141 // Is it enough that we could fit this new text block?
2142 const sym = big_block.getSymbol(self);
2143 const capacity = big_block.capacity(self);
2158 const big_atom_index = free_list.items[i];
2159 const big_atom = self.getAtom(big_atom_index);
2160 // We now have a pointer to a live atom that has too much capacity.
2161 // Is it enough that we could fit this new atom?
2162 const big_atom_sym = big_atom.getSymbol(self);
2163 const capacity = big_atom.capacity(self);
21442164 const ideal_capacity = padToIdeal(capacity);
2145 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;
2146 const capacity_end_vaddr = sym.st_value + capacity;
2147 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;
2165 const ideal_capacity_end_vaddr = std.math.add(u64, big_atom_sym.st_value, ideal_capacity) catch ideal_capacity;
2166 const capacity_end_vaddr = big_atom_sym.st_value + capacity;
2167 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
21482168 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
21492169 if (new_start_vaddr < ideal_capacity_end_vaddr) {
21502170 // Additional bookkeeping here to notice if this free list node
21512171 // should be deleted because the block that it points to has grown to take up
21522172 // more of the extra capacity.
2153 if (!big_block.freeListEligible(self)) {
2173 if (!big_atom.freeListEligible(self)) {
21542174 _ = free_list.swapRemove(i);
21552175 } else {
21562176 i += 1;
......@@ -2164,29 +2184,33 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
21642184 const keep_free_list_node = remaining_capacity >= min_text_capacity;
21652185
21662186 // Set up the metadata to be updated, after errors are no longer possible.
2167 block_placement = big_block;
2187 atom_placement = big_atom_index;
21682188 if (!keep_free_list_node) {
21692189 free_list_removal = i;
21702190 }
21712191 break :blk new_start_vaddr;
2172 } else if (self.atoms.get(phdr_index)) |last| {
2173 const sym = last.getSymbol(self);
2174 const ideal_capacity = padToIdeal(sym.st_size);
2175 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;
2192 } else if (maybe_last_atom_index.*) |last_index| {
2193 const last = self.getAtom(last_index);
2194 const last_sym = last.getSymbol(self);
2195 const ideal_capacity = padToIdeal(last_sym.st_size);
2196 const ideal_capacity_end_vaddr = last_sym.st_value + ideal_capacity;
21762197 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
21772198 // Set up the metadata to be updated, after errors are no longer possible.
2178 block_placement = last;
2199 atom_placement = last_index;
21792200 break :blk new_start_vaddr;
21802201 } else {
21812202 break :blk phdr.p_vaddr;
21822203 }
21832204 };
21842205
2185 const expand_text_section = block_placement == null or block_placement.?.next == null;
2186 if (expand_text_section) {
2206 const expand_section = if (atom_placement) |placement_index|
2207 self.getAtom(placement_index).next_index == null
2208 else
2209 true;
2210 if (expand_section) {
21872211 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
2188 try self.growAllocSection(shdr_index, phdr_index, needed_size);
2189 _ = try self.atoms.put(self.base.allocator, phdr_index, text_block);
2212 try self.growAllocSection(sym.st_shndx, needed_size);
2213 maybe_last_atom_index.* = atom_index;
21902214
21912215 if (self.dwarf) |_| {
21922216 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
......@@ -2201,23 +2225,28 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
22012225 }
22022226 shdr.sh_addralign = math.max(shdr.sh_addralign, alignment);
22032227
2204 // This function can also reallocate a text block.
2228 // This function can also reallocate an atom.
22052229 // In this case we need to "unplug" it from its previous location before
22062230 // plugging it in to its new location.
2207 if (text_block.prev) |prev| {
2208 prev.next = text_block.next;
2231 if (atom.prev_index) |prev_index| {
2232 const prev = self.getAtomPtr(prev_index);
2233 prev.next_index = atom.next_index;
22092234 }
2210 if (text_block.next) |next| {
2211 next.prev = text_block.prev;
2235 if (atom.next_index) |next_index| {
2236 const next = self.getAtomPtr(next_index);
2237 next.prev_index = atom.prev_index;
22122238 }
22132239
2214 if (block_placement) |big_block| {
2215 text_block.prev = big_block;
2216 text_block.next = big_block.next;
2217 big_block.next = text_block;
2240 if (atom_placement) |big_atom_index| {
2241 const big_atom = self.getAtomPtr(big_atom_index);
2242 const atom_ptr = self.getAtomPtr(atom_index);
2243 atom_ptr.prev_index = big_atom_index;
2244 atom_ptr.next_index = big_atom.next_index;
2245 big_atom.next_index = atom_index;
22182246 } else {
2219 text_block.prev = null;
2220 text_block.next = null;
2247 const atom_ptr = self.getAtomPtr(atom_index);
2248 atom_ptr.prev_index = null;
2249 atom_ptr.next_index = null;
22212250 }
22222251 if (free_list_removal) |i| {
22232252 _ = free_list.swapRemove(i);
......@@ -2272,15 +2301,10 @@ pub fn allocateGotOffset(self: *Elf) !u32 {
22722301 return index;
22732302}
22742303
2275fn freeRelocationsForTextBlock(self: *Elf, text_block: *TextBlock) void {
2276 var removed_relocs = self.relocs.fetchRemove(text_block);
2277 if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator);
2278}
2279
22802304fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
22812305 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
22822306 for (unnamed_consts.items) |atom| {
2283 self.freeTextBlock(atom, self.phdr_load_ro_index.?);
2307 self.freeAtom(atom);
22842308 }
22852309 unnamed_consts.clearAndFree(self.base.allocator);
22862310}
......@@ -2295,43 +2319,57 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
22952319
22962320 log.debug("freeDecl {*}", .{decl});
22972321
2298 if (self.decls.fetchRemove(decl_index)) |kv| {
2299 if (kv.value) |index| {
2300 self.freeTextBlock(&decl.link.elf, index);
2301 self.freeUnnamedConsts(decl_index);
2302 }
2322 if (self.decls.fetchRemove(decl_index)) |const_kv| {
2323 var kv = const_kv;
2324 self.freeAtom(kv.value.atom);
2325 self.freeUnnamedConsts(decl_index);
2326 kv.value.exports.deinit(self.base.allocator);
23032327 }
23042328
23052329 if (self.dwarf) |*dw| {
2306 dw.freeDecl(decl);
2330 dw.freeDecl(decl_index);
2331 }
2332}
2333
2334pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {
2335 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2336 if (!gop.found_existing) {
2337 gop.value_ptr.* = .{
2338 .atom = try self.createAtom(),
2339 .shdr = self.getDeclShdrIndex(decl_index),
2340 .exports = .{},
2341 };
23072342 }
2343 return gop.value_ptr.atom;
23082344}
23092345
2310fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 {
2346fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 {
2347 const decl = self.base.options.module.?.declPtr(decl_index);
23112348 const ty = decl.ty;
23122349 const zig_ty = ty.zigTypeTag();
23132350 const val = decl.val;
2314 const phdr_index: u16 = blk: {
2351 const shdr_index: u16 = blk: {
23152352 if (val.isUndefDeep()) {
23162353 // TODO in release-fast and release-small, we should put undef in .bss
2317 break :blk self.phdr_load_rw_index.?;
2354 break :blk self.data_section_index.?;
23182355 }
23192356
23202357 switch (zig_ty) {
23212358 // TODO: what if this is a function pointer?
2322 .Fn => break :blk self.phdr_load_re_index.?,
2359 .Fn => break :blk self.text_section_index.?,
23232360 else => {
23242361 if (val.castTag(.variable)) |_| {
2325 break :blk self.phdr_load_rw_index.?;
2362 break :blk self.data_section_index.?;
23262363 }
2327 break :blk self.phdr_load_ro_index.?;
2364 break :blk self.rodata_section_index.?;
23282365 },
23292366 }
23302367 };
2331 return phdr_index;
2368 return shdr_index;
23322369}
23332370
23342371fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
2372 const gpa = self.base.allocator;
23352373 const mod = self.base.options.module.?;
23362374 const decl = mod.declPtr(decl_index);
23372375
......@@ -2341,60 +2379,65 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
23412379 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
23422380 const required_alignment = decl.getAlignment(self.base.options.target);
23432381
2344 const decl_ptr = self.decls.getPtr(decl_index).?;
2345 if (decl_ptr.* == null) {
2346 decl_ptr.* = try self.getDeclPhdrIndex(decl);
2347 }
2348 const phdr_index = decl_ptr.*.?;
2349 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2382 const decl_metadata = self.decls.get(decl_index).?;
2383 const atom_index = decl_metadata.atom;
2384 const atom = self.getAtom(atom_index);
2385
2386 const shdr_index = decl_metadata.shdr;
2387 if (atom.getSymbol(self).st_size != 0) {
2388 const local_sym = atom.getSymbolPtr(self);
2389 local_sym.st_name = try self.shstrtab.insert(gpa, decl_name);
2390 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
2391 local_sym.st_other = 0;
2392 local_sym.st_shndx = shdr_index;
23502393
2351 const local_sym = decl.link.elf.getSymbolPtr(self);
2352 if (local_sym.st_size != 0) {
2353 const capacity = decl.link.elf.capacity(self);
2394 const capacity = atom.capacity(self);
23542395 const need_realloc = code.len > capacity or
23552396 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
2397
23562398 if (need_realloc) {
2357 const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index);
2399 const vaddr = try self.growAtom(atom_index, code.len, required_alignment);
23582400 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, local_sym.st_value, vaddr });
23592401 if (vaddr != local_sym.st_value) {
23602402 local_sym.st_value = vaddr;
23612403
23622404 log.debug(" (writing new offset table entry)", .{});
2363 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
2364 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2405 self.offset_table.items[atom.offset_table_index] = vaddr;
2406 try self.writeOffsetTableEntry(atom.offset_table_index);
23652407 }
23662408 } else if (code.len < local_sym.st_size) {
2367 self.shrinkTextBlock(&decl.link.elf, code.len, phdr_index);
2409 self.shrinkAtom(atom_index, code.len);
23682410 }
23692411 local_sym.st_size = code.len;
2370 local_sym.st_name = try self.updateString(local_sym.st_name, decl_name);
2371 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
2372 local_sym.st_other = 0;
2373 local_sym.st_shndx = shdr_index;
2412
23742413 // TODO this write could be avoided if no fields of the symbol were changed.
2375 try self.writeSymbol(decl.link.elf.getSymbolIndex().?);
2414 try self.writeSymbol(atom.getSymbolIndex().?);
23762415 } else {
2377 const name_str_index = try self.makeString(decl_name);
2378 const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index);
2379 errdefer self.freeTextBlock(&decl.link.elf, phdr_index);
2380 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr });
2381
2416 const local_sym = atom.getSymbolPtr(self);
23822417 local_sym.* = .{
2383 .st_name = name_str_index,
2418 .st_name = try self.shstrtab.insert(gpa, decl_name),
23842419 .st_info = (elf.STB_LOCAL << 4) | stt_bits,
23852420 .st_other = 0,
23862421 .st_shndx = shdr_index,
2387 .st_value = vaddr,
2388 .st_size = code.len,
2422 .st_value = 0,
2423 .st_size = 0,
23892424 };
2390 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
2425 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
2426 errdefer self.freeAtom(atom_index);
2427 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr });
23912428
2392 try self.writeSymbol(decl.link.elf.getSymbolIndex().?);
2393 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2429 self.offset_table.items[atom.offset_table_index] = vaddr;
2430 local_sym.st_value = vaddr;
2431 local_sym.st_size = code.len;
2432
2433 try self.writeSymbol(atom.getSymbolIndex().?);
2434 try self.writeOffsetTableEntry(atom.offset_table_index);
23942435 }
23952436
2437 const local_sym = atom.getSymbolPtr(self);
2438 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
23962439 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;
2397 const file_offset = self.sections.items[shdr_index].sh_offset + section_offset;
2440 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
23982441 try self.base.file.?.pwriteAll(code, file_offset);
23992442
24002443 return local_sym;
......@@ -2413,15 +2456,10 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24132456
24142457 const decl_index = func.owner_decl;
24152458 const decl = module.declPtr(decl_index);
2416 const atom = &decl.link.elf;
2417 try atom.ensureInitialized(self);
2418 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2419 if (gop.found_existing) {
2420 self.freeUnnamedConsts(decl_index);
2421 self.freeRelocationsForTextBlock(atom);
2422 } else {
2423 gop.value_ptr.* = null;
2424 }
2459
2460 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2461 self.freeUnnamedConsts(decl_index);
2462 Atom.freeRelocations(self, atom_index);
24252463
24262464 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
24272465 defer code_buffer.deinit();
......@@ -2483,16 +2521,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
24832521 }
24842522 }
24852523
2486 assert(!self.unnamed_const_atoms.contains(decl_index));
2487
2488 const atom = &decl.link.elf;
2489 try atom.ensureInitialized(self);
2490 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2491 if (gop.found_existing) {
2492 self.freeRelocationsForTextBlock(atom);
2493 } else {
2494 gop.value_ptr.* = null;
2495 }
2524 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2525 Atom.freeRelocations(self, atom_index);
2526 const atom = self.getAtom(atom_index);
24962527
24972528 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
24982529 defer code_buffer.deinit();
......@@ -2509,14 +2540,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
25092540 }, &code_buffer, .{
25102541 .dwarf = ds,
25112542 }, .{
2512 .parent_atom_index = decl.link.elf.getSymbolIndex().?,
2543 .parent_atom_index = atom.getSymbolIndex().?,
25132544 })
25142545 else
25152546 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
25162547 .ty = decl.ty,
25172548 .val = decl_val,
25182549 }, &code_buffer, .none, .{
2519 .parent_atom_index = decl.link.elf.getSymbolIndex().?,
2550 .parent_atom_index = atom.getSymbolIndex().?,
25202551 });
25212552
25222553 const code = switch (res) {
......@@ -2545,41 +2576,35 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
25452576}
25462577
25472578pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
2548 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2579 const gpa = self.base.allocator;
2580
2581 var code_buffer = std.ArrayList(u8).init(gpa);
25492582 defer code_buffer.deinit();
25502583
25512584 const mod = self.base.options.module.?;
2552 const decl = mod.declPtr(decl_index);
2553
2554 const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index);
2585 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
25552586 if (!gop.found_existing) {
25562587 gop.value_ptr.* = .{};
25572588 }
25582589 const unnamed_consts = gop.value_ptr;
25592590
2560 const atom = try self.base.allocator.create(TextBlock);
2561 errdefer self.base.allocator.destroy(atom);
2562 atom.* = TextBlock.empty;
2563 // TODO for unnamed consts we don't need GOT offset/entry allocated
2564 try atom.ensureInitialized(self);
2565 try self.managed_atoms.append(self.base.allocator, atom);
2566
2591 const decl = mod.declPtr(decl_index);
25672592 const name_str_index = blk: {
25682593 const decl_name = try decl.getFullyQualifiedName(mod);
2569 defer self.base.allocator.free(decl_name);
2570
2594 defer gpa.free(decl_name);
25712595 const index = unnamed_consts.items.len;
2572 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index });
2573 defer self.base.allocator.free(name);
2574
2575 break :blk try self.makeString(name);
2596 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
2597 defer gpa.free(name);
2598 break :blk try self.shstrtab.insert(gpa, name);
25762599 };
2577 const name = self.getString(name_str_index);
2600 const name = self.shstrtab.get(name_str_index).?;
2601
2602 const atom_index = try self.createAtom();
25782603
25792604 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
25802605 .none = {},
25812606 }, .{
2582 .parent_atom_index = atom.getSymbolIndex().?,
2607 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
25832608 });
25842609 const code = switch (res) {
25852610 .ok => code_buffer.items,
......@@ -2592,31 +2617,27 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
25922617 };
25932618
25942619 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
2595 const phdr_index = self.phdr_load_ro_index.?;
2596 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2597 const vaddr = try self.allocateTextBlock(atom, code.len, required_alignment, phdr_index);
2598 errdefer self.freeTextBlock(atom, phdr_index);
2599
2600 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });
2601
2602 const local_sym = atom.getSymbolPtr(self);
2603 local_sym.* = .{
2604 .st_name = name_str_index,
2605 .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT,
2606 .st_other = 0,
2607 .st_shndx = shdr_index,
2608 .st_value = vaddr,
2609 .st_size = code.len,
2610 };
2611
2612 try self.writeSymbol(atom.getSymbolIndex().?);
2613 try unnamed_consts.append(self.base.allocator, atom);
2620 const shdr_index = self.rodata_section_index.?;
2621 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
2622 const local_sym = self.getAtom(atom_index).getSymbolPtr(self);
2623 local_sym.st_name = name_str_index;
2624 local_sym.st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT;
2625 local_sym.st_other = 0;
2626 local_sym.st_shndx = shdr_index;
2627 local_sym.st_size = code.len;
2628 local_sym.st_value = try self.allocateAtom(atom_index, code.len, required_alignment);
2629 errdefer self.freeAtom(atom_index);
2630
2631 log.debug("allocated text block for {s} at 0x{x}", .{ name, local_sym.st_value });
2632
2633 try self.writeSymbol(self.getAtom(atom_index).getSymbolIndex().?);
2634 try unnamed_consts.append(gpa, atom_index);
26142635
26152636 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;
2616 const file_offset = self.sections.items[shdr_index].sh_offset + section_offset;
2637 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
26172638 try self.base.file.?.pwriteAll(code, file_offset);
26182639
2619 return atom.getSymbolIndex().?;
2640 return self.getAtom(atom_index).getSymbolIndex().?;
26202641}
26212642
26222643pub fn updateDeclExports(
......@@ -2635,20 +2656,16 @@ pub fn updateDeclExports(
26352656 const tracy = trace(@src());
26362657 defer tracy.end();
26372658
2638 const decl = module.declPtr(decl_index);
2639 const atom = &decl.link.elf;
2640
2641 if (atom.getSymbolIndex() == null) return;
2659 const gpa = self.base.allocator;
26422660
2661 const decl = module.declPtr(decl_index);
2662 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2663 const atom = self.getAtom(atom_index);
26432664 const decl_sym = atom.getSymbol(self);
2644 try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len);
2665 const decl_metadata = self.decls.getPtr(decl_index).?;
2666 const shdr_index = decl_metadata.shdr;
26452667
2646 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2647 if (!gop.found_existing) {
2648 gop.value_ptr.* = try self.getDeclPhdrIndex(decl);
2649 }
2650 const phdr_index = gop.value_ptr.*.?;
2651 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2668 try self.global_symbols.ensureUnusedCapacity(gpa, exports.len);
26522669
26532670 for (exports) |exp| {
26542671 if (exp.options.section) |section_name| {
......@@ -2681,10 +2698,10 @@ pub fn updateDeclExports(
26812698 },
26822699 };
26832700 const stt_bits: u8 = @truncate(u4, decl_sym.st_info);
2684 if (exp.link.elf.sym_index) |i| {
2701 if (decl_metadata.getExport(self, exp.options.name)) |i| {
26852702 const sym = &self.global_symbols.items[i];
26862703 sym.* = .{
2687 .st_name = try self.updateString(sym.st_name, exp.options.name),
2704 .st_name = try self.shstrtab.insert(gpa, exp.options.name),
26882705 .st_info = (stb_bits << 4) | stt_bits,
26892706 .st_other = 0,
26902707 .st_shndx = shdr_index,
......@@ -2692,30 +2709,29 @@ pub fn updateDeclExports(
26922709 .st_size = decl_sym.st_size,
26932710 };
26942711 } else {
2695 const name = try self.makeString(exp.options.name);
26962712 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
26972713 _ = self.global_symbols.addOneAssumeCapacity();
26982714 break :blk self.global_symbols.items.len - 1;
26992715 };
2716 try decl_metadata.exports.append(gpa, @intCast(u32, i));
27002717 self.global_symbols.items[i] = .{
2701 .st_name = name,
2718 .st_name = try self.shstrtab.insert(gpa, exp.options.name),
27022719 .st_info = (stb_bits << 4) | stt_bits,
27032720 .st_other = 0,
27042721 .st_shndx = shdr_index,
27052722 .st_value = decl_sym.st_value,
27062723 .st_size = decl_sym.st_size,
27072724 };
2708
2709 exp.link.elf.sym_index = @intCast(u32, i);
27102725 }
27112726 }
27122727}
27132728
27142729/// Must be called only after a successful call to `updateDecl`.
2715pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl) !void {
2730pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.Index) !void {
27162731 const tracy = trace(@src());
27172732 defer tracy.end();
27182733
2734 const decl = mod.declPtr(decl_index);
27192735 const decl_name = try decl.getFullyQualifiedName(mod);
27202736 defer self.base.allocator.free(decl_name);
27212737
......@@ -2723,16 +2739,18 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)
27232739
27242740 if (self.llvm_object) |_| return;
27252741 if (self.dwarf) |*dw| {
2726 try dw.updateDeclLineNumber(decl);
2742 try dw.updateDeclLineNumber(mod, decl_index);
27272743 }
27282744}
27292745
2730pub fn deleteExport(self: *Elf, exp: Export) void {
2746pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void {
27312747 if (self.llvm_object) |_| return;
2732
2733 const sym_index = exp.sym_index orelse return;
2734 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};
2735 self.global_symbols.items[sym_index].st_info = 0;
2748 const metadata = self.decls.getPtr(decl_index) orelse return;
2749 const sym_index = metadata.getExportPtr(self, name) orelse return;
2750 log.debug("deleting export '{s}'", .{name});
2751 self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {};
2752 self.global_symbols.items[sym_index.*].st_info = 0;
2753 sym_index.* = 0;
27362754}
27372755
27382756fn writeProgHeader(self: *Elf, index: usize) !void {
......@@ -2761,7 +2779,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
27612779 switch (self.ptr_width) {
27622780 .p32 => {
27632781 var shdr: [1]elf.Elf32_Shdr = undefined;
2764 shdr[0] = sectHeaderTo32(self.sections.items[index]);
2782 shdr[0] = sectHeaderTo32(self.sections.items(.shdr)[index]);
27652783 if (foreign_endian) {
27662784 mem.byteSwapAllFields(elf.Elf32_Shdr, &shdr[0]);
27672785 }
......@@ -2769,7 +2787,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
27692787 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
27702788 },
27712789 .p64 => {
2772 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};
2790 var shdr = [1]elf.Elf64_Shdr{self.sections.items(.shdr)[index]};
27732791 if (foreign_endian) {
27742792 mem.byteSwapAllFields(elf.Elf64_Shdr, &shdr[0]);
27752793 }
......@@ -2783,11 +2801,11 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
27832801 const entry_size: u16 = self.archPtrWidthBytes();
27842802 if (self.offset_table_count_dirty) {
27852803 const needed_size = self.offset_table.items.len * entry_size;
2786 try self.growAllocSection(self.got_section_index.?, self.phdr_got_index.?, needed_size);
2804 try self.growAllocSection(self.got_section_index.?, needed_size);
27872805 self.offset_table_count_dirty = false;
27882806 }
27892807 const endian = self.base.options.target.cpu.arch.endian();
2790 const shdr = &self.sections.items[self.got_section_index.?];
2808 const shdr = &self.sections.items(.shdr)[self.got_section_index.?];
27912809 const off = shdr.sh_offset + @as(u64, entry_size) * index;
27922810 switch (entry_size) {
27932811 2 => {
......@@ -2813,7 +2831,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
28132831 const tracy = trace(@src());
28142832 defer tracy.end();
28152833
2816 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2834 const syms_sect = &self.sections.items(.shdr)[self.symtab_section_index.?];
28172835 // Make sure we are not pointlessly writing symbol data that will have to get relocated
28182836 // due to running out of space.
28192837 if (self.local_symbols.items.len != syms_sect.sh_info) {
......@@ -2835,7 +2853,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
28352853 .p64 => syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index,
28362854 };
28372855 const local = self.local_symbols.items[index];
2838 log.debug("writing symbol {d}, '{s}' at 0x{x}", .{ index, self.getString(local.st_name), off });
2856 log.debug("writing symbol {d}, '{?s}' at 0x{x}", .{ index, self.shstrtab.get(local.st_name), off });
28392857 log.debug(" ({})", .{local});
28402858 switch (self.ptr_width) {
28412859 .p32 => {
......@@ -2865,7 +2883,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
28652883}
28662884
28672885fn writeAllGlobalSymbols(self: *Elf) !void {
2868 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2886 const syms_sect = &self.sections.items(.shdr)[self.symtab_section_index.?];
28692887 const sym_size: u64 = switch (self.ptr_width) {
28702888 .p32 => @sizeOf(elf.Elf32_Sym),
28712889 .p64 => @sizeOf(elf.Elf64_Sym),
......@@ -3215,10 +3233,58 @@ const CsuObjects = struct {
32153233fn logSymtab(self: Elf) void {
32163234 log.debug("locals:", .{});
32173235 for (self.local_symbols.items) |sym, id| {
3218 log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.st_name), sym.st_value, sym.st_shndx });
3236 log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.shstrtab.get(sym.st_name), sym.st_value, sym.st_shndx });
32193237 }
32203238 log.debug("globals:", .{});
32213239 for (self.global_symbols.items) |sym, id| {
3222 log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.st_name), sym.st_value, sym.st_shndx });
3240 log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.shstrtab.get(sym.st_name), sym.st_value, sym.st_shndx });
32233241 }
32243242}
3243
3244pub fn getProgramHeader(self: *const Elf, shdr_index: u16) elf.Elf64_Phdr {
3245 const index = self.sections.items(.phdr_index)[shdr_index];
3246 return self.program_headers.items[index];
3247}
3248
3249pub fn getProgramHeaderPtr(self: *Elf, shdr_index: u16) *elf.Elf64_Phdr {
3250 const index = self.sections.items(.phdr_index)[shdr_index];
3251 return &self.program_headers.items[index];
3252}
3253
3254/// Returns pointer-to-symbol described at sym_index.
3255pub fn getSymbolPtr(self: *Elf, sym_index: u32) *elf.Elf64_Sym {
3256 return &self.local_symbols.items[sym_index];
3257}
3258
3259/// Returns symbol at sym_index.
3260pub fn getSymbol(self: *const Elf, sym_index: u32) elf.Elf64_Sym {
3261 return self.local_symbols.items[sym_index];
3262}
3263
3264/// Returns name of the symbol at sym_index.
3265pub fn getSymbolName(self: *const Elf, sym_index: u32) []const u8 {
3266 const sym = self.local_symbols.items[sym_index];
3267 return self.shstrtab.get(sym.st_name).?;
3268}
3269
3270/// Returns name of the global symbol at index.
3271pub fn getGlobalName(self: *const Elf, index: u32) []const u8 {
3272 const sym = self.global_symbols.items[index];
3273 return self.shstrtab.get(sym.st_name).?;
3274}
3275
3276pub fn getAtom(self: *const Elf, atom_index: Atom.Index) Atom {
3277 assert(atom_index < self.atoms.items.len);
3278 return self.atoms.items[atom_index];
3279}
3280
3281pub fn getAtomPtr(self: *Elf, atom_index: Atom.Index) *Atom {
3282 assert(atom_index < self.atoms.items.len);
3283 return &self.atoms.items[atom_index];
3284}
3285
3286/// Returns atom if there is an atom referenced by the symbol.
3287/// Returns null on failure.
3288pub fn getAtomIndexForSymbol(self: *Elf, sym_index: u32) ?Atom.Index {
3289 return self.atom_by_index_table.get(sym_index);
3290}
src/link/Elf/Atom.zig+33-29
......@@ -4,7 +4,6 @@ const std = @import("std");
44const assert = std.debug.assert;
55const elf = std.elf;
66
7const Dwarf = @import("../Dwarf.zig");
87const Elf = @import("../Elf.zig");
98
109/// Each decl always gets a local symbol with the fully qualified name.
......@@ -20,44 +19,33 @@ offset_table_index: u32,
2019
2120/// Points to the previous and next neighbors, based on the `text_offset`.
2221/// This can be used to find, for example, the capacity of this `TextBlock`.
23prev: ?*Atom,
24next: ?*Atom,
22prev_index: ?Index,
23next_index: ?Index,
2524
26dbg_info_atom: Dwarf.Atom,
25pub const Index = u32;
2726
28pub const empty = Atom{
29 .local_sym_index = 0,
30 .offset_table_index = undefined,
31 .prev = null,
32 .next = null,
33 .dbg_info_atom = undefined,
27pub const Reloc = struct {
28 target: u32,
29 offset: u64,
30 addend: u32,
31 prev_vaddr: u64,
3432};
3533
36pub fn ensureInitialized(self: *Atom, elf_file: *Elf) !void {
37 if (self.getSymbolIndex() != null) return; // Already initialized
38 self.local_sym_index = try elf_file.allocateLocalSymbol();
39 self.offset_table_index = try elf_file.allocateGotOffset();
40 try elf_file.atom_by_index_table.putNoClobber(elf_file.base.allocator, self.local_sym_index, self);
41}
42
4334pub fn getSymbolIndex(self: Atom) ?u32 {
4435 if (self.local_sym_index == 0) return null;
4536 return self.local_sym_index;
4637}
4738
48pub fn getSymbol(self: Atom, elf_file: *Elf) elf.Elf64_Sym {
49 const sym_index = self.getSymbolIndex().?;
50 return elf_file.local_symbols.items[sym_index];
39pub fn getSymbol(self: Atom, elf_file: *const Elf) elf.Elf64_Sym {
40 return elf_file.getSymbol(self.getSymbolIndex().?);
5141}
5242
5343pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym {
54 const sym_index = self.getSymbolIndex().?;
55 return &elf_file.local_symbols.items[sym_index];
44 return elf_file.getSymbolPtr(self.getSymbolIndex().?);
5645}
5746
58pub fn getName(self: Atom, elf_file: *Elf) []const u8 {
59 const sym = self.getSymbol();
60 return elf_file.getString(sym.st_name);
47pub fn getName(self: Atom, elf_file: *const Elf) []const u8 {
48 return elf_file.getSymbolName(self.getSymbolIndex().?);
6149}
6250
6351pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
......@@ -72,9 +60,10 @@ pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
7260/// Returns how much room there is to grow in virtual address space.
7361/// File offset relocation happens transparently, so it is not included in
7462/// this calculation.
75pub fn capacity(self: Atom, elf_file: *Elf) u64 {
63pub fn capacity(self: Atom, elf_file: *const Elf) u64 {
7664 const self_sym = self.getSymbol(elf_file);
77 if (self.next) |next| {
65 if (self.next_index) |next_index| {
66 const next = elf_file.getAtom(next_index);
7867 const next_sym = next.getSymbol(elf_file);
7968 return next_sym.st_value - self_sym.st_value;
8069 } else {
......@@ -83,9 +72,10 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
8372 }
8473}
8574
86pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
75pub fn freeListEligible(self: Atom, elf_file: *const Elf) bool {
8776 // No need to keep a free list node for the last block.
88 const next = self.next orelse return false;
77 const next_index = self.next_index orelse return false;
78 const next = elf_file.getAtom(next_index);
8979 const self_sym = self.getSymbol(elf_file);
9080 const next_sym = next.getSymbol(elf_file);
9181 const cap = next_sym.st_value - self_sym.st_value;
......@@ -94,3 +84,17 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
9484 const surplus = cap - ideal_cap;
9585 return surplus >= Elf.min_text_capacity;
9686}
87
88pub fn addRelocation(elf_file: *Elf, atom_index: Index, reloc: Reloc) !void {
89 const gpa = elf_file.base.allocator;
90 const gop = try elf_file.relocs.getOrPut(gpa, atom_index);
91 if (!gop.found_existing) {
92 gop.value_ptr.* = .{};
93 }
94 try gop.value_ptr.append(gpa, reloc);
95}
96
97pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {
98 var removed_relocs = elf_file.relocs.fetchRemove(atom_index);
99 if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator);
100}
src/link/MachO.zig+327-297
......@@ -66,7 +66,7 @@ const Section = struct {
6666
6767 // TODO is null here necessary, or can we do away with tracking via section
6868 // size in incremental context?
69 last_atom: ?*Atom = null,
69 last_atom_index: ?Atom.Index = null,
7070
7171 /// A list of atoms that have surplus capacity. This list can have false
7272 /// positives, as functions grow and shrink over time, only sometimes being added
......@@ -83,7 +83,7 @@ const Section = struct {
8383 /// overcapacity can be negative. A simple way to have negative overcapacity is to
8484 /// allocate a fresh atom, which will have ideal capacity, and then grow it
8585 /// by 1 byte. It will then have -1 overcapacity.
86 free_list: std.ArrayListUnmanaged(*Atom) = .{},
86 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
8787};
8888
8989base: File,
......@@ -140,8 +140,8 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{},
140140globals_free_list: std.ArrayListUnmanaged(u32) = .{},
141141
142142dyld_stub_binder_index: ?u32 = null,
143dyld_private_atom: ?*Atom = null,
144stub_helper_preamble_atom: ?*Atom = null,
143dyld_private_atom_index: ?Atom.Index = null,
144stub_helper_preamble_atom_index: ?Atom.Index = null,
145145
146146strtab: StringTable(.strtab) = .{},
147147
......@@ -164,10 +164,10 @@ segment_table_dirty: bool = false,
164164cold_start: bool = true,
165165
166166/// List of atoms that are either synthetic or map directly to the Zig source program.
167managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
167atoms: std.ArrayListUnmanaged(Atom) = .{},
168168
169169/// Table of atoms indexed by the symbol index.
170atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
170atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
171171
172172/// Table of unnamed constants associated with a parent `Decl`.
173173/// We store them here so that we can free the constants whenever the `Decl`
......@@ -210,11 +210,36 @@ bindings: BindingTable = .{},
210210/// this will be a table indexed by index into the list of Atoms.
211211lazy_bindings: BindingTable = .{},
212212
213/// Table of Decls that are currently alive.
214/// We store them here so that we can properly dispose of any allocated
215/// memory within the atom in the incremental linker.
216/// TODO consolidate this.
217decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?u8) = .{},
213/// Table of tracked Decls.
214decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
215
216const DeclMetadata = struct {
217 atom: Atom.Index,
218 section: u8,
219 /// A list of all exports aliases of this Decl.
220 /// TODO do we actually need this at all?
221 exports: std.ArrayListUnmanaged(u32) = .{},
222
223 fn getExport(m: DeclMetadata, macho_file: *const MachO, name: []const u8) ?u32 {
224 for (m.exports.items) |exp| {
225 if (mem.eql(u8, name, macho_file.getSymbolName(.{
226 .sym_index = exp,
227 .file = null,
228 }))) return exp;
229 }
230 return null;
231 }
232
233 fn getExportPtr(m: *DeclMetadata, macho_file: *MachO, name: []const u8) ?*u32 {
234 for (m.exports.items) |*exp| {
235 if (mem.eql(u8, name, macho_file.getSymbolName(.{
236 .sym_index = exp.*,
237 .file = null,
238 }))) return exp;
239 }
240 return null;
241 }
242};
218243
219244const Entry = struct {
220245 target: SymbolWithLoc,
......@@ -229,8 +254,8 @@ const Entry = struct {
229254 return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null });
230255 }
231256
232 pub fn getAtom(entry: Entry, macho_file: *MachO) ?*Atom {
233 return macho_file.getAtomForSymbol(.{ .sym_index = entry.sym_index, .file = null });
257 pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index {
258 return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index, .file = null });
234259 }
235260
236261 pub fn getName(entry: Entry, macho_file: *MachO) []const u8 {
......@@ -238,10 +263,10 @@ const Entry = struct {
238263 }
239264};
240265
241const BindingTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Atom.Binding));
242const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));
243const RebaseTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32));
244const RelocationTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation));
266const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
267const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
268const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
269const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
245270
246271const PendingUpdate = union(enum) {
247272 resolve_undef: u32,
......@@ -286,10 +311,6 @@ pub const default_pagezero_vmsize: u64 = 0x100000000;
286311/// potential future extensions.
287312pub const default_headerpad_size: u32 = 0x1000;
288313
289pub const Export = struct {
290 sym_index: ?u32 = null,
291};
292
293314pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
294315 assert(options.target.ofmt == .macho);
295316
......@@ -547,8 +568,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
547568
548569 try self.allocateSpecialSymbols();
549570
550 for (self.relocs.keys()) |atom| {
551 try atom.resolveRelocations(self);
571 for (self.relocs.keys()) |atom_index| {
572 try Atom.resolveRelocations(self, atom_index);
552573 }
553574
554575 if (build_options.enable_logging) {
......@@ -999,18 +1020,19 @@ pub fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs:
9991020 }
10001021}
10011022
1002pub fn writeAtom(self: *MachO, atom: *Atom, code: []const u8) !void {
1023pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []const u8) !void {
1024 const atom = self.getAtom(atom_index);
10031025 const sym = atom.getSymbol(self);
10041026 const section = self.sections.get(sym.n_sect - 1);
10051027 const file_offset = section.header.offset + sym.n_value - section.header.addr;
10061028 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
10071029 try self.base.file.?.pwriteAll(code, file_offset);
1008 try atom.resolveRelocations(self);
1030 try Atom.resolveRelocations(self, atom_index);
10091031}
10101032
1011fn writePtrWidthAtom(self: *MachO, atom: *Atom) !void {
1033fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {
10121034 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
1013 try self.writeAtom(atom, &buffer);
1035 try self.writeAtom(atom_index, &buffer);
10141036}
10151037
10161038fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
......@@ -1026,7 +1048,8 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
10261048fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
10271049 for (self.relocs.values()) |*relocs| {
10281050 for (relocs.items) |*reloc| {
1029 const target_atom = reloc.getTargetAtom(self) orelse continue;
1051 const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue;
1052 const target_atom = self.getAtom(target_atom_index);
10301053 const target_sym = target_atom.getSymbol(self);
10311054 if (target_sym.n_value < addr) continue;
10321055 reloc.dirty = true;
......@@ -1053,26 +1076,38 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {
10531076 }
10541077}
10551078
1056pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
1079pub fn createAtom(self: *MachO) !Atom.Index {
10571080 const gpa = self.base.allocator;
1081 const atom_index = @intCast(Atom.Index, self.atoms.items.len);
1082 const atom = try self.atoms.addOne(gpa);
1083 const sym_index = try self.allocateSymbol();
1084 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
1085 atom.* = .{
1086 .sym_index = sym_index,
1087 .file = null,
1088 .size = 0,
1089 .alignment = 0,
1090 .prev_index = null,
1091 .next_index = null,
1092 };
1093 log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index });
1094 return atom_index;
1095}
10581096
1059 const atom = try gpa.create(Atom);
1060 atom.* = Atom.empty;
1061 try atom.ensureInitialized(self);
1097pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1098 const atom_index = try self.createAtom();
1099 const atom = self.getAtomPtr(atom_index);
10621100 atom.size = @sizeOf(u64);
10631101 atom.alignment = @alignOf(u64);
1064 errdefer gpa.destroy(atom);
1065
1066 try self.managed_atoms.append(gpa, atom);
10671102
10681103 const sym = atom.getSymbolPtr(self);
10691104 sym.n_type = macho.N_SECT;
10701105 sym.n_sect = self.got_section_index.? + 1;
1071 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));
1106 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));
10721107
10731108 log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});
10741109
1075 try atom.addRelocation(self, .{
1110 try Atom.addRelocation(self, atom_index, .{
10761111 .type = switch (self.base.options.target.cpu.arch) {
10771112 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
10781113 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
......@@ -1087,45 +1122,39 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
10871122
10881123 const target_sym = self.getSymbol(target);
10891124 if (target_sym.undf()) {
1090 try atom.addBinding(self, .{
1125 try Atom.addBinding(self, atom_index, .{
10911126 .target = self.getGlobal(self.getSymbolName(target)).?,
10921127 .offset = 0,
10931128 });
10941129 } else {
1095 try atom.addRebase(self, 0);
1130 try Atom.addRebase(self, atom_index, 0);
10961131 }
10971132
1098 return atom;
1133 return atom_index;
10991134}
11001135
11011136pub fn createDyldPrivateAtom(self: *MachO) !void {
11021137 if (self.dyld_stub_binder_index == null) return;
1103 if (self.dyld_private_atom != null) return;
1104
1105 const gpa = self.base.allocator;
1138 if (self.dyld_private_atom_index != null) return;
11061139
1107 const atom = try gpa.create(Atom);
1108 atom.* = Atom.empty;
1109 try atom.ensureInitialized(self);
1140 const atom_index = try self.createAtom();
1141 const atom = self.getAtomPtr(atom_index);
11101142 atom.size = @sizeOf(u64);
11111143 atom.alignment = @alignOf(u64);
1112 errdefer gpa.destroy(atom);
11131144
11141145 const sym = atom.getSymbolPtr(self);
11151146 sym.n_type = macho.N_SECT;
11161147 sym.n_sect = self.data_section_index.? + 1;
1117 self.dyld_private_atom = atom;
1148 self.dyld_private_atom_index = atom_index;
11181149
1119 try self.managed_atoms.append(gpa, atom);
1120
1121 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));
1150 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));
11221151 log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value});
1123 try self.writePtrWidthAtom(atom);
1152 try self.writePtrWidthAtom(atom_index);
11241153}
11251154
11261155pub fn createStubHelperPreambleAtom(self: *MachO) !void {
11271156 if (self.dyld_stub_binder_index == null) return;
1128 if (self.stub_helper_preamble_atom != null) return;
1157 if (self.stub_helper_preamble_atom_index != null) return;
11291158
11301159 const gpa = self.base.allocator;
11311160 const arch = self.base.options.target.cpu.arch;
......@@ -1134,22 +1163,23 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
11341163 .aarch64 => 6 * @sizeOf(u32),
11351164 else => unreachable,
11361165 };
1137 const atom = try gpa.create(Atom);
1138 atom.* = Atom.empty;
1139 try atom.ensureInitialized(self);
1166 const atom_index = try self.createAtom();
1167 const atom = self.getAtomPtr(atom_index);
11401168 atom.size = size;
11411169 atom.alignment = switch (arch) {
11421170 .x86_64 => 1,
11431171 .aarch64 => @alignOf(u32),
11441172 else => unreachable,
11451173 };
1146 errdefer gpa.destroy(atom);
11471174
11481175 const sym = atom.getSymbolPtr(self);
11491176 sym.n_type = macho.N_SECT;
11501177 sym.n_sect = self.stub_helper_section_index.? + 1;
11511178
1152 const dyld_private_sym_index = self.dyld_private_atom.?.getSymbolIndex().?;
1179 const dyld_private_sym_index = if (self.dyld_private_atom_index) |dyld_index|
1180 self.getAtom(dyld_index).getSymbolIndex().?
1181 else
1182 unreachable;
11531183
11541184 const code = try gpa.alloc(u8, size);
11551185 defer gpa.free(code);
......@@ -1168,7 +1198,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
11681198 code[9] = 0xff;
11691199 code[10] = 0x25;
11701200
1171 try atom.addRelocations(self, 2, .{ .{
1201 try Atom.addRelocations(self, atom_index, 2, .{ .{
11721202 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
11731203 .target = .{ .sym_index = dyld_private_sym_index, .file = null },
11741204 .offset = 3,
......@@ -1208,7 +1238,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
12081238 // br x16
12091239 mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32());
12101240
1211 try atom.addRelocations(self, 4, .{ .{
1241 try Atom.addRelocations(self, atom_index, 4, .{ .{
12121242 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
12131243 .target = .{ .sym_index = dyld_private_sym_index, .file = null },
12141244 .offset = 0,
......@@ -1241,16 +1271,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
12411271
12421272 else => unreachable,
12431273 }
1244 self.stub_helper_preamble_atom = atom;
1274 self.stub_helper_preamble_atom_index = atom_index;
12451275
1246 try self.managed_atoms.append(gpa, atom);
1247
1248 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1276 sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment);
12491277 log.debug("allocated stub preamble atom at 0x{x}", .{sym.n_value});
1250 try self.writeAtom(atom, code);
1278 try self.writeAtom(atom_index, code);
12511279}
12521280
1253pub fn createStubHelperAtom(self: *MachO) !*Atom {
1281pub fn createStubHelperAtom(self: *MachO) !Atom.Index {
12541282 const gpa = self.base.allocator;
12551283 const arch = self.base.options.target.cpu.arch;
12561284 const size: u4 = switch (arch) {
......@@ -1258,16 +1286,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
12581286 .aarch64 => 3 * @sizeOf(u32),
12591287 else => unreachable,
12601288 };
1261 const atom = try gpa.create(Atom);
1262 atom.* = Atom.empty;
1263 try atom.ensureInitialized(self);
1289 const atom_index = try self.createAtom();
1290 const atom = self.getAtomPtr(atom_index);
12641291 atom.size = size;
12651292 atom.alignment = switch (arch) {
12661293 .x86_64 => 1,
12671294 .aarch64 => @alignOf(u32),
12681295 else => unreachable,
12691296 };
1270 errdefer gpa.destroy(atom);
12711297
12721298 const sym = atom.getSymbolPtr(self);
12731299 sym.n_type = macho.N_SECT;
......@@ -1277,6 +1303,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
12771303 defer gpa.free(code);
12781304 mem.set(u8, code, 0);
12791305
1306 const stub_helper_preamble_atom_sym_index = if (self.stub_helper_preamble_atom_index) |stub_index|
1307 self.getAtom(stub_index).getSymbolIndex().?
1308 else
1309 unreachable;
1310
12801311 switch (arch) {
12811312 .x86_64 => {
12821313 // pushq
......@@ -1285,9 +1316,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
12851316 // jmpq
12861317 code[5] = 0xe9;
12871318
1288 try atom.addRelocation(self, .{
1319 try Atom.addRelocation(self, atom_index, .{
12891320 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
1290 .target = .{ .sym_index = self.stub_helper_preamble_atom.?.getSymbolIndex().?, .file = null },
1321 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },
12911322 .offset = 6,
12921323 .addend = 0,
12931324 .pcrel = true,
......@@ -1308,9 +1339,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
13081339 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(0).toU32());
13091340 // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.
13101341
1311 try atom.addRelocation(self, .{
1342 try Atom.addRelocation(self, atom_index, .{
13121343 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),
1313 .target = .{ .sym_index = self.stub_helper_preamble_atom.?.getSymbolIndex().?, .file = null },
1344 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },
13141345 .offset = 4,
13151346 .addend = 0,
13161347 .pcrel = true,
......@@ -1320,29 +1351,24 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
13201351 else => unreachable,
13211352 }
13221353
1323 try self.managed_atoms.append(gpa, atom);
1324
1325 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1354 sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment);
13261355 log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value});
1327 try self.writeAtom(atom, code);
1356 try self.writeAtom(atom_index, code);
13281357
1329 return atom;
1358 return atom_index;
13301359}
13311360
1332pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom {
1333 const gpa = self.base.allocator;
1334 const atom = try gpa.create(Atom);
1335 atom.* = Atom.empty;
1336 try atom.ensureInitialized(self);
1361pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !Atom.Index {
1362 const atom_index = try self.createAtom();
1363 const atom = self.getAtomPtr(atom_index);
13371364 atom.size = @sizeOf(u64);
13381365 atom.alignment = @alignOf(u64);
1339 errdefer gpa.destroy(atom);
13401366
13411367 const sym = atom.getSymbolPtr(self);
13421368 sym.n_type = macho.N_SECT;
13431369 sym.n_sect = self.la_symbol_ptr_section_index.? + 1;
13441370
1345 try atom.addRelocation(self, .{
1371 try Atom.addRelocation(self, atom_index, .{
13461372 .type = switch (self.base.options.target.cpu.arch) {
13471373 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
13481374 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
......@@ -1354,22 +1380,20 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi
13541380 .pcrel = false,
13551381 .length = 3,
13561382 });
1357 try atom.addRebase(self, 0);
1358 try atom.addLazyBinding(self, .{
1383 try Atom.addRebase(self, atom_index, 0);
1384 try Atom.addLazyBinding(self, atom_index, .{
13591385 .target = self.getGlobal(self.getSymbolName(target)).?,
13601386 .offset = 0,
13611387 });
13621388
1363 try self.managed_atoms.append(gpa, atom);
1364
1365 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));
1389 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));
13661390 log.debug("allocated lazy pointer atom at 0x{x} ({s})", .{ sym.n_value, self.getSymbolName(target) });
1367 try self.writePtrWidthAtom(atom);
1391 try self.writePtrWidthAtom(atom_index);
13681392
1369 return atom;
1393 return atom_index;
13701394}
13711395
1372pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
1396pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
13731397 const gpa = self.base.allocator;
13741398 const arch = self.base.options.target.cpu.arch;
13751399 const size: u4 = switch (arch) {
......@@ -1377,9 +1401,8 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
13771401 .aarch64 => 3 * @sizeOf(u32),
13781402 else => unreachable, // unhandled architecture type
13791403 };
1380 const atom = try gpa.create(Atom);
1381 atom.* = Atom.empty;
1382 try atom.ensureInitialized(self);
1404 const atom_index = try self.createAtom();
1405 const atom = self.getAtomPtr(atom_index);
13831406 atom.size = size;
13841407 atom.alignment = switch (arch) {
13851408 .x86_64 => 1,
......@@ -1387,7 +1410,6 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
13871410 else => unreachable, // unhandled architecture type
13881411
13891412 };
1390 errdefer gpa.destroy(atom);
13911413
13921414 const sym = atom.getSymbolPtr(self);
13931415 sym.n_type = macho.N_SECT;
......@@ -1403,7 +1425,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
14031425 code[0] = 0xff;
14041426 code[1] = 0x25;
14051427
1406 try atom.addRelocation(self, .{
1428 try Atom.addRelocation(self, atom_index, .{
14071429 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
14081430 .target = .{ .sym_index = laptr_sym_index, .file = null },
14091431 .offset = 2,
......@@ -1424,7 +1446,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
14241446 // br x16
14251447 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());
14261448
1427 try atom.addRelocations(self, 2, .{
1449 try Atom.addRelocations(self, atom_index, 2, .{
14281450 .{
14291451 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
14301452 .target = .{ .sym_index = laptr_sym_index, .file = null },
......@@ -1446,13 +1468,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
14461468 else => unreachable,
14471469 }
14481470
1449 try self.managed_atoms.append(gpa, atom);
1450
1451 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1471 sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment);
14521472 log.debug("allocated stub atom at 0x{x}", .{sym.n_value});
1453 try self.writeAtom(atom, code);
1473 try self.writeAtom(atom_index, code);
14541474
1455 return atom;
1475 return atom_index;
14561476}
14571477
14581478pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {
......@@ -1586,9 +1606,12 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {
15861606 if (self.stubs_table.contains(global)) break :blk;
15871607
15881608 const stub_index = try self.allocateStubEntry(global);
1589 const stub_helper_atom = try self.createStubHelperAtom();
1590 const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, global);
1591 const stub_atom = try self.createStubAtom(laptr_atom.getSymbolIndex().?);
1609 const stub_helper_atom_index = try self.createStubHelperAtom();
1610 const stub_helper_atom = self.getAtom(stub_helper_atom_index);
1611 const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, global);
1612 const laptr_atom = self.getAtom(laptr_atom_index);
1613 const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?);
1614 const stub_atom = self.getAtom(stub_atom_index);
15921615 self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
15931616 self.markRelocsDirtyByTarget(global);
15941617 }
......@@ -1686,10 +1709,11 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {
16861709
16871710 // Add dyld_stub_binder as the final GOT entry.
16881711 const got_index = try self.allocateGotEntry(global);
1689 const got_atom = try self.createGotAtom(global);
1712 const got_atom_index = try self.createGotAtom(global);
1713 const got_atom = self.getAtom(got_atom_index);
16901714 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
16911715
1692 try self.writePtrWidthAtom(got_atom);
1716 try self.writePtrWidthAtom(got_atom_index);
16931717}
16941718
16951719pub fn deinit(self: *MachO) void {
......@@ -1739,12 +1763,12 @@ pub fn deinit(self: *MachO) void {
17391763 }
17401764 self.sections.deinit(gpa);
17411765
1742 for (self.managed_atoms.items) |atom| {
1743 gpa.destroy(atom);
1744 }
1745 self.managed_atoms.deinit(gpa);
1766 self.atoms.deinit(gpa);
17461767
17471768 if (self.base.options.module) |_| {
1769 for (self.decls.values()) |*m| {
1770 m.exports.deinit(gpa);
1771 }
17481772 self.decls.deinit(gpa);
17491773 } else {
17501774 assert(self.decls.count() == 0);
......@@ -1778,14 +1802,14 @@ pub fn deinit(self: *MachO) void {
17781802 self.lazy_bindings.deinit(gpa);
17791803}
17801804
1781fn freeAtom(self: *MachO, atom: *Atom) void {
1782 log.debug("freeAtom {*}", .{atom});
1783
1805fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
17841806 const gpa = self.base.allocator;
1807 log.debug("freeAtom {d}", .{atom_index});
17851808
17861809 // Remove any relocs and base relocs associated with this Atom
1787 self.freeRelocationsForAtom(atom);
1810 Atom.freeRelocations(self, atom_index);
17881811
1812 const atom = self.getAtom(atom_index);
17891813 const sect_id = atom.getSymbol(self).n_sect - 1;
17901814 const free_list = &self.sections.items(.free_list)[sect_id];
17911815 var already_have_free_list_node = false;
......@@ -1793,45 +1817,46 @@ fn freeAtom(self: *MachO, atom: *Atom) void {
17931817 var i: usize = 0;
17941818 // TODO turn free_list into a hash map
17951819 while (i < free_list.items.len) {
1796 if (free_list.items[i] == atom) {
1820 if (free_list.items[i] == atom_index) {
17971821 _ = free_list.swapRemove(i);
17981822 continue;
17991823 }
1800 if (free_list.items[i] == atom.prev) {
1824 if (free_list.items[i] == atom.prev_index) {
18011825 already_have_free_list_node = true;
18021826 }
18031827 i += 1;
18041828 }
18051829 }
18061830
1807 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];
1808 if (maybe_last_atom.*) |last_atom| {
1809 if (last_atom == atom) {
1810 if (atom.prev) |prev| {
1831 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
1832 if (maybe_last_atom_index.*) |last_atom_index| {
1833 if (last_atom_index == atom_index) {
1834 if (atom.prev_index) |prev_index| {
18111835 // TODO shrink the section size here
1812 maybe_last_atom.* = prev;
1836 maybe_last_atom_index.* = prev_index;
18131837 } else {
1814 maybe_last_atom.* = null;
1838 maybe_last_atom_index.* = null;
18151839 }
18161840 }
18171841 }
18181842
1819 if (atom.prev) |prev| {
1820 prev.next = atom.next;
1843 if (atom.prev_index) |prev_index| {
1844 const prev = self.getAtomPtr(prev_index);
1845 prev.next_index = atom.next_index;
18211846
1822 if (!already_have_free_list_node and prev.freeListEligible(self)) {
1847 if (!already_have_free_list_node and prev.*.freeListEligible(self)) {
18231848 // The free list is heuristics, it doesn't have to be perfect, so we can ignore
18241849 // the OOM here.
1825 free_list.append(gpa, prev) catch {};
1850 free_list.append(gpa, prev_index) catch {};
18261851 }
18271852 } else {
1828 atom.prev = null;
1853 self.getAtomPtr(atom_index).prev_index = null;
18291854 }
18301855
1831 if (atom.next) |next| {
1832 next.prev = atom.prev;
1856 if (atom.next_index) |next_index| {
1857 self.getAtomPtr(next_index).prev_index = atom.prev_index;
18331858 } else {
1834 atom.next = null;
1859 self.getAtomPtr(atom_index).next_index = null;
18351860 }
18361861
18371862 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
......@@ -1859,27 +1884,24 @@ fn freeAtom(self: *MachO, atom: *Atom) void {
18591884 self.locals.items[sym_index].n_type = 0;
18601885 _ = self.atom_by_index_table.remove(sym_index);
18611886 log.debug(" adding local symbol index {d} to free list", .{sym_index});
1862 atom.sym_index = 0;
1863
1864 if (self.d_sym) |*d_sym| {
1865 d_sym.dwarf.freeAtom(&atom.dbg_info_atom);
1866 }
1887 self.getAtomPtr(atom_index).sym_index = 0;
18671888}
18681889
1869fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64) void {
1890fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {
18701891 _ = self;
1871 _ = atom;
1892 _ = atom_index;
18721893 _ = new_block_size;
18731894 // TODO check the new capacity, and if it crosses the size threshold into a big enough
18741895 // capacity, insert a free list node for it.
18751896}
18761897
1877fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64 {
1898fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 {
1899 const atom = self.getAtom(atom_index);
18781900 const sym = atom.getSymbol(self);
18791901 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;
18801902 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
18811903 if (!need_realloc) return sym.n_value;
1882 return self.allocateAtom(atom, new_atom_size, alignment);
1904 return self.allocateAtom(atom_index, new_atom_size, alignment);
18831905}
18841906
18851907pub fn allocateSymbol(self: *MachO) !u32 {
......@@ -1986,15 +2008,12 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
19862008
19872009 const decl_index = func.owner_decl;
19882010 const decl = module.declPtr(decl_index);
1989 const atom = &decl.link.macho;
1990 try atom.ensureInitialized(self);
1991 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1992 if (gop.found_existing) {
1993 self.freeUnnamedConsts(decl_index);
1994 self.freeRelocationsForAtom(atom);
1995 } else {
1996 gop.value_ptr.* = null;
1997 }
2011
2012 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2013 self.freeUnnamedConsts(decl_index);
2014 Atom.freeRelocations(self, atom_index);
2015
2016 const atom = self.getAtom(atom_index);
19982017
19992018 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
20002019 defer code_buffer.deinit();
......@@ -2024,13 +2043,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
20242043 const addr = try self.updateDeclCode(decl_index, code);
20252044
20262045 if (decl_state) |*ds| {
2027 try self.d_sym.?.dwarf.commitDeclState(
2028 module,
2029 decl_index,
2030 addr,
2031 decl.link.macho.size,
2032 ds,
2033 );
2046 try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds);
20342047 }
20352048
20362049 // Since we updated the vaddr and the size, each corresponding export symbol also
......@@ -2065,14 +2078,10 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
20652078
20662079 log.debug("allocating symbol indexes for {?s}", .{name});
20672080
2068 const atom = try gpa.create(Atom);
2069 errdefer gpa.destroy(atom);
2070 atom.* = Atom.empty;
2071 try atom.ensureInitialized(self);
2072 try self.managed_atoms.append(gpa, atom);
2081 const atom_index = try self.createAtom();
20732082
20742083 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{
2075 .parent_atom_index = atom.getSymbolIndex().?,
2084 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
20762085 });
20772086 const code = switch (res) {
20782087 .ok => code_buffer.items,
......@@ -2085,24 +2094,25 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
20852094 };
20862095
20872096 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
2097 const atom = self.getAtomPtr(atom_index);
20882098 atom.size = code.len;
20892099 atom.alignment = required_alignment;
20902100 // TODO: work out logic for disambiguating functions from function pointers
2091 // const sect_id = self.getDeclOutputSection(decl);
2101 // const sect_id = self.getDeclOutputSection(decl_index);
20922102 const sect_id = self.data_const_section_index.?;
20932103 const symbol = atom.getSymbolPtr(self);
20942104 symbol.n_strx = name_str_index;
20952105 symbol.n_type = macho.N_SECT;
20962106 symbol.n_sect = sect_id + 1;
2097 symbol.n_value = try self.allocateAtom(atom, code.len, required_alignment);
2098 errdefer self.freeAtom(atom);
2107 symbol.n_value = try self.allocateAtom(atom_index, code.len, required_alignment);
2108 errdefer self.freeAtom(atom_index);
20992109
2100 try unnamed_consts.append(gpa, atom);
2110 try unnamed_consts.append(gpa, atom_index);
21012111
21022112 log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value });
21032113 log.debug(" (required alignment 0x{x})", .{required_alignment});
21042114
2105 try self.writeAtom(atom, code);
2115 try self.writeAtom(atom_index, code);
21062116
21072117 return atom.getSymbolIndex().?;
21082118}
......@@ -2129,14 +2139,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
21292139 }
21302140 }
21312141
2132 const atom = &decl.link.macho;
2133 try atom.ensureInitialized(self);
2134 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2135 if (gop.found_existing) {
2136 self.freeRelocationsForAtom(atom);
2137 } else {
2138 gop.value_ptr.* = null;
2139 }
2142 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2143 Atom.freeRelocations(self, atom_index);
2144 const atom = self.getAtom(atom_index);
21402145
21412146 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
21422147 defer code_buffer.deinit();
......@@ -2155,14 +2160,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
21552160 }, &code_buffer, .{
21562161 .dwarf = ds,
21572162 }, .{
2158 .parent_atom_index = decl.link.macho.getSymbolIndex().?,
2163 .parent_atom_index = atom.getSymbolIndex().?,
21592164 })
21602165 else
21612166 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
21622167 .ty = decl.ty,
21632168 .val = decl_val,
21642169 }, &code_buffer, .none, .{
2165 .parent_atom_index = decl.link.macho.getSymbolIndex().?,
2170 .parent_atom_index = atom.getSymbolIndex().?,
21662171 });
21672172
21682173 const code = switch (res) {
......@@ -2176,13 +2181,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
21762181 const addr = try self.updateDeclCode(decl_index, code);
21772182
21782183 if (decl_state) |*ds| {
2179 try self.d_sym.?.dwarf.commitDeclState(
2180 module,
2181 decl_index,
2182 addr,
2183 decl.link.macho.size,
2184 ds,
2185 );
2184 try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds);
21862185 }
21872186
21882187 // Since we updated the vaddr and the size, each corresponding export symbol also
......@@ -2190,7 +2189,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
21902189 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
21912190}
21922191
2193fn getDeclOutputSection(self: *MachO, decl: *Module.Decl) u8 {
2192pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index {
2193 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2194 if (!gop.found_existing) {
2195 gop.value_ptr.* = .{
2196 .atom = try self.createAtom(),
2197 .section = self.getDeclOutputSection(decl_index),
2198 .exports = .{},
2199 };
2200 }
2201 return gop.value_ptr.atom;
2202}
2203
2204fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 {
2205 const decl = self.base.options.module.?.declPtr(decl_index);
21942206 const ty = decl.ty;
21952207 const val = decl.val;
21962208 const zig_ty = ty.zigTypeTag();
......@@ -2341,13 +2353,11 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
23412353 const sym_name = try decl.getFullyQualifiedName(mod);
23422354 defer self.base.allocator.free(sym_name);
23432355
2344 const atom = &decl.link.macho;
2345 const sym_index = atom.getSymbolIndex().?; // Atom was not initialized
2346 const decl_ptr = self.decls.getPtr(decl_index).?;
2347 if (decl_ptr.* == null) {
2348 decl_ptr.* = self.getDeclOutputSection(decl);
2349 }
2350 const sect_id = decl_ptr.*.?;
2356 const decl_metadata = self.decls.get(decl_index).?;
2357 const atom_index = decl_metadata.atom;
2358 const atom = self.getAtom(atom_index);
2359 const sym_index = atom.getSymbolIndex().?;
2360 const sect_id = decl_metadata.section;
23512361 const code_len = code.len;
23522362
23532363 if (atom.size != 0) {
......@@ -2357,11 +2367,11 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
23572367 sym.n_sect = sect_id + 1;
23582368 sym.n_desc = 0;
23592369
2360 const capacity = decl.link.macho.capacity(self);
2370 const capacity = atom.capacity(self);
23612371 const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment);
23622372
23632373 if (need_realloc) {
2364 const vaddr = try self.growAtom(atom, code_len, required_alignment);
2374 const vaddr = try self.growAtom(atom_index, code_len, required_alignment);
23652375 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, sym.n_value, vaddr });
23662376 log.debug(" (required alignment 0x{x})", .{required_alignment});
23672377
......@@ -2369,19 +2379,19 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
23692379 sym.n_value = vaddr;
23702380 log.debug(" (updating GOT entry)", .{});
23712381 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2372 const got_atom = self.getGotAtomForSymbol(got_target).?;
2382 const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?;
23732383 self.markRelocsDirtyByTarget(got_target);
2374 try self.writePtrWidthAtom(got_atom);
2384 try self.writePtrWidthAtom(got_atom_index);
23752385 }
23762386 } else if (code_len < atom.size) {
2377 self.shrinkAtom(atom, code_len);
2378 } else if (atom.next == null) {
2387 self.shrinkAtom(atom_index, code_len);
2388 } else if (atom.next_index == null) {
23792389 const header = &self.sections.items(.header)[sect_id];
23802390 const segment = self.getSegment(sect_id);
23812391 const needed_size = (sym.n_value + code_len) - segment.vmaddr;
23822392 header.size = needed_size;
23832393 }
2384 atom.size = code_len;
2394 self.getAtomPtr(atom_index).size = code_len;
23852395 } else {
23862396 const name_str_index = try self.strtab.insert(gpa, sym_name);
23872397 const sym = atom.getSymbolPtr(self);
......@@ -2390,32 +2400,32 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
23902400 sym.n_sect = sect_id + 1;
23912401 sym.n_desc = 0;
23922402
2393 const vaddr = try self.allocateAtom(atom, code_len, required_alignment);
2394 errdefer self.freeAtom(atom);
2403 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
2404 errdefer self.freeAtom(atom_index);
23952405
23962406 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, vaddr });
23972407 log.debug(" (required alignment 0x{x})", .{required_alignment});
23982408
2399 atom.size = code_len;
2409 self.getAtomPtr(atom_index).size = code_len;
24002410 sym.n_value = vaddr;
24012411
24022412 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
24032413 const got_index = try self.allocateGotEntry(got_target);
2404 const got_atom = try self.createGotAtom(got_target);
2414 const got_atom_index = try self.createGotAtom(got_target);
2415 const got_atom = self.getAtom(got_atom_index);
24052416 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
2406 try self.writePtrWidthAtom(got_atom);
2417 try self.writePtrWidthAtom(got_atom_index);
24072418 }
24082419
24092420 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
2410 try self.writeAtom(atom, code);
2421 try self.writeAtom(atom_index, code);
24112422
24122423 return atom.getSymbol(self).n_value;
24132424}
24142425
2415pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
2416 _ = module;
2426pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void {
24172427 if (self.d_sym) |*d_sym| {
2418 try d_sym.dwarf.updateDeclLineNumber(decl);
2428 try d_sym.dwarf.updateDeclLineNumber(module, decl_index);
24192429 }
24202430}
24212431
......@@ -2432,22 +2442,17 @@ pub fn updateDeclExports(
24322442 if (self.llvm_object) |llvm_object|
24332443 return llvm_object.updateDeclExports(module, decl_index, exports);
24342444 }
2445
24352446 const tracy = trace(@src());
24362447 defer tracy.end();
24372448
24382449 const gpa = self.base.allocator;
24392450
24402451 const decl = module.declPtr(decl_index);
2441 const atom = &decl.link.macho;
2442
2443 if (atom.getSymbolIndex() == null) return;
2444
2445 const gop = try self.decls.getOrPut(gpa, decl_index);
2446 if (!gop.found_existing) {
2447 gop.value_ptr.* = self.getDeclOutputSection(decl);
2448 }
2449
2452 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2453 const atom = self.getAtom(atom_index);
24502454 const decl_sym = atom.getSymbol(self);
2455 const decl_metadata = self.decls.getPtr(decl_index).?;
24512456
24522457 for (exports) |exp| {
24532458 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name});
......@@ -2485,9 +2490,9 @@ pub fn updateDeclExports(
24852490 continue;
24862491 }
24872492
2488 const sym_index = exp.link.macho.sym_index orelse blk: {
2493 const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: {
24892494 const sym_index = try self.allocateSymbol();
2490 exp.link.macho.sym_index = sym_index;
2495 try decl_metadata.exports.append(gpa, sym_index);
24912496 break :blk sym_index;
24922497 };
24932498 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
......@@ -2535,16 +2540,18 @@ pub fn updateDeclExports(
25352540 }
25362541}
25372542
2538pub fn deleteExport(self: *MachO, exp: Export) void {
2543pub fn deleteDeclExport(self: *MachO, decl_index: Module.Decl.Index, name: []const u8) Allocator.Error!void {
25392544 if (self.llvm_object) |_| return;
2540 const sym_index = exp.sym_index orelse return;
2545 const metadata = self.decls.getPtr(decl_index) orelse return;
25412546
25422547 const gpa = self.base.allocator;
2548 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
2549 defer gpa.free(exp_name);
2550 const sym_index = metadata.getExportPtr(self, exp_name) orelse return;
25432551
2544 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2552 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
25452553 const sym = self.getSymbolPtr(sym_loc);
2546 const sym_name = self.getSymbolName(sym_loc);
2547 log.debug("deleting export '{s}'", .{sym_name});
2554 log.debug("deleting export '{s}'", .{exp_name});
25482555 assert(sym.sect() and sym.ext());
25492556 sym.* = .{
25502557 .n_strx = 0,
......@@ -2553,9 +2560,9 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
25532560 .n_desc = 0,
25542561 .n_value = 0,
25552562 };
2556 self.locals_free_list.append(gpa, sym_index) catch {};
2563 self.locals_free_list.append(gpa, sym_index.*) catch {};
25572564
2558 if (self.resolver.fetchRemove(sym_name)) |entry| {
2565 if (self.resolver.fetchRemove(exp_name)) |entry| {
25592566 defer gpa.free(entry.key);
25602567 self.globals_free_list.append(gpa, entry.value) catch {};
25612568 self.globals.items[entry.value] = .{
......@@ -2563,17 +2570,8 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
25632570 .file = null,
25642571 };
25652572 }
2566}
25672573
2568fn freeRelocationsForAtom(self: *MachO, atom: *Atom) void {
2569 var removed_relocs = self.relocs.fetchOrderedRemove(atom);
2570 if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator);
2571 var removed_rebases = self.rebases.fetchOrderedRemove(atom);
2572 if (removed_rebases) |*rebases| rebases.value.deinit(self.base.allocator);
2573 var removed_bindings = self.bindings.fetchOrderedRemove(atom);
2574 if (removed_bindings) |*bindings| bindings.value.deinit(self.base.allocator);
2575 var removed_lazy_bindings = self.lazy_bindings.fetchOrderedRemove(atom);
2576 if (removed_lazy_bindings) |*lazy_bindings| lazy_bindings.value.deinit(self.base.allocator);
2574 sym_index.* = 0;
25772575}
25782576
25792577fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {
......@@ -2594,29 +2592,25 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {
25942592
25952593 log.debug("freeDecl {*}", .{decl});
25962594
2597 if (self.decls.fetchSwapRemove(decl_index)) |kv| {
2598 if (kv.value) |_| {
2599 self.freeAtom(&decl.link.macho);
2600 self.freeUnnamedConsts(decl_index);
2601 }
2595 if (self.decls.fetchSwapRemove(decl_index)) |const_kv| {
2596 var kv = const_kv;
2597 self.freeAtom(kv.value.atom);
2598 self.freeUnnamedConsts(decl_index);
2599 kv.value.exports.deinit(self.base.allocator);
26022600 }
26032601
26042602 if (self.d_sym) |*d_sym| {
2605 d_sym.dwarf.freeDecl(decl);
2603 d_sym.dwarf.freeDecl(decl_index);
26062604 }
26072605}
26082606
26092607pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 {
2610 const mod = self.base.options.module.?;
2611 const decl = mod.declPtr(decl_index);
2612
26132608 assert(self.llvm_object == null);
26142609
2615 try decl.link.macho.ensureInitialized(self);
2616 const sym_index = decl.link.macho.getSymbolIndex().?;
2617
2618 const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
2619 try atom.addRelocation(self, .{
2610 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
2611 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
2612 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
2613 try Atom.addRelocation(self, atom_index, .{
26202614 .type = switch (self.base.options.target.cpu.arch) {
26212615 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
26222616 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
......@@ -2628,7 +2622,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
26282622 .pcrel = false,
26292623 .length = 3,
26302624 });
2631 try atom.addRebase(self, @intCast(u32, reloc_info.offset));
2625 try Atom.addRebase(self, atom_index, @intCast(u32, reloc_info.offset));
26322626
26332627 return 0;
26342628}
......@@ -2860,34 +2854,36 @@ fn moveSectionInVirtualMemory(self: *MachO, sect_id: u8, needed_size: u64) !void
28602854 // TODO: enforce order by increasing VM addresses in self.sections container.
28612855 for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| {
28622856 const index = @intCast(u8, sect_id + 1 + next_sect_id);
2863 const maybe_last_atom = &self.sections.items(.last_atom)[index];
28642857 const next_segment = self.getSegmentPtr(index);
28652858 next_header.addr += diff;
28662859 next_segment.vmaddr += diff;
28672860
2868 if (maybe_last_atom.*) |last_atom| {
2869 var atom = last_atom;
2861 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[index];
2862 if (maybe_last_atom_index.*) |last_atom_index| {
2863 var atom_index = last_atom_index;
28702864 while (true) {
2865 const atom = self.getAtom(atom_index);
28712866 const sym = atom.getSymbolPtr(self);
28722867 sym.n_value += diff;
28732868
2874 if (atom.prev) |prev| {
2875 atom = prev;
2869 if (atom.prev_index) |prev_index| {
2870 atom_index = prev_index;
28762871 } else break;
28772872 }
28782873 }
28792874 }
28802875}
28812876
2882fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64 {
2877fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 {
28832878 const tracy = trace(@src());
28842879 defer tracy.end();
28852880
2881 const atom = self.getAtom(atom_index);
28862882 const sect_id = atom.getSymbol(self).n_sect - 1;
28872883 const segment = self.getSegmentPtr(sect_id);
28882884 const header = &self.sections.items(.header)[sect_id];
28892885 const free_list = &self.sections.items(.free_list)[sect_id];
2890 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];
2886 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
28912887 const requires_padding = blk: {
28922888 if (!header.isCode()) break :blk false;
28932889 if (header.isSymbolStubs()) break :blk false;
......@@ -2901,7 +2897,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
29012897 // It would be simpler to do it inside the for loop below, but that would cause a
29022898 // problem if an error was returned later in the function. So this action
29032899 // is actually carried out at the end of the function, when errors are no longer possible.
2904 var atom_placement: ?*Atom = null;
2900 var atom_placement: ?Atom.Index = null;
29052901 var free_list_removal: ?usize = null;
29062902
29072903 // First we look for an appropriately sized free list node.
......@@ -2909,7 +2905,8 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
29092905 var vaddr = blk: {
29102906 var i: usize = 0;
29112907 while (i < free_list.items.len) {
2912 const big_atom = free_list.items[i];
2908 const big_atom_index = free_list.items[i];
2909 const big_atom = self.getAtom(big_atom_index);
29132910 // We now have a pointer to a live atom that has too much capacity.
29142911 // Is it enough that we could fit this new atom?
29152912 const sym = big_atom.getSymbol(self);
......@@ -2937,30 +2934,35 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
29372934 const keep_free_list_node = remaining_capacity >= min_text_capacity;
29382935
29392936 // Set up the metadata to be updated, after errors are no longer possible.
2940 atom_placement = big_atom;
2937 atom_placement = big_atom_index;
29412938 if (!keep_free_list_node) {
29422939 free_list_removal = i;
29432940 }
29442941 break :blk new_start_vaddr;
2945 } else if (maybe_last_atom.*) |last| {
2942 } else if (maybe_last_atom_index.*) |last_index| {
2943 const last = self.getAtom(last_index);
29462944 const last_symbol = last.getSymbol(self);
29472945 const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size;
29482946 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
29492947 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
2950 atom_placement = last;
2948 atom_placement = last_index;
29512949 break :blk new_start_vaddr;
29522950 } else {
29532951 break :blk mem.alignForwardGeneric(u64, segment.vmaddr, alignment);
29542952 }
29552953 };
29562954
2957 const expand_section = atom_placement == null or atom_placement.?.next == null;
2955 const expand_section = if (atom_placement) |placement_index|
2956 self.getAtom(placement_index).next_index == null
2957 else
2958 true;
29582959 if (expand_section) {
29592960 const sect_capacity = self.allocatedSize(header.offset);
29602961 const needed_size = (vaddr + new_atom_size) - segment.vmaddr;
29612962 if (needed_size > sect_capacity) {
29622963 const new_offset = self.findFreeSpace(needed_size, self.page_size);
2963 const current_size = if (maybe_last_atom.*) |last_atom| blk: {
2964 const current_size = if (maybe_last_atom_index.*) |last_atom_index| blk: {
2965 const last_atom = self.getAtom(last_atom_index);
29642966 const sym = last_atom.getSymbol(self);
29652967 break :blk (sym.n_value + last_atom.size) - segment.vmaddr;
29662968 } else 0;
......@@ -2992,7 +2994,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
29922994 header.size = needed_size;
29932995 segment.filesize = mem.alignForwardGeneric(u64, needed_size, self.page_size);
29942996 segment.vmsize = mem.alignForwardGeneric(u64, needed_size, self.page_size);
2995 maybe_last_atom.* = atom;
2997 maybe_last_atom_index.* = atom_index;
29962998
29972999 self.segment_table_dirty = true;
29983000 }
......@@ -3001,21 +3003,31 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
30013003 if (header.@"align" < align_pow) {
30023004 header.@"align" = align_pow;
30033005 }
3006 {
3007 const atom_ptr = self.getAtomPtr(atom_index);
3008 atom_ptr.size = new_atom_size;
3009 atom_ptr.alignment = @intCast(u32, alignment);
3010 }
30043011
3005 if (atom.prev) |prev| {
3006 prev.next = atom.next;
3012 if (atom.prev_index) |prev_index| {
3013 const prev = self.getAtomPtr(prev_index);
3014 prev.next_index = atom.next_index;
30073015 }
3008 if (atom.next) |next| {
3009 next.prev = atom.prev;
3016 if (atom.next_index) |next_index| {
3017 const next = self.getAtomPtr(next_index);
3018 next.prev_index = atom.prev_index;
30103019 }
30113020
3012 if (atom_placement) |big_atom| {
3013 atom.prev = big_atom;
3014 atom.next = big_atom.next;
3015 big_atom.next = atom;
3021 if (atom_placement) |big_atom_index| {
3022 const big_atom = self.getAtomPtr(big_atom_index);
3023 const atom_ptr = self.getAtomPtr(atom_index);
3024 atom_ptr.prev_index = big_atom_index;
3025 atom_ptr.next_index = big_atom.next_index;
3026 big_atom.next_index = atom_index;
30163027 } else {
3017 atom.prev = null;
3018 atom.next = null;
3028 const atom_ptr = self.getAtomPtr(atom_index);
3029 atom_ptr.prev_index = null;
3030 atom_ptr.next_index = null;
30193031 }
30203032 if (free_list_removal) |i| {
30213033 _ = free_list.swapRemove(i);
......@@ -3155,7 +3167,8 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {
31553167 const gpa = self.base.allocator;
31563168 const slice = self.sections.slice();
31573169
3158 for (self.rebases.keys()) |atom, i| {
3170 for (self.rebases.keys()) |atom_index, i| {
3171 const atom = self.getAtom(atom_index);
31593172 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });
31603173
31613174 const sym = atom.getSymbol(self);
......@@ -3184,7 +3197,8 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {
31843197 const gpa = self.base.allocator;
31853198 const slice = self.sections.slice();
31863199
3187 for (raw_bindings.keys()) |atom, i| {
3200 for (raw_bindings.keys()) |atom_index, i| {
3201 const atom = self.getAtom(atom_index);
31883202 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });
31893203
31903204 const sym = atom.getSymbol(self);
......@@ -3359,7 +3373,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void
33593373 if (lazy_bind.size() == 0) return;
33603374
33613375 const stub_helper_section_index = self.stub_helper_section_index.?;
3362 assert(self.stub_helper_preamble_atom != null);
3376 assert(self.stub_helper_preamble_atom_index != null);
33633377
33643378 const section = self.sections.get(stub_helper_section_index);
33653379
......@@ -3369,10 +3383,11 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void
33693383 else => unreachable,
33703384 };
33713385 const header = section.header;
3372 var atom = section.last_atom.?;
3386 var atom_index = section.last_atom_index.?;
33733387
33743388 var index: usize = lazy_bind.offsets.items.len;
33753389 while (index > 0) : (index -= 1) {
3390 const atom = self.getAtom(atom_index);
33763391 const sym = atom.getSymbol(self);
33773392 const file_offset = header.offset + sym.n_value - header.addr + stub_offset;
33783393 const bind_offset = lazy_bind.offsets.items[index - 1];
......@@ -3385,7 +3400,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void
33853400
33863401 try self.base.file.?.pwriteAll(mem.asBytes(&bind_offset), file_offset);
33873402
3388 atom = atom.prev.?;
3403 atom_index = atom.prev_index.?;
33893404 }
33903405}
33913406
......@@ -3828,25 +3843,35 @@ pub fn getOrPutGlobalPtr(self: *MachO, name: []const u8) !GetOrPutGlobalPtrResul
38283843 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
38293844}
38303845
3846pub fn getAtom(self: *MachO, atom_index: Atom.Index) Atom {
3847 assert(atom_index < self.atoms.items.len);
3848 return self.atoms.items[atom_index];
3849}
3850
3851pub fn getAtomPtr(self: *MachO, atom_index: Atom.Index) *Atom {
3852 assert(atom_index < self.atoms.items.len);
3853 return &self.atoms.items[atom_index];
3854}
3855
38313856/// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor.
38323857/// Returns null on failure.
3833pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {
3858pub fn getAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
38343859 assert(sym_with_loc.file == null);
38353860 return self.atom_by_index_table.get(sym_with_loc.sym_index);
38363861}
38373862
38383863/// Returns GOT atom that references `sym_with_loc` if one exists.
38393864/// Returns null otherwise.
3840pub fn getGotAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {
3865pub fn getGotAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
38413866 const got_index = self.got_entries_table.get(sym_with_loc) orelse return null;
3842 return self.got_entries.items[got_index].getAtom(self);
3867 return self.got_entries.items[got_index].getAtomIndex(self);
38433868}
38443869
38453870/// Returns stubs atom that references `sym_with_loc` if one exists.
38463871/// Returns null otherwise.
3847pub fn getStubsAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {
3872pub fn getStubsAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
38483873 const stubs_index = self.stubs_table.get(sym_with_loc) orelse return null;
3849 return self.stubs.items[stubs_index].getAtom(self);
3874 return self.stubs.items[stubs_index].getAtomIndex(self);
38503875}
38513876
38523877/// Returns symbol location corresponding to the set entrypoint.
......@@ -4232,26 +4257,31 @@ pub fn logAtoms(self: *MachO) void {
42324257 log.debug("atoms:", .{});
42334258
42344259 const slice = self.sections.slice();
4235 for (slice.items(.last_atom)) |last, i| {
4236 var atom = last orelse continue;
4260 for (slice.items(.last_atom_index)) |last_atom_index, i| {
4261 var atom_index = last_atom_index orelse continue;
42374262 const header = slice.items(.header)[i];
42384263
4239 while (atom.prev) |prev| {
4240 atom = prev;
4264 while (true) {
4265 const atom = self.getAtom(atom_index);
4266 if (atom.prev_index) |prev_index| {
4267 atom_index = prev_index;
4268 } else break;
42414269 }
42424270
42434271 log.debug("{s},{s}", .{ header.segName(), header.sectName() });
42444272
42454273 while (true) {
4246 self.logAtom(atom);
4247 if (atom.next) |next| {
4248 atom = next;
4274 self.logAtom(atom_index);
4275 const atom = self.getAtom(atom_index);
4276 if (atom.next_index) |next_index| {
4277 atom_index = next_index;
42494278 } else break;
42504279 }
42514280 }
42524281}
42534282
4254pub fn logAtom(self: *MachO, atom: *const Atom) void {
4283pub fn logAtom(self: *MachO, atom_index: Atom.Index) void {
4284 const atom = self.getAtom(atom_index);
42554285 const sym = atom.getSymbol(self);
42564286 const sym_name = atom.getName(self);
42574287 log.debug(" ATOM(%{?d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{
src/link/MachO/Atom.zig+42-40
......@@ -13,7 +13,6 @@ const trace = @import("../../tracy.zig").trace;
1313
1414const Allocator = mem.Allocator;
1515const Arch = std.Target.Cpu.Arch;
16const Dwarf = @import("../Dwarf.zig");
1716const MachO = @import("../MachO.zig");
1817const Relocation = @import("Relocation.zig");
1918const SymbolWithLoc = MachO.SymbolWithLoc;
......@@ -39,10 +38,11 @@ size: u64,
3938alignment: u32,
4039
4140/// Points to the previous and next neighbours
42next: ?*Atom,
43prev: ?*Atom,
41/// TODO use the same trick as with symbols: reserve index 0 as null atom
42next_index: ?Index,
43prev_index: ?Index,
4444
45dbg_info_atom: Dwarf.Atom,
45pub const Index = u32;
4646
4747pub const Binding = struct {
4848 target: SymbolWithLoc,
......@@ -54,22 +54,6 @@ pub const SymbolAtOffset = struct {
5454 offset: u64,
5555};
5656
57pub const empty = Atom{
58 .sym_index = 0,
59 .file = null,
60 .size = 0,
61 .alignment = 0,
62 .prev = null,
63 .next = null,
64 .dbg_info_atom = undefined,
65};
66
67pub fn ensureInitialized(self: *Atom, macho_file: *MachO) !void {
68 if (self.getSymbolIndex() != null) return; // Already initialized
69 self.sym_index = try macho_file.allocateSymbol();
70 try macho_file.atom_by_index_table.putNoClobber(macho_file.base.allocator, self.sym_index, self);
71}
72
7357pub fn getSymbolIndex(self: Atom) ?u32 {
7458 if (self.sym_index == 0) return null;
7559 return self.sym_index;
......@@ -108,7 +92,8 @@ pub fn getName(self: Atom, macho_file: *MachO) []const u8 {
10892/// this calculation.
10993pub fn capacity(self: Atom, macho_file: *MachO) u64 {
11094 const self_sym = self.getSymbol(macho_file);
111 if (self.next) |next| {
95 if (self.next_index) |next_index| {
96 const next = macho_file.getAtom(next_index);
11297 const next_sym = next.getSymbol(macho_file);
11398 return next_sym.n_value - self_sym.n_value;
11499 } else {
......@@ -120,7 +105,8 @@ pub fn capacity(self: Atom, macho_file: *MachO) u64 {
120105
121106pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
122107 // No need to keep a free list node for the last atom.
123 const next = self.next orelse return false;
108 const next_index = self.next_index orelse return false;
109 const next = macho_file.getAtom(next_index);
124110 const self_sym = self.getSymbol(macho_file);
125111 const next_sym = next.getSymbol(macho_file);
126112 const cap = next_sym.n_value - self_sym.n_value;
......@@ -130,19 +116,19 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
130116 return surplus >= MachO.min_text_capacity;
131117}
132118
133pub fn addRelocation(self: *Atom, macho_file: *MachO, reloc: Relocation) !void {
134 return self.addRelocations(macho_file, 1, .{reloc});
119pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) !void {
120 return addRelocations(macho_file, atom_index, 1, .{reloc});
135121}
136122
137123pub fn addRelocations(
138 self: *Atom,
139124 macho_file: *MachO,
125 atom_index: Index,
140126 comptime count: comptime_int,
141127 relocs: [count]Relocation,
142128) !void {
143129 const gpa = macho_file.base.allocator;
144130 const target = macho_file.base.options.target;
145 const gop = try macho_file.relocs.getOrPut(gpa, self);
131 const gop = try macho_file.relocs.getOrPut(gpa, atom_index);
146132 if (!gop.found_existing) {
147133 gop.value_ptr.* = .{};
148134 }
......@@ -156,56 +142,72 @@ pub fn addRelocations(
156142 }
157143}
158144
159pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void {
145pub fn addRebase(macho_file: *MachO, atom_index: Index, offset: u32) !void {
160146 const gpa = macho_file.base.allocator;
161 log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, self.getSymbolIndex() });
162 const gop = try macho_file.rebases.getOrPut(gpa, self);
147 const atom = macho_file.getAtom(atom_index);
148 log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, atom.getSymbolIndex() });
149 const gop = try macho_file.rebases.getOrPut(gpa, atom_index);
163150 if (!gop.found_existing) {
164151 gop.value_ptr.* = .{};
165152 }
166153 try gop.value_ptr.append(gpa, offset);
167154}
168155
169pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {
156pub fn addBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void {
170157 const gpa = macho_file.base.allocator;
158 const atom = macho_file.getAtom(atom_index);
171159 log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{?d})", .{
172160 macho_file.getSymbolName(binding.target),
173161 binding.offset,
174 self.getSymbolIndex(),
162 atom.getSymbolIndex(),
175163 });
176 const gop = try macho_file.bindings.getOrPut(gpa, self);
164 const gop = try macho_file.bindings.getOrPut(gpa, atom_index);
177165 if (!gop.found_existing) {
178166 gop.value_ptr.* = .{};
179167 }
180168 try gop.value_ptr.append(gpa, binding);
181169}
182170
183pub fn addLazyBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {
171pub fn addLazyBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void {
184172 const gpa = macho_file.base.allocator;
173 const atom = macho_file.getAtom(atom_index);
185174 log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{?d})", .{
186175 macho_file.getSymbolName(binding.target),
187176 binding.offset,
188 self.getSymbolIndex(),
177 atom.getSymbolIndex(),
189178 });
190 const gop = try macho_file.lazy_bindings.getOrPut(gpa, self);
179 const gop = try macho_file.lazy_bindings.getOrPut(gpa, atom_index);
191180 if (!gop.found_existing) {
192181 gop.value_ptr.* = .{};
193182 }
194183 try gop.value_ptr.append(gpa, binding);
195184}
196185
197pub fn resolveRelocations(self: *Atom, macho_file: *MachO) !void {
198 const relocs = macho_file.relocs.get(self) orelse return;
199 const source_sym = self.getSymbol(macho_file);
186pub fn resolveRelocations(macho_file: *MachO, atom_index: Index) !void {
187 const atom = macho_file.getAtom(atom_index);
188 const relocs = macho_file.relocs.get(atom_index) orelse return;
189 const source_sym = atom.getSymbol(macho_file);
200190 const source_section = macho_file.sections.get(source_sym.n_sect - 1).header;
201191 const file_offset = source_section.offset + source_sym.n_value - source_section.addr;
202192
203 log.debug("relocating '{s}'", .{self.getName(macho_file)});
193 log.debug("relocating '{s}'", .{atom.getName(macho_file)});
204194
205195 for (relocs.items) |*reloc| {
206196 if (!reloc.dirty) continue;
207197
208 try reloc.resolve(self, macho_file, file_offset);
198 try reloc.resolve(macho_file, atom_index, file_offset);
209199 reloc.dirty = false;
210200 }
211201}
202
203pub fn freeRelocations(macho_file: *MachO, atom_index: Index) void {
204 const gpa = macho_file.base.allocator;
205 var removed_relocs = macho_file.relocs.fetchOrderedRemove(atom_index);
206 if (removed_relocs) |*relocs| relocs.value.deinit(gpa);
207 var removed_rebases = macho_file.rebases.fetchOrderedRemove(atom_index);
208 if (removed_rebases) |*rebases| rebases.value.deinit(gpa);
209 var removed_bindings = macho_file.bindings.fetchOrderedRemove(atom_index);
210 if (removed_bindings) |*bindings| bindings.value.deinit(gpa);
211 var removed_lazy_bindings = macho_file.lazy_bindings.fetchOrderedRemove(atom_index);
212 if (removed_lazy_bindings) |*lazy_bindings| lazy_bindings.value.deinit(gpa);
213}
src/link/MachO/DebugSymbols.zig+6-6
......@@ -82,11 +82,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols) !void {
8282 }
8383
8484 if (self.debug_str_section_index == null) {
85 assert(self.dwarf.strtab.items.len == 0);
86 try self.dwarf.strtab.append(self.allocator, 0);
85 assert(self.dwarf.strtab.buffer.items.len == 0);
86 try self.dwarf.strtab.buffer.append(self.allocator, 0);
8787 self.debug_str_section_index = try self.allocateSection(
8888 "__debug_str",
89 @intCast(u32, self.dwarf.strtab.items.len),
89 @intCast(u32, self.dwarf.strtab.buffer.items.len),
9090 0,
9191 );
9292 self.debug_string_table_dirty = true;
......@@ -291,10 +291,10 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
291291
292292 {
293293 const sect_index = self.debug_str_section_index.?;
294 if (self.debug_string_table_dirty or self.dwarf.strtab.items.len != self.getSection(sect_index).size) {
295 const needed_size = @intCast(u32, self.dwarf.strtab.items.len);
294 if (self.debug_string_table_dirty or self.dwarf.strtab.buffer.items.len != self.getSection(sect_index).size) {
295 const needed_size = @intCast(u32, self.dwarf.strtab.buffer.items.len);
296296 try self.growSection(sect_index, needed_size, false);
297 try self.file.pwriteAll(self.dwarf.strtab.items, self.getSection(sect_index).offset);
297 try self.file.pwriteAll(self.dwarf.strtab.buffer.items, self.getSection(sect_index).offset);
298298 self.debug_string_table_dirty = false;
299299 }
300300 }
src/link/MachO/Relocation.zig+9-7
......@@ -29,33 +29,35 @@ pub fn fmtType(self: Relocation, target: std.Target) []const u8 {
2929 }
3030}
3131
32pub fn getTargetAtom(self: Relocation, macho_file: *MachO) ?*Atom {
32pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
3333 switch (macho_file.base.options.target.cpu.arch) {
3434 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.type)) {
3535 .ARM64_RELOC_GOT_LOAD_PAGE21,
3636 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
3737 .ARM64_RELOC_POINTER_TO_GOT,
38 => return macho_file.getGotAtomForSymbol(self.target),
38 => return macho_file.getGotAtomIndexForSymbol(self.target),
3939 else => {},
4040 },
4141 .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, self.type)) {
4242 .X86_64_RELOC_GOT,
4343 .X86_64_RELOC_GOT_LOAD,
44 => return macho_file.getGotAtomForSymbol(self.target),
44 => return macho_file.getGotAtomIndexForSymbol(self.target),
4545 else => {},
4646 },
4747 else => unreachable,
4848 }
49 if (macho_file.getStubsAtomForSymbol(self.target)) |stubs_atom| return stubs_atom;
50 return macho_file.getAtomForSymbol(self.target);
49 if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom;
50 return macho_file.getAtomIndexForSymbol(self.target);
5151}
5252
53pub fn resolve(self: Relocation, atom: *Atom, macho_file: *MachO, base_offset: u64) !void {
53pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, base_offset: u64) !void {
5454 const arch = macho_file.base.options.target.cpu.arch;
55 const atom = macho_file.getAtom(atom_index);
5556 const source_sym = atom.getSymbol(macho_file);
5657 const source_addr = source_sym.n_value + self.offset;
5758
58 const target_atom = self.getTargetAtom(macho_file) orelse return;
59 const target_atom_index = self.getTargetAtomIndex(macho_file) orelse return;
60 const target_atom = macho_file.getAtom(target_atom_index);
5961 const target_addr = @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend;
6062
6163 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
src/link/Plan9.zig+149-83
......@@ -21,14 +21,7 @@ const Allocator = std.mem.Allocator;
2121const log = std.log.scoped(.link);
2222const assert = std.debug.assert;
2323
24const FnDeclOutput = struct {
25 /// this code is modified when relocated so it is mutable
26 code: []u8,
27 /// this might have to be modified in the linker, so thats why its mutable
28 lineinfo: []u8,
29 start_line: u32,
30 end_line: u32,
31};
24pub const base_tag = .plan9;
3225
3326base: link.File,
3427sixtyfour_bit: bool,
......@@ -101,6 +94,9 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},
10194
10295syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},
10396
97decl_blocks: std.ArrayListUnmanaged(DeclBlock) = .{},
98decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
99
104100const Reloc = struct {
105101 target: Module.Decl.Index,
106102 offset: u64,
......@@ -115,6 +111,42 @@ const Bases = struct {
115111
116112const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 }));
117113
114pub const PtrWidth = enum { p32, p64 };
115
116pub const DeclBlock = struct {
117 type: aout.Sym.Type,
118 /// offset in the text or data sects
119 offset: ?u64,
120 /// offset into syms
121 sym_index: ?usize,
122 /// offset into got
123 got_index: ?usize,
124
125 pub const Index = u32;
126};
127
128const DeclMetadata = struct {
129 index: DeclBlock.Index,
130 exports: std.ArrayListUnmanaged(usize) = .{},
131
132 fn getExport(m: DeclMetadata, p9: *const Plan9, name: []const u8) ?usize {
133 for (m.exports.items) |exp| {
134 const sym = p9.syms.items[exp];
135 if (mem.eql(u8, name, sym.name)) return exp;
136 }
137 return null;
138 }
139};
140
141const FnDeclOutput = struct {
142 /// this code is modified when relocated so it is mutable
143 code: []u8,
144 /// this might have to be modified in the linker, so thats why its mutable
145 lineinfo: []u8,
146 start_line: u32,
147 end_line: u32,
148};
149
118150fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 {
119151 return addr + switch (t) {
120152 .T, .t, .l, .L => self.bases.text,
......@@ -127,22 +159,6 @@ fn getSymAddr(self: Plan9, s: aout.Sym) u64 {
127159 return self.getAddr(s.value, s.type);
128160}
129161
130pub const DeclBlock = struct {
131 type: aout.Sym.Type,
132 /// offset in the text or data sects
133 offset: ?u64,
134 /// offset into syms
135 sym_index: ?usize,
136 /// offset into got
137 got_index: ?usize,
138 pub const empty = DeclBlock{
139 .type = .t,
140 .offset = null,
141 .sym_index = null,
142 .got_index = null,
143 };
144};
145
146162pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
147163 return switch (arch) {
148164 .x86_64 => .{
......@@ -164,8 +180,6 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
164180 };
165181}
166182
167pub const PtrWidth = enum { p32, p64 };
168
169183pub fn createEmpty(gpa: Allocator, options: link.Options) !*Plan9 {
170184 if (options.use_llvm)
171185 return error.LLVMBackendDoesNotSupportPlan9;
......@@ -271,7 +285,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
271285 const decl = module.declPtr(decl_index);
272286 self.freeUnnamedConsts(decl_index);
273287
274 try self.seeDecl(decl_index);
288 _ = try self.seeDecl(decl_index);
275289 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });
276290
277291 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
......@@ -313,11 +327,11 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
313327 .end_line = end_line,
314328 };
315329 try self.putFn(decl_index, out);
316 return self.updateFinish(decl);
330 return self.updateFinish(decl_index);
317331}
318332
319333pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {
320 try self.seeDecl(decl_index);
334 _ = try self.seeDecl(decl_index);
321335 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
322336 defer code_buffer.deinit();
323337
......@@ -387,7 +401,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index)
387401 }
388402 }
389403
390 try self.seeDecl(decl_index);
404 _ = try self.seeDecl(decl_index);
391405
392406 log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index });
393407
......@@ -414,28 +428,31 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index)
414428 if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| {
415429 self.base.allocator.free(old_entry.value);
416430 }
417 return self.updateFinish(decl);
431 return self.updateFinish(decl_index);
418432}
419433/// called at the end of update{Decl,Func}
420fn updateFinish(self: *Plan9, decl: *Module.Decl) !void {
434fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void {
435 const decl = self.base.options.module.?.declPtr(decl_index);
421436 const is_fn = (decl.ty.zigTypeTag() == .Fn);
422437 log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name });
423438 const sym_t: aout.Sym.Type = if (is_fn) .t else .d;
439
440 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);
424441 // write the internal linker metadata
425 decl.link.plan9.type = sym_t;
442 decl_block.type = sym_t;
426443 // write the symbol
427444 // we already have the got index
428445 const sym: aout.Sym = .{
429446 .value = undefined, // the value of stuff gets filled in in flushModule
430 .type = decl.link.plan9.type,
447 .type = decl_block.type,
431448 .name = mem.span(decl.name),
432449 };
433450
434 if (decl.link.plan9.sym_index) |s| {
451 if (decl_block.sym_index) |s| {
435452 self.syms.items[s] = sym;
436453 } else {
437454 const s = try self.allocateSymbolIndex();
438 decl.link.plan9.sym_index = s;
455 decl_block.sym_index = s;
439456 self.syms.items[s] = sym;
440457 }
441458}
......@@ -550,6 +567,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
550567 while (it.next()) |entry| {
551568 const decl_index = entry.key_ptr.*;
552569 const decl = mod.declPtr(decl_index);
570 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);
553571 const out = entry.value_ptr.*;
554572 log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line + 1, out.end_line });
555573 {
......@@ -568,16 +586,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
568586 iovecs_i += 1;
569587 const off = self.getAddr(text_i, .t);
570588 text_i += out.code.len;
571 decl.link.plan9.offset = off;
589 decl_block.offset = off;
572590 if (!self.sixtyfour_bit) {
573 mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off));
574 mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
591 mem.writeIntNative(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off));
592 mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
575593 } else {
576 mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
594 mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
577595 }
578 self.syms.items[decl.link.plan9.sym_index.?].value = off;
596 self.syms.items[decl_block.sym_index.?].value = off;
579597 if (mod.decl_exports.get(decl_index)) |exports| {
580 try self.addDeclExports(mod, decl, exports.items);
598 try self.addDeclExports(mod, decl_index, exports.items);
581599 }
582600 }
583601 }
......@@ -598,6 +616,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
598616 while (it.next()) |entry| {
599617 const decl_index = entry.key_ptr.*;
600618 const decl = mod.declPtr(decl_index);
619 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);
601620 const code = entry.value_ptr.*;
602621 log.debug("write data decl {*} ({s})", .{ decl, decl.name });
603622
......@@ -606,15 +625,15 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
606625 iovecs_i += 1;
607626 const off = self.getAddr(data_i, .d);
608627 data_i += code.len;
609 decl.link.plan9.offset = off;
628 decl_block.offset = off;
610629 if (!self.sixtyfour_bit) {
611 mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
630 mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
612631 } else {
613 mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
632 mem.writeInt(u64, got_table[decl_block.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
614633 }
615 self.syms.items[decl.link.plan9.sym_index.?].value = off;
634 self.syms.items[decl_block.sym_index.?].value = off;
616635 if (mod.decl_exports.get(decl_index)) |exports| {
617 try self.addDeclExports(mod, decl, exports.items);
636 try self.addDeclExports(mod, decl_index, exports.items);
618637 }
619638 }
620639 // write the unnamed constants after the other data decls
......@@ -676,7 +695,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
676695 for (kv.value_ptr.items) |reloc| {
677696 const target_decl_index = reloc.target;
678697 const target_decl = mod.declPtr(target_decl_index);
679 const target_decl_offset = target_decl.link.plan9.offset.?;
698 const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index);
699 const target_decl_offset = target_decl_block.offset.?;
680700
681701 const offset = reloc.offset;
682702 const addend = reloc.addend;
......@@ -709,28 +729,36 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
709729fn addDeclExports(
710730 self: *Plan9,
711731 module: *Module,
712 decl: *Module.Decl,
732 decl_index: Module.Decl.Index,
713733 exports: []const *Module.Export,
714734) !void {
735 const metadata = self.decls.getPtr(decl_index).?;
736 const decl_block = self.getDeclBlock(metadata.index);
737
715738 for (exports) |exp| {
716739 // plan9 does not support custom sections
717740 if (exp.options.section) |section_name| {
718741 if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) {
719 try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{}));
742 try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(
743 self.base.allocator,
744 module.declPtr(decl_index).srcLoc(),
745 "plan9 does not support extra sections",
746 .{},
747 ));
720748 break;
721749 }
722750 }
723751 const sym = .{
724 .value = decl.link.plan9.offset.?,
725 .type = decl.link.plan9.type.toGlobal(),
752 .value = decl_block.offset.?,
753 .type = decl_block.type.toGlobal(),
726754 .name = exp.options.name,
727755 };
728756
729 if (exp.link.plan9) |i| {
757 if (metadata.getExport(self, exp.options.name)) |i| {
730758 self.syms.items[i] = sym;
731759 } else {
732760 try self.syms.append(self.base.allocator, sym);
733 exp.link.plan9 = self.syms.items.len - 1;
761 try metadata.exports.append(self.base.allocator, self.syms.items.len - 1);
734762 }
735763 }
736764}
......@@ -760,13 +788,18 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {
760788 self.base.allocator.free(removed_entry.value);
761789 }
762790 }
763 if (decl.link.plan9.got_index) |i| {
764 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length
765 self.got_index_free_list.append(self.base.allocator, i) catch {};
766 }
767 if (decl.link.plan9.sym_index) |i| {
768 self.syms_index_free_list.append(self.base.allocator, i) catch {};
769 self.syms.items[i] = aout.Sym.undefined_symbol;
791 if (self.decls.fetchRemove(decl_index)) |const_kv| {
792 var kv = const_kv;
793 const decl_block = self.getDeclBlock(kv.value.index);
794 if (decl_block.got_index) |i| {
795 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length
796 self.got_index_free_list.append(self.base.allocator, i) catch {};
797 }
798 if (decl_block.sym_index) |i| {
799 self.syms_index_free_list.append(self.base.allocator, i) catch {};
800 self.syms.items[i] = aout.Sym.undefined_symbol;
801 }
802 kv.value.exports.deinit(self.base.allocator);
770803 }
771804 self.freeUnnamedConsts(decl_index);
772805 {
......@@ -786,12 +819,30 @@ fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void {
786819 unnamed_consts.clearAndFree(self.base.allocator);
787820}
788821
789pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void {
790 const mod = self.base.options.module.?;
791 const decl = mod.declPtr(decl_index);
792 if (decl.link.plan9.got_index == null) {
793 decl.link.plan9.got_index = self.allocateGotIndex();
822fn createDeclBlock(self: *Plan9) !DeclBlock.Index {
823 const gpa = self.base.allocator;
824 const index = @intCast(DeclBlock.Index, self.decl_blocks.items.len);
825 const decl_block = try self.decl_blocks.addOne(gpa);
826 decl_block.* = .{
827 .type = .t,
828 .offset = null,
829 .sym_index = null,
830 .got_index = null,
831 };
832 return index;
833}
834
835pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !DeclBlock.Index {
836 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
837 if (!gop.found_existing) {
838 const index = try self.createDeclBlock();
839 self.getDeclBlockPtr(index).got_index = self.allocateGotIndex();
840 gop.value_ptr.* = .{
841 .index = index,
842 .exports = .{},
843 };
794844 }
845 return gop.value_ptr.index;
795846}
796847
797848pub fn updateDeclExports(
......@@ -800,7 +851,7 @@ pub fn updateDeclExports(
800851 decl_index: Module.Decl.Index,
801852 exports: []const *Module.Export,
802853) !void {
803 try self.seeDecl(decl_index);
854 _ = try self.seeDecl(decl_index);
804855 // we do all the things in flush
805856 _ = module;
806857 _ = exports;
......@@ -842,10 +893,17 @@ pub fn deinit(self: *Plan9) void {
842893 self.syms_index_free_list.deinit(gpa);
843894 self.file_segments.deinit(gpa);
844895 self.path_arena.deinit();
896 self.decl_blocks.deinit(gpa);
897
898 {
899 var it = self.decls.iterator();
900 while (it.next()) |entry| {
901 entry.value_ptr.exports.deinit(gpa);
902 }
903 self.decls.deinit(gpa);
904 }
845905}
846906
847pub const Export = ?usize;
848pub const base_tag = .plan9;
849907pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {
850908 if (options.use_llvm)
851909 return error.LLVMBackendDoesNotSupportPlan9;
......@@ -911,20 +969,19 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
911969 }
912970 }
913971
914 const mod = self.base.options.module.?;
915
916972 // write the data symbols
917973 {
918974 var it = self.data_decl_table.iterator();
919975 while (it.next()) |entry| {
920976 const decl_index = entry.key_ptr.*;
921 const decl = mod.declPtr(decl_index);
922 const sym = self.syms.items[decl.link.plan9.sym_index.?];
977 const decl_metadata = self.decls.get(decl_index).?;
978 const decl_block = self.getDeclBlock(decl_metadata.index);
979 const sym = self.syms.items[decl_block.sym_index.?];
923980 try self.writeSym(writer, sym);
924981 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
925 for (exports.items) |e| {
926 try self.writeSym(writer, self.syms.items[e.link.plan9.?]);
927 }
982 for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| {
983 try self.writeSym(writer, self.syms.items[exp_i]);
984 };
928985 }
929986 }
930987 }
......@@ -943,16 +1000,17 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
9431000 var submap_it = symidx_and_submap.functions.iterator();
9441001 while (submap_it.next()) |entry| {
9451002 const decl_index = entry.key_ptr.*;
946 const decl = mod.declPtr(decl_index);
947 const sym = self.syms.items[decl.link.plan9.sym_index.?];
1003 const decl_metadata = self.decls.get(decl_index).?;
1004 const decl_block = self.getDeclBlock(decl_metadata.index);
1005 const sym = self.syms.items[decl_block.sym_index.?];
9481006 try self.writeSym(writer, sym);
9491007 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
950 for (exports.items) |e| {
951 const s = self.syms.items[e.link.plan9.?];
1008 for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| {
1009 const s = self.syms.items[exp_i];
9521010 if (mem.eql(u8, s.name, "_start"))
9531011 self.entry_val = s.value;
9541012 try self.writeSym(writer, s);
955 }
1013 };
9561014 }
9571015 }
9581016 }
......@@ -960,10 +1018,10 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
9601018}
9611019
9621020/// Must be called only after a successful call to `updateDecl`.
963pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl: *const Module.Decl) !void {
1021pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void {
9641022 _ = self;
9651023 _ = mod;
966 _ = decl;
1024 _ = decl_index;
9671025}
9681026
9691027pub fn getDeclVAddr(
......@@ -1004,3 +1062,11 @@ pub fn getDeclVAddr(
10041062 });
10051063 return undefined;
10061064}
1065
1066pub fn getDeclBlock(self: *const Plan9, index: DeclBlock.Index) DeclBlock {
1067 return self.decl_blocks.items[index];
1068}
1069
1070fn getDeclBlockPtr(self: *Plan9, index: DeclBlock.Index) *DeclBlock {
1071 return &self.decl_blocks.items[index];
1072}
src/link/SpirV.zig+7-11
......@@ -42,13 +42,6 @@ const SpvModule = @import("../codegen/spirv/Module.zig");
4242const spec = @import("../codegen/spirv/spec.zig");
4343const IdResult = spec.IdResult;
4444
45// TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl?
46pub const FnData = struct {
47 // We're going to fill these in flushModule, and we're going to fill them unconditionally,
48 // so just set it to undefined.
49 id: IdResult = undefined,
50};
51
5245base: link.File,
5346
5447/// This linker backend does not try to incrementally link output SPIR-V code.
......@@ -209,16 +202,19 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
209202 // so that we can access them before processing them.
210203 // TODO: We're allocating an ID unconditionally now, are there
211204 // declarations which don't generate a result?
212 // TODO: fn_link is used here, but thats probably not the right field. It will work anyway though.
205 var ids = std.AutoHashMap(Module.Decl.Index, IdResult).init(self.base.allocator);
206 defer ids.deinit();
207 try ids.ensureTotalCapacity(@intCast(u32, self.decl_table.count()));
208
213209 for (self.decl_table.keys()) |decl_index| {
214210 const decl = module.declPtr(decl_index);
215211 if (decl.has_tv) {
216 decl.fn_link.spirv.id = spv.allocId();
212 ids.putAssumeCapacityNoClobber(decl_index, spv.allocId());
217213 }
218214 }
219215
220216 // Now, actually generate the code for all declarations.
221 var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &spv);
217 var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &spv, &ids);
222218 defer decl_gen.deinit();
223219
224220 var it = self.decl_table.iterator();
......@@ -231,7 +227,7 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
231227 const liveness = entry.value_ptr.liveness;
232228
233229 // Note, if `decl` is not a function, air/liveness may be undefined.
234 if (try decl_gen.gen(decl, air, liveness)) |msg| {
230 if (try decl_gen.gen(decl_index, air, liveness)) |msg| {
235231 try module.failed_decls.put(module.gpa, decl_index, msg);
236232 return; // TODO: Attempt to generate more decls?
237233 }
src/link/Wasm.zig+281-258
......@@ -9,7 +9,7 @@ const fs = std.fs;
99const leb = std.leb;
1010const log = std.log.scoped(.link);
1111
12const Atom = @import("Wasm/Atom.zig");
12pub const Atom = @import("Wasm/Atom.zig");
1313const Dwarf = @import("Dwarf.zig");
1414const Module = @import("../Module.zig");
1515const Compilation = @import("../Compilation.zig");
......@@ -31,10 +31,7 @@ const Object = @import("Wasm/Object.zig");
3131const Archive = @import("Wasm/Archive.zig");
3232const types = @import("Wasm/types.zig");
3333
34pub const base_tag = link.File.Tag.wasm;
35
36/// deprecated: Use `@import("Wasm/Atom.zig");`
37pub const DeclBlock = Atom;
34pub const base_tag: link.File.Tag = .wasm;
3835
3936base: link.File,
4037/// Output name of the file
......@@ -47,18 +44,16 @@ llvm_object: ?*LlvmObject = null,
4744/// TODO: Allow setting this through a flag?
4845host_name: []const u8 = "env",
4946/// List of all `Decl` that are currently alive.
50/// This is ment for bookkeeping so we can safely cleanup all codegen memory
51/// when calling `deinit`
52decls: std.AutoHashMapUnmanaged(Module.Decl.Index, void) = .{},
47/// Each index maps to the corresponding `Atom.Index`.
48decls: std.AutoHashMapUnmanaged(Module.Decl.Index, Atom.Index) = .{},
5349/// List of all symbols generated by Zig code.
5450symbols: std.ArrayListUnmanaged(Symbol) = .{},
5551/// List of symbol indexes which are free to be used.
5652symbols_free_list: std.ArrayListUnmanaged(u32) = .{},
5753/// Maps atoms to their segment index
58atoms: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
59/// Atoms managed and created by the linker. This contains atoms
60/// from object files, and not Atoms generated by a Decl.
61managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
54atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
55/// List of all atoms.
56managed_atoms: std.ArrayListUnmanaged(Atom) = .{},
6257/// Represents the index into `segments` where the 'code' section
6358/// lives.
6459code_section_index: ?u32 = null,
......@@ -148,7 +143,7 @@ undefs: std.StringArrayHashMapUnmanaged(SymbolLoc) = .{},
148143/// Maps a symbol's location to an atom. This can be used to find meta
149144/// data of a symbol, such as its size, or its offset to perform a relocation.
150145/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.
151symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, *Atom) = .{},
146symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .{},
152147/// Maps a symbol's location to its export name, which may differ from the decl's name
153148/// which does the exporting.
154149/// Note: The value represents the offset into the string table, rather than the actual string.
......@@ -165,14 +160,14 @@ error_table_symbol: ?u32 = null,
165160// unit contains Zig code. The lifetime of these atoms are extended
166161// until the end of the compiler's lifetime. Meaning they're not freed
167162// during `flush()` in incremental-mode.
168debug_info_atom: ?*Atom = null,
169debug_line_atom: ?*Atom = null,
170debug_loc_atom: ?*Atom = null,
171debug_ranges_atom: ?*Atom = null,
172debug_abbrev_atom: ?*Atom = null,
173debug_str_atom: ?*Atom = null,
174debug_pubnames_atom: ?*Atom = null,
175debug_pubtypes_atom: ?*Atom = null,
163debug_info_atom: ?Atom.Index = null,
164debug_line_atom: ?Atom.Index = null,
165debug_loc_atom: ?Atom.Index = null,
166debug_ranges_atom: ?Atom.Index = null,
167debug_abbrev_atom: ?Atom.Index = null,
168debug_str_atom: ?Atom.Index = null,
169debug_pubnames_atom: ?Atom.Index = null,
170debug_pubtypes_atom: ?Atom.Index = null,
176171
177172pub const Segment = struct {
178173 alignment: u32,
......@@ -183,13 +178,9 @@ pub const Segment = struct {
183178pub const FnData = struct {
184179 /// Reference to the wasm type that represents this function.
185180 type_index: u32,
186 /// Contains debug information related to this function.
187 /// For Wasm, the offset is relative to the code-section.
188 src_fn: Dwarf.SrcFn,
189181
190182 pub const empty: FnData = .{
191183 .type_index = undefined,
192 .src_fn = Dwarf.SrcFn.empty,
193184 };
194185};
195186
......@@ -434,10 +425,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
434425 // at the end during `initializeCallCtorsFunction`.
435426 }
436427
437 if (!options.strip and options.module != null) {
438 wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);
439 try wasm_bin.initDebugSections();
440 }
428 // if (!options.strip and options.module != null) {
429 // wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);
430 // try wasm_bin.initDebugSections();
431 // }
441432
442433 return wasm_bin;
443434}
......@@ -478,6 +469,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol
478469 try wasm.globals.put(wasm.base.allocator, name_offset, loc);
479470 return loc;
480471}
472
481473/// Initializes symbols and atoms for the debug sections
482474/// Initialization is only done when compiling Zig code.
483475/// When Zig is invoked as a linker instead, the atoms
......@@ -520,6 +512,36 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
520512 return true;
521513}
522514
515/// For a given `Module.Decl.Index` returns its corresponding `Atom.Index`.
516/// When the index was not found, a new `Atom` will be created, and its index will be returned.
517/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
518pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: Module.Decl.Index) !Atom.Index {
519 const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
520 if (!gop.found_existing) {
521 gop.value_ptr.* = try wasm.createAtom();
522 }
523 return gop.value_ptr.*;
524}
525
526/// Creates a new empty `Atom` and returns its `Atom.Index`
527fn createAtom(wasm: *Wasm) !Atom.Index {
528 const index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
529 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
530 atom.* = Atom.empty;
531 atom.sym_index = try wasm.allocateSymbol();
532 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, .{ .file = null, .index = atom.sym_index }, index);
533
534 return index;
535}
536
537pub inline fn getAtom(wasm: *const Wasm, index: Atom.Index) Atom {
538 return wasm.managed_atoms.items[index];
539}
540
541pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
542 return &wasm.managed_atoms.items[index];
543}
544
523545/// Parses an archive file and will then parse each object file
524546/// that was found in the archive file.
525547/// Returns false when the file is not an archive file.
......@@ -861,15 +883,16 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
861883 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
862884 _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations.
863885
864 const atom = try wasm.base.allocator.create(Atom);
865 errdefer wasm.base.allocator.destroy(atom);
866 try wasm.managed_atoms.append(wasm.base.allocator, atom);
886 // TODO: Can we use `createAtom` here while also re-using the symbol
887 // from `createSyntheticSymbol`.
888 const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
889 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
867890 atom.* = Atom.empty;
868891 atom.sym_index = loc.index;
869892 atom.alignment = 1;
870893
871 try wasm.parseAtom(atom, .{ .data = .synthetic });
872 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
894 try wasm.parseAtom(atom_index, .{ .data = .synthetic });
895 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
873896 }
874897
875898 if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| {
......@@ -877,15 +900,14 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
877900 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
878901 _ = wasm.resolved_symbols.swapRemove(loc);
879902
880 const atom = try wasm.base.allocator.create(Atom);
881 errdefer wasm.base.allocator.destroy(atom);
882 try wasm.managed_atoms.append(wasm.base.allocator, atom);
903 const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
904 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
883905 atom.* = Atom.empty;
884906 atom.sym_index = loc.index;
885907 atom.alignment = 1;
886908
887 try wasm.parseAtom(atom, .{ .data = .synthetic });
888 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
909 try wasm.parseAtom(atom_index, .{ .data = .synthetic });
910 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
889911 }
890912}
891913
......@@ -924,16 +946,6 @@ pub fn deinit(wasm: *Wasm) void {
924946 if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);
925947 }
926948
927 if (wasm.base.options.module) |mod| {
928 var decl_it = wasm.decls.keyIterator();
929 while (decl_it.next()) |decl_index_ptr| {
930 const decl = mod.declPtr(decl_index_ptr.*);
931 decl.link.wasm.deinit(gpa);
932 }
933 } else {
934 assert(wasm.decls.count() == 0);
935 }
936
937949 for (wasm.func_types.items) |*func_type| {
938950 func_type.deinit(gpa);
939951 }
......@@ -958,9 +970,8 @@ pub fn deinit(wasm: *Wasm) void {
958970 wasm.symbol_atom.deinit(gpa);
959971 wasm.export_names.deinit(gpa);
960972 wasm.atoms.deinit(gpa);
961 for (wasm.managed_atoms.items) |managed_atom| {
962 managed_atom.deinit(gpa);
963 gpa.destroy(managed_atom);
973 for (wasm.managed_atoms.items) |*managed_atom| {
974 managed_atom.deinit(wasm);
964975 }
965976 wasm.managed_atoms.deinit(gpa);
966977 wasm.segments.deinit(gpa);
......@@ -1018,18 +1029,24 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
10181029
10191030 const decl_index = func.owner_decl;
10201031 const decl = mod.declPtr(decl_index);
1021 const atom = &decl.link.wasm;
1022 try atom.ensureInitialized(wasm);
1023 const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
1024 if (gop.found_existing) {
1025 atom.clear();
1026 } else gop.value_ptr.* = {};
1032 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1033 const atom = wasm.getAtomPtr(atom_index);
1034 atom.clear();
10271035
1028 var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;
1029 defer if (decl_state) |*ds| ds.deinit();
1036 // var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;
1037 // defer if (decl_state) |*ds| ds.deinit();
10301038
10311039 var code_writer = std.ArrayList(u8).init(wasm.base.allocator);
10321040 defer code_writer.deinit();
1041 // const result = try codegen.generateFunction(
1042 // &wasm.base,
1043 // decl.srcLoc(),
1044 // func,
1045 // air,
1046 // liveness,
1047 // &code_writer,
1048 // if (decl_state) |*ds| .{ .dwarf = ds } else .none,
1049 // );
10331050 const result = try codegen.generateFunction(
10341051 &wasm.base,
10351052 decl.srcLoc(),
......@@ -1037,7 +1054,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
10371054 air,
10381055 liveness,
10391056 &code_writer,
1040 if (decl_state) |*ds| .{ .dwarf = ds } else .none,
1057 .none,
10411058 );
10421059
10431060 const code = switch (result) {
......@@ -1049,19 +1066,19 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
10491066 },
10501067 };
10511068
1052 if (wasm.dwarf) |*dwarf| {
1053 try dwarf.commitDeclState(
1054 mod,
1055 decl_index,
1056 // Actual value will be written after relocation.
1057 // For Wasm, this is the offset relative to the code section
1058 // which isn't known until flush().
1059 0,
1060 code.len,
1061 &decl_state.?,
1062 );
1063 }
1064 return wasm.finishUpdateDecl(decl, code);
1069 // if (wasm.dwarf) |*dwarf| {
1070 // try dwarf.commitDeclState(
1071 // mod,
1072 // decl_index,
1073 // // Actual value will be written after relocation.
1074 // // For Wasm, this is the offset relative to the code section
1075 // // which isn't known until flush().
1076 // 0,
1077 // code.len,
1078 // &decl_state.?,
1079 // );
1080 // }
1081 return wasm.finishUpdateDecl(decl_index, code);
10651082}
10661083
10671084// Generate code for the Decl, storing it in memory to be later written to
......@@ -1084,17 +1101,14 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
10841101 return;
10851102 }
10861103
1087 const atom = &decl.link.wasm;
1088 try atom.ensureInitialized(wasm);
1089 const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
1090 if (gop.found_existing) {
1091 atom.clear();
1092 } else gop.value_ptr.* = {};
1104 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1105 const atom = wasm.getAtomPtr(atom_index);
1106 atom.clear();
10931107
10941108 if (decl.isExtern()) {
10951109 const variable = decl.getVariable().?;
10961110 const name = mem.sliceTo(decl.name, 0);
1097 return wasm.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null);
1111 return wasm.addOrUpdateImport(name, atom.sym_index, variable.lib_name, null);
10981112 }
10991113 const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
11001114
......@@ -1107,7 +1121,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
11071121 .{ .ty = decl.ty, .val = val },
11081122 &code_writer,
11091123 .none,
1110 .{ .parent_atom_index = decl.link.wasm.sym_index },
1124 .{ .parent_atom_index = atom.sym_index },
11111125 );
11121126
11131127 const code = switch (res) {
......@@ -1119,26 +1133,29 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
11191133 },
11201134 };
11211135
1122 return wasm.finishUpdateDecl(decl, code);
1136 return wasm.finishUpdateDecl(decl_index, code);
11231137}
11241138
1125pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl: *const Module.Decl) !void {
1139pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !void {
11261140 if (wasm.llvm_object) |_| return;
11271141 if (wasm.dwarf) |*dw| {
11281142 const tracy = trace(@src());
11291143 defer tracy.end();
11301144
1145 const decl = mod.declPtr(decl_index);
11311146 const decl_name = try decl.getFullyQualifiedName(mod);
11321147 defer wasm.base.allocator.free(decl_name);
11331148
11341149 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
1135 try dw.updateDeclLineNumber(decl);
1150 try dw.updateDeclLineNumber(mod, decl_index);
11361151 }
11371152}
11381153
1139fn finishUpdateDecl(wasm: *Wasm, decl: *Module.Decl, code: []const u8) !void {
1154fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8) !void {
11401155 const mod = wasm.base.options.module.?;
1141 const atom: *Atom = &decl.link.wasm;
1156 const decl = mod.declPtr(decl_index);
1157 const atom_index = wasm.decls.get(decl_index).?;
1158 const atom = wasm.getAtomPtr(atom_index);
11421159 const symbol = &wasm.symbols.items[atom.sym_index];
11431160 const full_name = try decl.getFullyQualifiedName(mod);
11441161 defer wasm.base.allocator.free(full_name);
......@@ -1204,48 +1221,51 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
12041221 const decl = mod.declPtr(decl_index);
12051222
12061223 // Create and initialize a new local symbol and atom
1207 const local_index = decl.link.wasm.locals.items.len;
1224 const atom_index = try wasm.createAtom();
1225 const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1226 const parent_atom = wasm.getAtomPtr(parent_atom_index);
1227 const local_index = parent_atom.locals.items.len;
1228 try parent_atom.locals.append(wasm.base.allocator, atom_index);
12081229 const fqdn = try decl.getFullyQualifiedName(mod);
12091230 defer wasm.base.allocator.free(fqdn);
12101231 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index });
12111232 defer wasm.base.allocator.free(name);
1212
1213 const atom = try decl.link.wasm.locals.addOne(wasm.base.allocator);
1214 atom.* = Atom.empty;
1215 try atom.ensureInitialized(wasm);
1216 atom.alignment = tv.ty.abiAlignment(wasm.base.options.target);
1217 wasm.symbols.items[atom.sym_index] = .{
1218 .name = try wasm.string_table.put(wasm.base.allocator, name),
1219 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1220 .tag = .data,
1221 .index = undefined,
1222 };
1223
1224 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});
1225
12261233 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
12271234 defer value_bytes.deinit();
12281235
1229 const result = try codegen.generateSymbol(
1230 &wasm.base,
1231 decl.srcLoc(),
1232 tv,
1233 &value_bytes,
1234 .none,
1235 .{
1236 .parent_atom_index = atom.sym_index,
1237 .addend = null,
1238 },
1239 );
1240 const code = switch (result) {
1241 .ok => value_bytes.items,
1242 .fail => |em| {
1243 decl.analysis = .codegen_failure;
1244 try mod.failed_decls.put(mod.gpa, decl_index, em);
1245 return error.AnalysisFail;
1246 },
1236 const code = code: {
1237 const atom = wasm.getAtomPtr(atom_index);
1238 atom.alignment = tv.ty.abiAlignment(wasm.base.options.target);
1239 wasm.symbols.items[atom.sym_index] = .{
1240 .name = try wasm.string_table.put(wasm.base.allocator, name),
1241 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1242 .tag = .data,
1243 .index = undefined,
1244 };
1245 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});
1246
1247 const result = try codegen.generateSymbol(
1248 &wasm.base,
1249 decl.srcLoc(),
1250 tv,
1251 &value_bytes,
1252 .none,
1253 .{
1254 .parent_atom_index = atom.sym_index,
1255 .addend = null,
1256 },
1257 );
1258 break :code switch (result) {
1259 .ok => value_bytes.items,
1260 .fail => |em| {
1261 decl.analysis = .codegen_failure;
1262 try mod.failed_decls.put(mod.gpa, decl_index, em);
1263 return error.AnalysisFail;
1264 },
1265 };
12471266 };
12481267
1268 const atom = wasm.getAtomPtr(atom_index);
12491269 atom.size = @intCast(u32, code.len);
12501270 try atom.code.appendSlice(wasm.base.allocator, code);
12511271 return atom.sym_index;
......@@ -1293,10 +1313,13 @@ pub fn getDeclVAddr(
12931313) !u64 {
12941314 const mod = wasm.base.options.module.?;
12951315 const decl = mod.declPtr(decl_index);
1296 try decl.link.wasm.ensureInitialized(wasm);
1297 const target_symbol_index = decl.link.wasm.sym_index;
1316
1317 const target_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1318 const target_symbol_index = wasm.getAtom(target_atom_index).sym_index;
1319
12981320 assert(reloc_info.parent_atom_index != 0);
1299 const atom = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
1321 const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
1322 const atom = wasm.getAtomPtr(atom_index);
13001323 const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;
13011324 if (decl.ty.zigTypeTag() == .Fn) {
13021325 assert(reloc_info.addend == 0); // addend not allowed for function relocations
......@@ -1324,9 +1347,10 @@ pub fn getDeclVAddr(
13241347 return target_symbol_index;
13251348}
13261349
1327pub fn deleteExport(wasm: *Wasm, exp: Export) void {
1350pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {
13281351 if (wasm.llvm_object) |_| return;
1329 const sym_index = exp.sym_index orelse return;
1352 const atom_index = wasm.decls.get(decl_index) orelse return;
1353 const sym_index = wasm.getAtom(atom_index).sym_index;
13301354 const loc: SymbolLoc = .{ .file = null, .index = sym_index };
13311355 const symbol = loc.getSymbol(wasm);
13321356 const symbol_name = wasm.string_table.get(symbol.name);
......@@ -1352,7 +1376,8 @@ pub fn updateDeclExports(
13521376 }
13531377
13541378 const decl = mod.declPtr(decl_index);
1355 if (decl.link.wasm.getSymbolIndex() == null) return; // unititialized
1379 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1380 const atom = wasm.getAtom(atom_index);
13561381
13571382 for (exports) |exp| {
13581383 if (exp.options.section) |section| {
......@@ -1367,7 +1392,7 @@ pub fn updateDeclExports(
13671392
13681393 const export_name = try wasm.string_table.put(wasm.base.allocator, exp.options.name);
13691394 if (wasm.globals.getPtr(export_name)) |existing_loc| {
1370 if (existing_loc.index == decl.link.wasm.sym_index) continue;
1395 if (existing_loc.index == atom.sym_index) continue;
13711396 const existing_sym: Symbol = existing_loc.getSymbol(wasm).*;
13721397
13731398 const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak;
......@@ -1388,15 +1413,16 @@ pub fn updateDeclExports(
13881413 } else if (exp_is_weak) {
13891414 continue; // to-be-exported symbol is weak, so we keep the existing symbol
13901415 } else {
1391 existing_loc.index = decl.link.wasm.sym_index;
1416 // TODO: Revisit this, why was this needed?
1417 existing_loc.index = atom.sym_index;
13921418 existing_loc.file = null;
1393 exp.link.wasm.sym_index = existing_loc.index;
1419 // exp.link.wasm.sym_index = existing_loc.index;
13941420 }
13951421 }
13961422
1397 const exported_decl = mod.declPtr(exp.exported_decl);
1398 const sym_index = exported_decl.link.wasm.sym_index;
1399 const sym_loc = exported_decl.link.wasm.symbolLoc();
1423 const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl);
1424 const exported_atom = wasm.getAtom(exported_atom_index);
1425 const sym_loc = exported_atom.symbolLoc();
14001426 const symbol = sym_loc.getSymbol(wasm);
14011427 switch (exp.options.linkage) {
14021428 .Internal => {
......@@ -1432,7 +1458,6 @@ pub fn updateDeclExports(
14321458 // if the symbol was previously undefined, remove it as an import
14331459 _ = wasm.imports.remove(sym_loc);
14341460 _ = wasm.undefs.swapRemove(exp.options.name);
1435 exp.link.wasm.sym_index = sym_index;
14361461 }
14371462}
14381463
......@@ -1442,11 +1467,13 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
14421467 }
14431468 const mod = wasm.base.options.module.?;
14441469 const decl = mod.declPtr(decl_index);
1445 const atom = &decl.link.wasm;
1470 const atom_index = wasm.decls.get(decl_index).?;
1471 const atom = wasm.getAtomPtr(atom_index);
14461472 wasm.symbols_free_list.append(wasm.base.allocator, atom.sym_index) catch {};
14471473 _ = wasm.decls.remove(decl_index);
14481474 wasm.symbols.items[atom.sym_index].tag = .dead;
1449 for (atom.locals.items) |local_atom| {
1475 for (atom.locals.items) |local_atom_index| {
1476 const local_atom = wasm.getAtom(local_atom_index);
14501477 const local_symbol = &wasm.symbols.items[local_atom.sym_index];
14511478 local_symbol.tag = .dead; // also for any local symbol
14521479 wasm.symbols_free_list.append(wasm.base.allocator, local_atom.sym_index) catch {};
......@@ -1460,12 +1487,20 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
14601487 _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc());
14611488 _ = wasm.symbol_atom.remove(atom.symbolLoc());
14621489
1463 if (wasm.dwarf) |*dwarf| {
1464 dwarf.freeDecl(decl);
1465 dwarf.freeAtom(&atom.dbg_info_atom);
1466 }
1490 // if (wasm.dwarf) |*dwarf| {
1491 // dwarf.freeDecl(decl_index);
1492 // }
14671493
1468 atom.deinit(wasm.base.allocator);
1494 if (atom.next) |next_atom_index| {
1495 const next_atom = wasm.getAtomPtr(next_atom_index);
1496 next_atom.prev = atom.prev;
1497 atom.next = null;
1498 }
1499 if (atom.prev) |prev_index| {
1500 const prev_atom = wasm.getAtomPtr(prev_index);
1501 prev_atom.next = atom.next;
1502 atom.prev = null;
1503 }
14691504}
14701505
14711506/// Appends a new entry to the indirect function table
......@@ -1587,7 +1622,8 @@ const Kind = union(enum) {
15871622};
15881623
15891624/// Parses an Atom and inserts its metadata into the corresponding sections.
1590fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void {
1625fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
1626 const atom = wasm.getAtomPtr(atom_index);
15911627 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
15921628 const final_index: u32 = switch (kind) {
15931629 .function => |fn_data| result: {
......@@ -1662,18 +1698,20 @@ fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void {
16621698 const segment: *Segment = &wasm.segments.items[final_index];
16631699 segment.alignment = std.math.max(segment.alignment, atom.alignment);
16641700
1665 try wasm.appendAtomAtIndex(final_index, atom);
1701 try wasm.appendAtomAtIndex(final_index, atom_index);
16661702}
16671703
16681704/// From a given index, append the given `Atom` at the back of the linked list.
16691705/// Simply inserts it into the map of atoms when it doesn't exist yet.
1670pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom: *Atom) !void {
1671 if (wasm.atoms.getPtr(index)) |last| {
1672 last.*.next = atom;
1673 atom.prev = last.*;
1674 last.* = atom;
1706pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {
1707 const atom = wasm.getAtomPtr(atom_index);
1708 if (wasm.atoms.getPtr(index)) |last_index_ptr| {
1709 const last = wasm.getAtomPtr(last_index_ptr.*);
1710 last.*.next = atom_index;
1711 atom.prev = last_index_ptr.*;
1712 last_index_ptr.* = atom_index;
16751713 } else {
1676 try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom);
1714 try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom_index);
16771715 }
16781716}
16791717
......@@ -1683,16 +1721,17 @@ fn allocateDebugAtoms(wasm: *Wasm) !void {
16831721 if (wasm.dwarf == null) return;
16841722
16851723 const allocAtom = struct {
1686 fn f(bin: *Wasm, maybe_index: *?u32, atom: *Atom) !void {
1724 fn f(bin: *Wasm, maybe_index: *?u32, atom_index: Atom.Index) !void {
16871725 const index = maybe_index.* orelse idx: {
16881726 const index = @intCast(u32, bin.segments.items.len);
16891727 try bin.appendDummySegment();
16901728 maybe_index.* = index;
16911729 break :idx index;
16921730 };
1731 const atom = bin.getAtomPtr(atom_index);
16931732 atom.size = @intCast(u32, atom.code.items.len);
16941733 bin.symbols.items[atom.sym_index].index = index;
1695 try bin.appendAtomAtIndex(index, atom);
1734 try bin.appendAtomAtIndex(index, atom_index);
16961735 }
16971736 }.f;
16981737
......@@ -1714,15 +1753,16 @@ fn allocateAtoms(wasm: *Wasm) !void {
17141753 var it = wasm.atoms.iterator();
17151754 while (it.next()) |entry| {
17161755 const segment = &wasm.segments.items[entry.key_ptr.*];
1717 var atom: *Atom = entry.value_ptr.*.getFirst();
1756 var atom_index = entry.value_ptr.*;
17181757 var offset: u32 = 0;
17191758 while (true) {
1759 const atom = wasm.getAtomPtr(atom_index);
17201760 const symbol_loc = atom.symbolLoc();
17211761 if (wasm.code_section_index) |index| {
17221762 if (index == entry.key_ptr.*) {
17231763 if (!wasm.resolved_symbols.contains(symbol_loc)) {
17241764 // only allocate resolved function body's.
1725 atom = atom.next orelse break;
1765 atom_index = atom.prev orelse break;
17261766 continue;
17271767 }
17281768 }
......@@ -1736,8 +1776,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
17361776 atom.size,
17371777 });
17381778 offset += atom.size;
1739 try wasm.symbol_atom.put(wasm.base.allocator, symbol_loc, atom); // Update atom pointers
1740 atom = atom.next orelse break;
1779 atom_index = atom.prev orelse break;
17411780 }
17421781 segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);
17431782 }
......@@ -1871,8 +1910,8 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
18711910 symbol.index = func_index;
18721911
18731912 // create the atom that will be output into the final binary
1874 const atom = try wasm.base.allocator.create(Atom);
1875 errdefer wasm.base.allocator.destroy(atom);
1913 const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
1914 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
18761915 atom.* = .{
18771916 .size = @intCast(u32, function_body.items.len),
18781917 .offset = 0,
......@@ -1882,15 +1921,14 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
18821921 .next = null,
18831922 .prev = null,
18841923 .code = function_body.moveToUnmanaged(),
1885 .dbg_info_atom = undefined,
18861924 };
1887 try wasm.managed_atoms.append(wasm.base.allocator, atom);
1888 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom);
1889 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
1925 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);
1926 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
18901927
18911928 // `allocateAtoms` has already been called, set the atom's offset manually.
18921929 // This is fine to do manually as we insert the atom at the very end.
1893 atom.offset = atom.prev.?.offset + atom.prev.?.size;
1930 const prev_atom = wasm.getAtom(atom.prev.?);
1931 atom.offset = prev_atom.offset + prev_atom.size;
18941932}
18951933
18961934fn setupImports(wasm: *Wasm) !void {
......@@ -2093,7 +2131,8 @@ fn setupExports(wasm: *Wasm) !void {
20932131 break :blk try wasm.string_table.put(wasm.base.allocator, sym_name);
20942132 };
20952133 const exp: types.Export = if (symbol.tag == .data) exp: {
2096 const atom = wasm.symbol_atom.get(sym_loc).?;
2134 const atom_index = wasm.symbol_atom.get(sym_loc).?;
2135 const atom = wasm.getAtom(atom_index);
20972136 const va = atom.getVA(wasm, symbol);
20982137 const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len);
20992138 try wasm.wasm_globals.append(wasm.base.allocator, .{
......@@ -2198,7 +2237,8 @@ fn setupMemory(wasm: *Wasm) !void {
21982237 const segment_index = wasm.data_segments.get(".synthetic").?;
21992238 const segment = &wasm.segments.items[segment_index];
22002239 segment.offset = 0; // for simplicity we store the entire VA into atom's offset.
2201 const atom = wasm.symbol_atom.get(loc).?;
2240 const atom_index = wasm.symbol_atom.get(loc).?;
2241 const atom = wasm.getAtomPtr(atom_index);
22022242 atom.offset = @intCast(u32, mem.alignForwardGeneric(u64, memory_ptr, heap_alignment));
22032243 }
22042244
......@@ -2231,7 +2271,8 @@ fn setupMemory(wasm: *Wasm) !void {
22312271 const segment_index = wasm.data_segments.get(".synthetic").?;
22322272 const segment = &wasm.segments.items[segment_index];
22332273 segment.offset = 0;
2234 const atom = wasm.symbol_atom.get(loc).?;
2274 const atom_index = wasm.symbol_atom.get(loc).?;
2275 const atom = wasm.getAtomPtr(atom_index);
22352276 atom.offset = @intCast(u32, memory_ptr);
22362277 }
22372278
......@@ -2357,15 +2398,14 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
23572398 // and then return said symbol's index. The final table will be populated
23582399 // during `flush` when we know all possible error names.
23592400
2360 // As sym_index '0' is reserved, we use it for our stack pointer symbol
2361 const symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: {
2362 const index = @intCast(u32, wasm.symbols.items.len);
2363 _ = try wasm.symbols.addOne(wasm.base.allocator);
2364 break :blk index;
2365 };
2401 const atom_index = try wasm.createAtom();
2402 const atom = wasm.getAtomPtr(atom_index);
2403 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
2404 atom.alignment = slice_ty.abiAlignment(wasm.base.options.target);
2405 const sym_index = atom.sym_index;
23662406
23672407 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table");
2368 const symbol = &wasm.symbols.items[symbol_index];
2408 const symbol = &wasm.symbols.items[sym_index];
23692409 symbol.* = .{
23702410 .name = sym_name,
23712411 .tag = .data,
......@@ -2374,20 +2414,11 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
23742414 };
23752415 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
23762416
2377 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
2417 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});
23782418
2379 const atom = try wasm.base.allocator.create(Atom);
2380 atom.* = Atom.empty;
2381 atom.sym_index = symbol_index;
2382 atom.alignment = slice_ty.abiAlignment(wasm.base.options.target);
2383 try wasm.managed_atoms.append(wasm.base.allocator, atom);
2384 const loc = atom.symbolLoc();
2385 try wasm.resolved_symbols.put(wasm.base.allocator, loc, {});
2386 try wasm.symbol_atom.put(wasm.base.allocator, loc, atom);
2387
2388 log.debug("Error name table was created with symbol index: ({d})", .{symbol_index});
2389 wasm.error_table_symbol = symbol_index;
2390 return symbol_index;
2419 log.debug("Error name table was created with symbol index: ({d})", .{sym_index});
2420 wasm.error_table_symbol = sym_index;
2421 return sym_index;
23912422}
23922423
23932424/// Populates the error name table, when `error_table_symbol` is not null.
......@@ -2396,22 +2427,17 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
23962427/// The table is what is being pointed to within the runtime bodies that are generated.
23972428fn populateErrorNameTable(wasm: *Wasm) !void {
23982429 const symbol_index = wasm.error_table_symbol orelse return;
2399 const atom: *Atom = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;
2430 const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;
2431 const atom = wasm.getAtomPtr(atom_index);
2432
24002433 // Rather than creating a symbol for each individual error name,
24012434 // we create a symbol for the entire region of error names. We then calculate
24022435 // the pointers into the list using addends which are appended to the relocation.
2403 const names_atom = try wasm.base.allocator.create(Atom);
2404 names_atom.* = Atom.empty;
2405 try wasm.managed_atoms.append(wasm.base.allocator, names_atom);
2406 const names_symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: {
2407 const index = @intCast(u32, wasm.symbols.items.len);
2408 _ = try wasm.symbols.addOne(wasm.base.allocator);
2409 break :blk index;
2410 };
2411 names_atom.sym_index = names_symbol_index;
2436 const names_atom_index = try wasm.createAtom();
2437 const names_atom = wasm.getAtomPtr(names_atom_index);
24122438 names_atom.alignment = 1;
24132439 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names");
2414 const names_symbol = &wasm.symbols.items[names_symbol_index];
2440 const names_symbol = &wasm.symbols.items[names_atom.sym_index];
24152441 names_symbol.* = .{
24162442 .name = sym_name,
24172443 .tag = .data,
......@@ -2435,7 +2461,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
24352461 try atom.code.writer(wasm.base.allocator).writeIntLittle(u32, len - 1);
24362462 // create relocation to the error name
24372463 try atom.relocs.append(wasm.base.allocator, .{
2438 .index = names_symbol_index,
2464 .index = names_atom.sym_index,
24392465 .relocation_type = .R_WASM_MEMORY_ADDR_I32,
24402466 .offset = offset,
24412467 .addend = @intCast(i32, addend),
......@@ -2454,61 +2480,53 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
24542480
24552481 const name_loc = names_atom.symbolLoc();
24562482 try wasm.resolved_symbols.put(wasm.base.allocator, name_loc, {});
2457 try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom);
2483 try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom_index);
24582484
24592485 // link the atoms with the rest of the binary so they can be allocated
24602486 // and relocations will be performed.
2461 try wasm.parseAtom(atom, .{ .data = .read_only });
2462 try wasm.parseAtom(names_atom, .{ .data = .read_only });
2487 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2488 try wasm.parseAtom(names_atom_index, .{ .data = .read_only });
24632489}
24642490
24652491/// From a given index variable, creates a new debug section.
24662492/// This initializes the index, appends a new segment,
24672493/// and finally, creates a managed `Atom`.
2468pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !*Atom {
2494pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index {
24692495 const new_index = @intCast(u32, wasm.segments.items.len);
24702496 index.* = new_index;
24712497 try wasm.appendDummySegment();
24722498
2473 const sym_index = wasm.symbols_free_list.popOrNull() orelse idx: {
2474 const tmp_index = @intCast(u32, wasm.symbols.items.len);
2475 _ = try wasm.symbols.addOne(wasm.base.allocator);
2476 break :idx tmp_index;
2477 };
2478 wasm.symbols.items[sym_index] = .{
2499 const atom_index = try wasm.createAtom();
2500 const atom = wasm.getAtomPtr(atom_index);
2501 wasm.symbols.items[atom.sym_index] = .{
24792502 .tag = .section,
24802503 .name = try wasm.string_table.put(wasm.base.allocator, name),
24812504 .index = 0,
24822505 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
24832506 };
24842507
2485 const atom = try wasm.base.allocator.create(Atom);
2486 atom.* = Atom.empty;
24872508 atom.alignment = 1; // debug sections are always 1-byte-aligned
2488 atom.sym_index = sym_index;
2489 try wasm.managed_atoms.append(wasm.base.allocator, atom);
2490 try wasm.symbol_atom.put(wasm.base.allocator, atom.symbolLoc(), atom);
2491 return atom;
2509 return atom_index;
24922510}
24932511
24942512fn resetState(wasm: *Wasm) void {
24952513 for (wasm.segment_info.values()) |segment_info| {
24962514 wasm.base.allocator.free(segment_info.name);
24972515 }
2498 if (wasm.base.options.module) |mod| {
2499 var decl_it = wasm.decls.keyIterator();
2500 while (decl_it.next()) |decl_index_ptr| {
2501 const decl = mod.declPtr(decl_index_ptr.*);
2502 const atom = &decl.link.wasm;
2503 atom.next = null;
2504 atom.prev = null;
2505
2506 for (atom.locals.items) |*local_atom| {
2507 local_atom.next = null;
2508 local_atom.prev = null;
2509 }
2516
2517 var atom_it = wasm.decls.valueIterator();
2518 while (atom_it.next()) |atom_index| {
2519 const atom = wasm.getAtomPtr(atom_index.*);
2520 atom.next = null;
2521 atom.prev = null;
2522
2523 for (atom.locals.items) |local_atom_index| {
2524 const local_atom = wasm.getAtomPtr(local_atom_index);
2525 local_atom.next = null;
2526 local_atom.prev = null;
25102527 }
25112528 }
2529
25122530 wasm.functions.clearRetainingCapacity();
25132531 wasm.exports.clearRetainingCapacity();
25142532 wasm.segments.clearRetainingCapacity();
......@@ -2805,28 +2823,29 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
28052823 try wasm.setupStart();
28062824 try wasm.setupImports();
28072825 if (wasm.base.options.module) |mod| {
2808 var decl_it = wasm.decls.keyIterator();
2809 while (decl_it.next()) |decl_index_ptr| {
2810 const decl = mod.declPtr(decl_index_ptr.*);
2826 var decl_it = wasm.decls.iterator();
2827 while (decl_it.next()) |entry| {
2828 const decl = mod.declPtr(entry.key_ptr.*);
28112829 if (decl.isExtern()) continue;
2812 const atom = &decl.*.link.wasm;
2830 const atom_index = entry.value_ptr.*;
28132831 if (decl.ty.zigTypeTag() == .Fn) {
2814 try wasm.parseAtom(atom, .{ .function = decl.fn_link.wasm });
2832 try wasm.parseAtom(atom_index, .{ .function = decl.fn_link.? });
28152833 } else if (decl.getVariable()) |variable| {
28162834 if (!variable.is_mutable) {
2817 try wasm.parseAtom(atom, .{ .data = .read_only });
2835 try wasm.parseAtom(atom_index, .{ .data = .read_only });
28182836 } else if (variable.init.isUndefDeep()) {
2819 try wasm.parseAtom(atom, .{ .data = .uninitialized });
2837 try wasm.parseAtom(atom_index, .{ .data = .uninitialized });
28202838 } else {
2821 try wasm.parseAtom(atom, .{ .data = .initialized });
2839 try wasm.parseAtom(atom_index, .{ .data = .initialized });
28222840 }
28232841 } else {
2824 try wasm.parseAtom(atom, .{ .data = .read_only });
2842 try wasm.parseAtom(atom_index, .{ .data = .read_only });
28252843 }
28262844
28272845 // also parse atoms for a decl's locals
2828 for (atom.locals.items) |*local_atom| {
2829 try wasm.parseAtom(local_atom, .{ .data = .read_only });
2846 const atom = wasm.getAtomPtr(atom_index);
2847 for (atom.locals.items) |local_atom_index| {
2848 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
28302849 }
28312850 }
28322851
......@@ -3071,20 +3090,22 @@ fn writeToFile(
30713090 var code_section_size: u32 = 0;
30723091 if (wasm.code_section_index) |code_index| {
30733092 const header_offset = try reserveVecSectionHeader(&binary_bytes);
3074 var atom: *Atom = wasm.atoms.get(code_index).?.getFirst();
3093 var atom_index = wasm.atoms.get(code_index).?;
30753094
30763095 // The code section must be sorted in line with the function order.
30773096 var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count());
30783097 defer sorted_atoms.deinit();
30793098
30803099 while (true) {
3100 var atom = wasm.getAtomPtr(atom_index);
30813101 if (wasm.resolved_symbols.contains(atom.symbolLoc())) {
30823102 if (!is_obj) {
30833103 atom.resolveRelocs(wasm);
30843104 }
30853105 sorted_atoms.appendAssumeCapacity(atom);
30863106 }
3087 atom = atom.next orelse break;
3107 // atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
3108 atom_index = atom.prev orelse break;
30883109 }
30893110
30903111 const atom_sort_fn = struct {
......@@ -3124,11 +3145,11 @@ fn writeToFile(
31243145 // do not output 'bss' section unless we import memory and therefore
31253146 // want to guarantee the data is zero initialized
31263147 if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;
3127 const atom_index = entry.value_ptr.*;
3128 const segment = wasm.segments.items[atom_index];
3148 const segment_index = entry.value_ptr.*;
3149 const segment = wasm.segments.items[segment_index];
31293150 if (segment.size == 0) continue; // do not emit empty segments
31303151 segment_count += 1;
3131 var atom: *Atom = wasm.atoms.getPtr(atom_index).?.*.getFirst();
3152 var atom_index = wasm.atoms.get(segment_index).?;
31323153
31333154 // flag and index to memory section (currently, there can only be 1 memory section in wasm)
31343155 try leb.writeULEB128(binary_writer, @as(u32, 0));
......@@ -3139,6 +3160,7 @@ fn writeToFile(
31393160 // fill in the offset table and the data segments
31403161 var current_offset: u32 = 0;
31413162 while (true) {
3163 const atom = wasm.getAtomPtr(atom_index);
31423164 if (!is_obj) {
31433165 atom.resolveRelocs(wasm);
31443166 }
......@@ -3154,8 +3176,8 @@ fn writeToFile(
31543176 try binary_writer.writeAll(atom.code.items);
31553177
31563178 current_offset += atom.size;
3157 if (atom.next) |next| {
3158 atom = next;
3179 if (atom.prev) |prev| {
3180 atom_index = prev;
31593181 } else {
31603182 // also pad with zeroes when last atom to ensure
31613183 // segments are aligned.
......@@ -3197,15 +3219,15 @@ fn writeToFile(
31973219 }
31983220
31993221 if (!wasm.base.options.strip) {
3200 if (wasm.dwarf) |*dwarf| {
3201 const mod = wasm.base.options.module.?;
3202 try dwarf.writeDbgAbbrev();
3203 // for debug info and ranges, the address is always 0,
3204 // as locations are always offsets relative to 'code' section.
3205 try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);
3206 try dwarf.writeDbgAranges(0, code_section_size);
3207 try dwarf.writeDbgLineHeader();
3208 }
3222 // if (wasm.dwarf) |*dwarf| {
3223 // const mod = wasm.base.options.module.?;
3224 // try dwarf.writeDbgAbbrev();
3225 // // for debug info and ranges, the address is always 0,
3226 // // as locations are always offsets relative to 'code' section.
3227 // try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);
3228 // try dwarf.writeDbgAranges(0, code_section_size);
3229 // try dwarf.writeDbgLineHeader();
3230 // }
32093231
32103232 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);
32113233 defer debug_bytes.deinit();
......@@ -3228,11 +3250,11 @@ fn writeToFile(
32283250
32293251 for (debug_sections) |item| {
32303252 if (item.index) |index| {
3231 var atom = wasm.atoms.get(index).?.getFirst();
3253 var atom = wasm.getAtomPtr(wasm.atoms.get(index).?);
32323254 while (true) {
32333255 atom.resolveRelocs(wasm);
32343256 try debug_bytes.appendSlice(atom.code.items);
3235 atom = atom.next orelse break;
3257 atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
32363258 }
32373259 try emitDebugSection(&binary_bytes, debug_bytes.items, item.name);
32383260 debug_bytes.clearRetainingCapacity();
......@@ -3964,7 +3986,8 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
39643986
39653987 if (symbol.isDefined()) {
39663988 try leb.writeULEB128(writer, symbol.index);
3967 const atom = wasm.symbol_atom.get(sym_loc).?;
3989 const atom_index = wasm.symbol_atom.get(sym_loc).?;
3990 const atom = wasm.getAtom(atom_index);
39683991 try leb.writeULEB128(writer, @as(u32, atom.offset));
39693992 try leb.writeULEB128(writer, @as(u32, atom.size));
39703993 }
......@@ -4042,7 +4065,7 @@ fn emitCodeRelocations(
40424065 const reloc_start = binary_bytes.items.len;
40434066
40444067 var count: u32 = 0;
4045 var atom: *Atom = wasm.atoms.get(code_index).?.getFirst();
4068 var atom: *Atom = wasm.getAtomPtr(wasm.atoms.get(code_index).?);
40464069 // for each atom, we calculate the uleb size and append that
40474070 var size_offset: u32 = 5; // account for code section size leb128
40484071 while (true) {
......@@ -4060,7 +4083,7 @@ fn emitCodeRelocations(
40604083 }
40614084 log.debug("Emit relocation: {}", .{relocation});
40624085 }
4063 atom = atom.next orelse break;
4086 atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
40644087 }
40654088 if (count == 0) return;
40664089 var buf: [5]u8 = undefined;
......@@ -4091,7 +4114,7 @@ fn emitDataRelocations(
40914114 // for each atom, we calculate the uleb size and append that
40924115 var size_offset: u32 = 5; // account for code section size leb128
40934116 for (wasm.data_segments.values()) |segment_index| {
4094 var atom: *Atom = wasm.atoms.get(segment_index).?.getFirst();
4117 var atom: *Atom = wasm.getAtomPtr(wasm.atoms.get(segment_index).?);
40954118 while (true) {
40964119 size_offset += getULEB128Size(atom.size);
40974120 for (atom.relocs.items) |relocation| {
......@@ -4110,7 +4133,7 @@ fn emitDataRelocations(
41104133 }
41114134 log.debug("Emit relocation: {}", .{relocation});
41124135 }
4113 atom = atom.next orelse break;
4136 atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
41144137 }
41154138 }
41164139 if (count == 0) return;
src/link/Wasm/Atom.zig+19-28
......@@ -4,7 +4,6 @@ const std = @import("std");
44const types = @import("types.zig");
55const Wasm = @import("../Wasm.zig");
66const Symbol = @import("Symbol.zig");
7const Dwarf = @import("../Dwarf.zig");
87
98const leb = std.leb;
109const log = std.log.scoped(.link);
......@@ -30,17 +29,17 @@ file: ?u16,
3029
3130/// Next atom in relation to this atom.
3231/// When null, this atom is the last atom
33next: ?*Atom,
32next: ?Atom.Index,
3433/// Previous atom in relation to this atom.
3534/// is null when this atom is the first in its order
36prev: ?*Atom,
35prev: ?Atom.Index,
3736
3837/// Contains atoms local to a decl, all managed by this `Atom`.
3938/// When the parent atom is being freed, it will also do so for all local atoms.
40locals: std.ArrayListUnmanaged(Atom) = .{},
39locals: std.ArrayListUnmanaged(Atom.Index) = .{},
4140
42/// Represents the debug Atom that holds all debug information of this Atom.
43dbg_info_atom: Dwarf.Atom,
41/// Alias to an unsigned 32-bit integer
42pub const Index = u32;
4443
4544/// Represents a default empty wasm `Atom`
4645pub const empty: Atom = .{
......@@ -51,18 +50,15 @@ pub const empty: Atom = .{
5150 .prev = null,
5251 .size = 0,
5352 .sym_index = 0,
54 .dbg_info_atom = undefined,
5553};
5654
5755/// Frees all resources owned by this `Atom`.
58pub fn deinit(atom: *Atom, gpa: Allocator) void {
56pub fn deinit(atom: *Atom, wasm: *Wasm) void {
57 const gpa = wasm.base.allocator;
5958 atom.relocs.deinit(gpa);
6059 atom.code.deinit(gpa);
61
62 for (atom.locals.items) |*local| {
63 local.deinit(gpa);
64 }
6560 atom.locals.deinit(gpa);
61 atom.* = undefined;
6662}
6763
6864/// Sets the length of relocations and code to '0',
......@@ -83,24 +79,11 @@ pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptio
8379 });
8480}
8581
86/// Returns the first `Atom` from a given atom
87pub fn getFirst(atom: *Atom) *Atom {
88 var tmp = atom;
89 while (tmp.prev) |prev| tmp = prev;
90 return tmp;
91}
92
9382/// Returns the location of the symbol that represents this `Atom`
9483pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
9584 return .{ .file = atom.file, .index = atom.sym_index };
9685}
9786
98pub fn ensureInitialized(atom: *Atom, wasm_bin: *Wasm) !void {
99 if (atom.getSymbolIndex() != null) return; // already initialized
100 atom.sym_index = try wasm_bin.allocateSymbol();
101 try wasm_bin.symbol_atom.putNoClobber(wasm_bin.base.allocator, atom.symbolLoc(), atom);
102}
103
10487pub fn getSymbolIndex(atom: Atom) ?u32 {
10588 if (atom.sym_index == 0) return null;
10689 return atom.sym_index;
......@@ -203,20 +186,28 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
203186 if (symbol.isUndefined()) {
204187 return 0;
205188 }
206 const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
189 const target_atom_index = wasm_bin.symbol_atom.get(target_loc) orelse {
190 // this can only occur during incremental-compilation when a relocation
191 // still points to a freed decl. It is fine to emit the value 0 here
192 // as no actual code will point towards it.
193 return 0;
194 };
195 const target_atom = wasm_bin.getAtom(target_atom_index);
207196 const va = @intCast(i32, target_atom.getVA(wasm_bin, symbol));
208197 return @intCast(u32, va + relocation.addend);
209198 },
210199 .R_WASM_EVENT_INDEX_LEB => return symbol.index,
211200 .R_WASM_SECTION_OFFSET_I32 => {
212 const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
201 const target_atom_index = wasm_bin.symbol_atom.get(target_loc).?;
202 const target_atom = wasm_bin.getAtom(target_atom_index);
213203 const rel_value = @intCast(i32, target_atom.offset) + relocation.addend;
214204 return @intCast(u32, rel_value);
215205 },
216206 .R_WASM_FUNCTION_OFFSET_I32 => {
217 const target_atom = wasm_bin.symbol_atom.get(target_loc) orelse {
207 const target_atom_index = wasm_bin.symbol_atom.get(target_loc) orelse {
218208 return @bitCast(u32, @as(i32, -1));
219209 };
210 const target_atom = wasm_bin.getAtom(target_atom_index);
220211 const offset: u32 = 11 + Wasm.getULEB128Size(target_atom.size); // Header (11 bytes fixed-size) + body size (leb-encoded)
221212 const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend;
222213 return @intCast(u32, rel_value);
src/link/Wasm/Object.zig+5-10
......@@ -901,14 +901,9 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
901901 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
902902 };
903903
904 const atom = try gpa.create(Atom);
904 const atom_index = @intCast(Atom.Index, wasm_bin.managed_atoms.items.len);
905 const atom = try wasm_bin.managed_atoms.addOne(gpa);
905906 atom.* = Atom.empty;
906 errdefer {
907 atom.deinit(gpa);
908 gpa.destroy(atom);
909 }
910
911 try wasm_bin.managed_atoms.append(gpa, atom);
912907 atom.file = object_index;
913908 atom.size = relocatable_data.size;
914909 atom.alignment = relocatable_data.getAlignment(object);
......@@ -938,12 +933,12 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
938933 .index = relocatable_data.getIndex(),
939934 })) |symbols| {
940935 atom.sym_index = symbols.pop();
941 try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
936 try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom_index);
942937
943938 // symbols referencing the same atom will be added as alias
944939 // or as 'parent' when they are global.
945940 while (symbols.popOrNull()) |idx| {
946 try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom);
941 try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom_index);
947942 const alias_symbol = object.symtable[idx];
948943 if (alias_symbol.isGlobal()) {
949944 atom.sym_index = idx;
......@@ -956,7 +951,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
956951 segment.alignment = std.math.max(segment.alignment, atom.alignment);
957952 }
958953
959 try wasm_bin.appendAtomAtIndex(final_index, atom);
954 try wasm_bin.appendAtomAtIndex(final_index, atom_index);
960955 log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index });
961956 }
962957}
test/link/wasm/export-data/build.zig+2-2
......@@ -25,8 +25,8 @@ pub fn build(b: *std.Build) void {
2525 check_lib.checkNext("type i32");
2626 check_lib.checkNext("mutable false");
2727 check_lib.checkNext("i32.const {bar_address}");
28 check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 0 } });
29 check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 4 } });
28 check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 4 } });
29 check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 0 } });
3030
3131 check_lib.checkStart("Section export");
3232 check_lib.checkNext("entries 3");