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 {...@@ -3299,7 +3299,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
3299 const gpa = comp.gpa;3299 const gpa = comp.gpa;
3300 const module = comp.bin_file.options.module.?;3300 const module = comp.bin_file.options.module.?;
3301 const decl = module.declPtr(decl_index);3301 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| {
3303 try module.failed_decls.ensureUnusedCapacity(gpa, 1);3303 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
3304 module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(3304 module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
3305 gpa,3305 gpa,
src/Module.zig+14-71
...@@ -328,8 +328,6 @@ pub const ErrorInt = u32;...@@ -328,8 +328,6 @@ pub const ErrorInt = u32;
328pub const Export = struct {328pub const Export = struct {
329 options: std.builtin.ExportOptions,329 options: std.builtin.ExportOptions,
330 src: LazySrcLoc,330 src: LazySrcLoc,
331 /// Represents the position of the export, if any, in the output file.
332 link: link.File.Export,
333 /// The Decl that performs the export. Note that this is *not* the Decl being exported.331 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
334 owner_decl: Decl.Index,332 owner_decl: Decl.Index,
335 /// The Decl containing the export statement. Inline function calls333 /// The Decl containing the export statement. Inline function calls
...@@ -533,16 +531,8 @@ pub const Decl = struct {...@@ -533,16 +531,8 @@ pub const Decl = struct {
533 /// What kind of a declaration is this.531 /// What kind of a declaration is this.
534 kind: Kind,532 kind: Kind,
535533
536 /// Represents the position of the code in the output file.534 /// TODO remove this once Wasm backend catches up
537 /// This is populated regardless of semantic analysis and code generation.535 fn_link: ?link.File.Wasm.FnData = null,
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,
546536
547 /// The shallow set of other decls whose typed_value could possibly change if this Decl's537 /// The shallow set of other decls whose typed_value could possibly change if this Decl's
548 /// typed_value is modified.538 /// typed_value is modified.
...@@ -4098,7 +4088,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -4098,7 +4088,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
40984088
4099 // The exports this Decl performs will be re-discovered, so we remove them here4089 // The exports this Decl performs will be re-discovered, so we remove them here
4100 // prior to re-analysis.4090 // prior to re-analysis.
4101 mod.deleteDeclExports(decl_index);4091 try mod.deleteDeclExports(decl_index);
41024092
4103 // Similarly, `@setAlignStack` invocations will be re-discovered.4093 // Similarly, `@setAlignStack` invocations will be re-discovered.
4104 if (decl.getFunction()) |func| {4094 if (decl.getFunction()) |func| {
...@@ -5183,20 +5173,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -5183,20 +5173,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
5183 decl.zir_decl_index = @intCast(u32, decl_sub_index);5173 decl.zir_decl_index = @intCast(u32, decl_sub_index);
5184 if (decl.getFunction()) |_| {5174 if (decl.getFunction()) |_| {
5185 switch (comp.bin_file.tag) {5175 switch (comp.bin_file.tag) {
5186 .coff => {5176 .coff, .elf, .macho, .plan9 => {
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 => {
5200 // TODO Look into detecting when this would be unnecessary by storing enough state5177 // TODO Look into detecting when this would be unnecessary by storing enough state
5201 // in `Decl` to notice that the line number did not change.5178 // in `Decl` to notice that the line number did not change.
5202 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });5179 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
...@@ -5265,33 +5242,15 @@ pub fn clearDecl(...@@ -5265,33 +5242,15 @@ pub fn clearDecl(
5265 assert(emit_h.decl_table.swapRemove(decl_index));5242 assert(emit_h.decl_table.swapRemove(decl_index));
5266 }5243 }
5267 _ = mod.compile_log_decls.swapRemove(decl_index);5244 _ = mod.compile_log_decls.swapRemove(decl_index);
5268 mod.deleteDeclExports(decl_index);5245 try mod.deleteDeclExports(decl_index);
52695246
5270 if (decl.has_tv) {5247 if (decl.has_tv) {
5271 if (decl.ty.isFnOrHasRuntimeBits()) {5248 if (decl.ty.isFnOrHasRuntimeBits()) {
5272 mod.comp.bin_file.freeDecl(decl_index);5249 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 };
5286 decl.fn_link = switch (mod.comp.bin_file.tag) {5251 decl.fn_link = switch (mod.comp.bin_file.tag) {
5287 .coff => .{ .coff = {} },5252 .wasm => link.File.Wasm.FnData.empty,
5288 .elf => .{ .elf = link.File.Dwarf.SrcFn.empty },5253 else => null,
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 = {} },
5295 };5254 };
5296 }5255 }
5297 if (decl.getInnerNamespace()) |namespace| {5256 if (decl.getInnerNamespace()) |namespace| {
...@@ -5358,7 +5317,7 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {...@@ -5358,7 +5317,7 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void {
53585317
5359/// Delete all the Export objects that are caused by this Decl. Re-analysis of5318/// Delete all the Export objects that are caused by this Decl. Re-analysis of
5360/// this Decl will cause them to be re-created (or not).5319/// 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 {
5362 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;5321 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
53635322
5364 for (export_owners.items) |exp| {5323 for (export_owners.items) |exp| {
...@@ -5381,16 +5340,16 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {...@@ -5381,16 +5340,16 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void {
5381 }5340 }
5382 }5341 }
5383 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {5342 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
5384 elf.deleteExport(exp.link.elf);5343 elf.deleteDeclExport(decl_index, exp.options.name);
5385 }5344 }
5386 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {5345 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);
5388 }5347 }
5389 if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {5348 if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {
5390 wasm.deleteExport(exp.link.wasm);5349 wasm.deleteDeclExport(decl_index);
5391 }5350 }
5392 if (mod.comp.bin_file.cast(link.File.Coff)) |coff| {5351 if (mod.comp.bin_file.cast(link.File.Coff)) |coff| {
5393 coff.deleteExport(exp.link.coff);5352 coff.deleteDeclExport(decl_index, exp.options.name);
5394 }5353 }
5395 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {5354 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
5396 failed_kv.value.destroy(mod.gpa);5355 failed_kv.value.destroy(mod.gpa);
...@@ -5693,25 +5652,9 @@ pub fn allocateNewDecl(...@@ -5693,25 +5652,9 @@ pub fn allocateNewDecl(
5693 .deletion_flag = false,5652 .deletion_flag = false,
5694 .zir_decl_index = 0,5653 .zir_decl_index = 0,
5695 .src_scope = src_scope,5654 .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 },
5706 .fn_link = switch (mod.comp.bin_file.tag) {5655 .fn_link = switch (mod.comp.bin_file.tag) {
5707 .coff => .{ .coff = {} },5656 .wasm => link.File.Wasm.FnData.empty,
5708 .elf => .{ .elf = link.File.Dwarf.SrcFn.empty },5657 else => null,
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 = {} },
5715 },5658 },
5716 .generation = 0,5659 .generation = 0,
5717 .is_pub = false,5660 .is_pub = false,
src/Sema.zig-10
...@@ -5564,16 +5564,6 @@ pub fn analyzeExport(...@@ -5564,16 +5564,6 @@ pub fn analyzeExport(
5564 .visibility = borrowed_options.visibility,5564 .visibility = borrowed_options.visibility,
5565 },5565 },
5566 .src = src,5566 .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 },
5577 .owner_decl = sema.owner_decl_index,5567 .owner_decl = sema.owner_decl_index,
5578 .src_decl = block.src_decl,5568 .src_decl = block.src_decl,
5579 .exported_decl = exported_decl_index,5569 .exported_decl = exported_decl_index,
src/arch/aarch64/CodeGen.zig+70-51
...@@ -203,13 +203,7 @@ const DbgInfoReloc = struct {...@@ -203,13 +203,7 @@ const DbgInfoReloc = struct {
203 else => unreachable, // not a possible argument203 else => unreachable, // not a possible argument
204204
205 };205 };
206 try dw.genArgDbgInfo(206 try dw.genArgDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, loc);
207 reloc.name,
208 reloc.ty,
209 function.bin_file.tag,
210 function.mod_fn.owner_decl,
211 loc,
212 );
213 },207 },
214 .plan9 => {},208 .plan9 => {},
215 .none => {},209 .none => {},
...@@ -255,14 +249,7 @@ const DbgInfoReloc = struct {...@@ -255,14 +249,7 @@ const DbgInfoReloc = struct {
255 break :blk .nop;249 break :blk .nop;
256 },250 },
257 };251 };
258 try dw.genVarDbgInfo(252 try dw.genVarDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, is_ptr, loc);
259 reloc.name,
260 reloc.ty,
261 function.bin_file.tag,
262 function.mod_fn.owner_decl,
263 is_ptr,
264 loc,
265 );
266 },253 },
267 .plan9 => {},254 .plan9 => {},
268 .none => {},255 .none => {},
...@@ -4019,11 +4006,17 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -4019,11 +4006,17 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
4019 .direct => .load_memory_ptr_direct,4006 .direct => .load_memory_ptr_direct,
4020 .import => unreachable,4007 .import => unreachable,
4021 };4008 };
4022 const mod = self.bin_file.options.module.?;
4023 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
4024 const atom_index = switch (self.bin_file.tag) {4009 const atom_index = switch (self.bin_file.tag) {
4025 .macho => owner_decl.link.macho.getSymbolIndex().?,4010 .macho => blk: {
4026 .coff => owner_decl.link.coff.getSymbolIndex().?,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 },
4027 else => unreachable, // unsupported target format4020 else => unreachable, // unsupported target format
4028 };4021 };
4029 _ = try self.addInst(.{4022 _ = try self.addInst(.{
...@@ -4301,34 +4294,37 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4301,34 +4294,37 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4301 if (self.air.value(callee)) |func_value| {4294 if (self.air.value(callee)) |func_value| {
4302 if (func_value.castTag(.function)) |func_payload| {4295 if (func_value.castTag(.function)) |func_payload| {
4303 const func = func_payload.data;4296 const func = func_payload.data;
4304 const fn_owner_decl = mod.declPtr(func.owner_decl);
43054297
4306 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4298 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4307 try fn_owner_decl.link.elf.ensureInitialized(elf_file);4299 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4308 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));4300 const atom = elf_file.getAtom(atom_index);
4301 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
4309 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });4302 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
4310 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4303 } 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().?;
4312 try self.genSetReg(Type.initTag(.u64), .x30, .{4306 try self.genSetReg(Type.initTag(.u64), .x30, .{
4313 .linker_load = .{4307 .linker_load = .{
4314 .type = .got,4308 .type = .got,
4315 .sym_index = fn_owner_decl.link.macho.getSymbolIndex().?,4309 .sym_index = sym_index,
4316 },4310 },
4317 });4311 });
4318 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {4312 } 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().?;
4320 try self.genSetReg(Type.initTag(.u64), .x30, .{4315 try self.genSetReg(Type.initTag(.u64), .x30, .{
4321 .linker_load = .{4316 .linker_load = .{
4322 .type = .got,4317 .type = .got,
4323 .sym_index = fn_owner_decl.link.coff.getSymbolIndex().?,4318 .sym_index = sym_index,
4324 },4319 },
4325 });4320 });
4326 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {4321 } 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);
4328 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4324 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4329 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4325 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4330 const got_addr = p9.bases.data;4326 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.?;
4332 const fn_got_addr = got_addr + got_index * ptr_bytes;4328 const fn_got_addr = got_addr + got_index * ptr_bytes;
4333 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr });4329 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr });
4334 } else unreachable;4330 } else unreachable;
...@@ -4349,11 +4345,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4349,11 +4345,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
43494345
4350 if (self.bin_file.cast(link.File.MachO)) |macho_file| {4346 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4351 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));4347 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().?;
4352 _ = try self.addInst(.{4350 _ = try self.addInst(.{
4353 .tag = .call_extern,4351 .tag = .call_extern,
4354 .data = .{4352 .data = .{
4355 .relocation = .{4353 .relocation = .{
4356 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?,4354 .atom_index = atom_index,
4357 .sym_index = sym_index,4355 .sym_index = sym_index,
4358 },4356 },
4359 },4357 },
...@@ -5488,11 +5486,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -5488,11 +5486,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
5488 .direct => .load_memory_ptr_direct,5486 .direct => .load_memory_ptr_direct,
5489 .import => unreachable,5487 .import => unreachable,
5490 };5488 };
5491 const mod = self.bin_file.options.module.?;
5492 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5493 const atom_index = switch (self.bin_file.tag) {5489 const atom_index = switch (self.bin_file.tag) {
5494 .macho => owner_decl.link.macho.getSymbolIndex().?,5490 .macho => blk: {
5495 .coff => owner_decl.link.coff.getSymbolIndex().?,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 },
5496 else => unreachable, // unsupported target format5500 else => unreachable, // unsupported target format
5497 };5501 };
5498 _ = try self.addInst(.{5502 _ = try self.addInst(.{
...@@ -5602,11 +5606,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5602,11 +5606,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5602 .direct => .load_memory_direct,5606 .direct => .load_memory_direct,
5603 .import => .load_memory_import,5607 .import => .load_memory_import,
5604 };5608 };
5605 const mod = self.bin_file.options.module.?;
5606 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5607 const atom_index = switch (self.bin_file.tag) {5609 const atom_index = switch (self.bin_file.tag) {
5608 .macho => owner_decl.link.macho.getSymbolIndex().?,5610 .macho => blk: {
5609 .coff => owner_decl.link.coff.getSymbolIndex().?,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 },
5610 else => unreachable, // unsupported target format5620 else => unreachable, // unsupported target format
5611 };5621 };
5612 _ = try self.addInst(.{5622 _ = try self.addInst(.{
...@@ -5796,11 +5806,17 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -5796,11 +5806,17 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
5796 .direct => .load_memory_ptr_direct,5806 .direct => .load_memory_ptr_direct,
5797 .import => unreachable,5807 .import => unreachable,
5798 };5808 };
5799 const mod = self.bin_file.options.module.?;
5800 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5801 const atom_index = switch (self.bin_file.tag) {5809 const atom_index = switch (self.bin_file.tag) {
5802 .macho => owner_decl.link.macho.getSymbolIndex().?,5810 .macho => blk: {
5803 .coff => owner_decl.link.coff.getSymbolIndex().?,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 },
5804 else => unreachable, // unsupported target format5820 else => unreachable, // unsupported target format
5805 };5821 };
5806 _ = try self.addInst(.{5822 _ = try self.addInst(.{
...@@ -6119,23 +6135,27 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6119,23 +6135,27 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6119 mod.markDeclAlive(decl);6135 mod.markDeclAlive(decl);
61206136
6121 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6137 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6122 try decl.link.elf.ensureInitialized(elf_file);6138 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6123 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };6139 const atom = elf_file.getAtom(atom_index);
6140 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
6124 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {6141 } 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().?;
6126 return MCValue{ .linker_load = .{6144 return MCValue{ .linker_load = .{
6127 .type = .got,6145 .type = .got,
6128 .sym_index = decl.link.macho.getSymbolIndex().?,6146 .sym_index = sym_index,
6129 } };6147 } };
6130 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {6148 } 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().?;
6132 return MCValue{ .linker_load = .{6151 return MCValue{ .linker_load = .{
6133 .type = .got,6152 .type = .got,
6134 .sym_index = decl.link.coff.getSymbolIndex().?,6153 .sym_index = sym_index,
6135 } };6154 } };
6136 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {6155 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6137 try p9.seeDecl(decl_index);6156 const decl_block_index = try p9.seeDecl(decl_index);
6138 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;6157 const decl_block = p9.getDeclBlock(decl_block_index);
6158 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
6139 return MCValue{ .memory = got_addr };6159 return MCValue{ .memory = got_addr };
6140 } else {6160 } else {
6141 return self.fail("TODO codegen non-ELF const Decl pointer", .{});6161 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
...@@ -6148,8 +6168,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -6148,8 +6168,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
6148 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});6168 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
6149 };6169 };
6150 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6170 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6151 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;6171 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
6152 return MCValue{ .memory = vaddr };
6153 } else if (self.bin_file.cast(link.File.MachO)) |_| {6172 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6154 return MCValue{ .linker_load = .{6173 return MCValue{ .linker_load = .{
6155 .type = .direct,6174 .type = .direct,
src/arch/aarch64/Emit.zig+8-8
...@@ -670,9 +670,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -670,9 +670,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
670670
671 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {671 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
672 // Add relocation to the decl.672 // 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 }).?;
674 const target = macho_file.getGlobalByIndex(relocation.sym_index);674 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, .{
676 .type = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),676 .type = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),
677 .target = target,677 .target = target,
678 .offset = offset,678 .offset = offset,
...@@ -883,10 +883,10 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -883,10 +883,10 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
883 }883 }
884884
885 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {885 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 }).?;
887 // TODO this causes segfault in stage1887 // TODO this causes segfault in stage1
888 // try atom.addRelocations(macho_file, 2, .{888 // try atom.addRelocations(macho_file, 2, .{
889 try atom.addRelocation(macho_file, .{889 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
890 .target = .{ .sym_index = data.sym_index, .file = null },890 .target = .{ .sym_index = data.sym_index, .file = null },
891 .offset = offset,891 .offset = offset,
892 .addend = 0,892 .addend = 0,
...@@ -902,7 +902,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -902,7 +902,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
902 else => unreachable,902 else => unreachable,
903 },903 },
904 });904 });
905 try atom.addRelocation(macho_file, .{905 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
906 .target = .{ .sym_index = data.sym_index, .file = null },906 .target = .{ .sym_index = data.sym_index, .file = null },
907 .offset = offset + 4,907 .offset = offset + 4,
908 .addend = 0,908 .addend = 0,
...@@ -919,7 +919,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -919,7 +919,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
919 },919 },
920 });920 });
921 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {921 } 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 }).?;
923 const target = switch (tag) {923 const target = switch (tag) {
924 .load_memory_got,924 .load_memory_got,
925 .load_memory_ptr_got,925 .load_memory_ptr_got,
...@@ -929,7 +929,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -929,7 +929,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
929 .load_memory_import => coff_file.getGlobalByIndex(data.sym_index),929 .load_memory_import => coff_file.getGlobalByIndex(data.sym_index),
930 else => unreachable,930 else => unreachable,
931 };931 };
932 try atom.addRelocation(coff_file, .{932 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
933 .target = target,933 .target = target,
934 .offset = offset,934 .offset = offset,
935 .addend = 0,935 .addend = 0,
...@@ -946,7 +946,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -946,7 +946,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
946 else => unreachable,946 else => unreachable,
947 },947 },
948 });948 });
949 try atom.addRelocation(coff_file, .{949 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
950 .target = target,950 .target = target,
951 .offset = offset + 4,951 .offset = offset + 4,
952 .addend = 0,952 .addend = 0,
src/arch/arm/CodeGen.zig+12-25
...@@ -282,13 +282,7 @@ const DbgInfoReloc = struct {...@@ -282,13 +282,7 @@ const DbgInfoReloc = struct {
282 else => unreachable, // not a possible argument282 else => unreachable, // not a possible argument
283 };283 };
284284
285 try dw.genArgDbgInfo(285 try dw.genArgDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, loc);
286 reloc.name,
287 reloc.ty,
288 function.bin_file.tag,
289 function.mod_fn.owner_decl,
290 loc,
291 );
292 },286 },
293 .plan9 => {},287 .plan9 => {},
294 .none => {},288 .none => {},
...@@ -331,14 +325,7 @@ const DbgInfoReloc = struct {...@@ -331,14 +325,7 @@ const DbgInfoReloc = struct {
331 break :blk .nop;325 break :blk .nop;
332 },326 },
333 };327 };
334 try dw.genVarDbgInfo(328 try dw.genVarDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, is_ptr, loc);
335 reloc.name,
336 reloc.ty,
337 function.bin_file.tag,
338 function.mod_fn.owner_decl,
339 is_ptr,
340 loc,
341 );
342 },329 },
343 .plan9 => {},330 .plan9 => {},
344 .none => {},331 .none => {},
...@@ -4256,12 +4243,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4256,12 +4243,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4256 if (self.air.value(callee)) |func_value| {4243 if (self.air.value(callee)) |func_value| {
4257 if (func_value.castTag(.function)) |func_payload| {4244 if (func_value.castTag(.function)) |func_payload| {
4258 const func = func_payload.data;4245 const func = func_payload.data;
4259 const mod = self.bin_file.options.module.?;
4260 const fn_owner_decl = mod.declPtr(func.owner_decl);
42614246
4262 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4247 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4263 try fn_owner_decl.link.elf.ensureInitialized(elf_file);4248 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4264 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));4249 const atom = elf_file.getAtom(atom_index);
4250 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
4265 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });4251 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
4266 } else if (self.bin_file.cast(link.File.MachO)) |_| {4252 } else if (self.bin_file.cast(link.File.MachO)) |_| {
4267 unreachable; // unsupported architecture for MachO4253 unreachable; // unsupported architecture for MachO
...@@ -6084,15 +6070,17 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6084,15 +6070,17 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6084 mod.markDeclAlive(decl);6070 mod.markDeclAlive(decl);
60856071
6086 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6072 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6087 try decl.link.elf.ensureInitialized(elf_file);6073 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6088 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };6074 const atom = elf_file.getAtom(atom_index);
6075 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
6089 } else if (self.bin_file.cast(link.File.MachO)) |_| {6076 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6090 unreachable; // unsupported architecture for MachO6077 unreachable; // unsupported architecture for MachO
6091 } else if (self.bin_file.cast(link.File.Coff)) |_| {6078 } else if (self.bin_file.cast(link.File.Coff)) |_| {
6092 return self.fail("TODO codegen COFF const Decl pointer", .{});6079 return self.fail("TODO codegen COFF const Decl pointer", .{});
6093 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {6080 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6094 try p9.seeDecl(decl_index);6081 const decl_block_index = try p9.seeDecl(decl_index);
6095 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;6082 const decl_block = p9.getDeclBlock(decl_block_index);
6083 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
6096 return MCValue{ .memory = got_addr };6084 return MCValue{ .memory = got_addr };
6097 } else {6085 } else {
6098 return self.fail("TODO codegen non-ELF const Decl pointer", .{});6086 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
...@@ -6106,8 +6094,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -6106,8 +6094,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
6106 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});6094 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
6107 };6095 };
6108 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6096 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6109 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;6097 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
6110 return MCValue{ .memory = vaddr };
6111 } else if (self.bin_file.cast(link.File.MachO)) |_| {6098 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6112 unreachable;6099 unreachable;
6113 } else if (self.bin_file.cast(link.File.Coff)) |_| {6100 } 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 {...@@ -1615,13 +1615,9 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
16151615
1616 switch (self.debug_output) {1616 switch (self.debug_output) {
1617 .dwarf => |dw| switch (mcv) {1617 .dwarf => |dw| switch (mcv) {
1618 .register => |reg| try dw.genArgDbgInfo(1618 .register => |reg| try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, .{
1619 name,1619 .register = reg.dwarfLocOp(),
1620 ty,1620 }),
1621 self.bin_file.tag,
1622 self.mod_fn.owner_decl,
1623 .{ .register = reg.dwarfLocOp() },
1624 ),
1625 .stack_offset => {},1621 .stack_offset => {},
1626 else => {},1622 else => {},
1627 },1623 },
...@@ -1721,12 +1717,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1721,12 +1717,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1721 if (self.air.value(callee)) |func_value| {1717 if (self.air.value(callee)) |func_value| {
1722 if (func_value.castTag(.function)) |func_payload| {1718 if (func_value.castTag(.function)) |func_payload| {
1723 const func = func_payload.data;1719 const func = func_payload.data;
17241720 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1725 const mod = self.bin_file.options.module.?;1721 const atom = elf_file.getAtom(atom_index);
1726 const fn_owner_decl = mod.declPtr(func.owner_decl);1722 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
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
1730 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });1723 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
1731 _ = try self.addInst(.{1724 _ = try self.addInst(.{
1732 .tag = .jalr,1725 .tag = .jalr,
...@@ -2553,17 +2546,17 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -2553,17 +2546,17 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
2553 const decl = mod.declPtr(decl_index);2546 const decl = mod.declPtr(decl_index);
2554 mod.markDeclAlive(decl);2547 mod.markDeclAlive(decl);
2555 if (self.bin_file.cast(link.File.Elf)) |elf_file| {2548 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2556 try decl.link.elf.ensureInitialized(elf_file);2549 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
2557 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };2550 const atom = elf_file.getAtom(atom_index);
2551 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
2558 } else if (self.bin_file.cast(link.File.MachO)) |_| {2552 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2559 // TODO I'm hacking my way through here by repurposing .memory for storing2553 unreachable;
2560 // index to the GOT target symbol index.
2561 return MCValue{ .memory = decl.link.macho.sym_index };
2562 } else if (self.bin_file.cast(link.File.Coff)) |_| {2554 } else if (self.bin_file.cast(link.File.Coff)) |_| {
2563 return self.fail("TODO codegen COFF const Decl pointer", .{});2555 return self.fail("TODO codegen COFF const Decl pointer", .{});
2564 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {2556 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2565 try p9.seeDecl(decl_index);2557 const decl_block_index = try p9.seeDecl(decl_index);
2566 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;2558 const decl_block = p9.getDeclBlock(decl_block_index);
2559 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
2567 return MCValue{ .memory = got_addr };2560 return MCValue{ .memory = got_addr };
2568 } else {2561 } else {
2569 return self.fail("TODO codegen non-ELF const Decl pointer", .{});2562 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...@@ -1216,11 +1216,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1216 if (self.bin_file.tag == link.File.Elf.base_tag) {1216 if (self.bin_file.tag == link.File.Elf.base_tag) {
1217 if (func_value.castTag(.function)) |func_payload| {1217 if (func_value.castTag(.function)) |func_payload| {
1218 const func = func_payload.data;1218 const func = func_payload.data;
1219 const mod = self.bin_file.options.module.?;
1220 const fn_owner_decl = mod.declPtr(func.owner_decl);
1221 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {1219 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1222 try fn_owner_decl.link.elf.ensureInitialized(elf_file);1220 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1223 break :blk @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));1221 const atom = elf_file.getAtom(atom_index);
1222 break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file));
1224 } else unreachable;1223 } else unreachable;
12251224
1226 try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr });1225 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 {...@@ -3413,13 +3412,9 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
34133412
3414 switch (self.debug_output) {3413 switch (self.debug_output) {
3415 .dwarf => |dw| switch (mcv) {3414 .dwarf => |dw| switch (mcv) {
3416 .register => |reg| try dw.genArgDbgInfo(3415 .register => |reg| try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, .{
3417 name,3416 .register = reg.dwarfLocOp(),
3418 ty,3417 }),
3419 self.bin_file.tag,
3420 self.mod_fn.owner_decl,
3421 .{ .register = reg.dwarfLocOp() },
3422 ),
3423 else => {},3418 else => {},
3424 },3419 },
3425 else => {},3420 else => {},
...@@ -4205,8 +4200,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -4205,8 +4200,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
42054200
4206 mod.markDeclAlive(decl);4201 mod.markDeclAlive(decl);
4207 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4202 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4208 try decl.link.elf.ensureInitialized(elf_file);4203 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
4209 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };4204 const atom = elf_file.getAtom(atom_index);
4205 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
4210 } else {4206 } else {
4211 return self.fail("TODO codegen non-ELF const Decl pointer", .{});4207 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
4212 }4208 }
src/arch/wasm/CodeGen.zig+20-20
...@@ -1194,7 +1194,7 @@ fn genFunc(func: *CodeGen) InnerError!void {...@@ -1194,7 +1194,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
1194 const fn_info = func.decl.ty.fnInfo();1194 const fn_info = func.decl.ty.fnInfo();
1195 var func_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type, func.target);1195 var func_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type, func.target);
1196 defer func_type.deinit(func.gpa);1196 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
1199 var cc_result = try func.resolveCallingConventionValues(func.decl.ty);1199 var cc_result = try func.resolveCallingConventionValues(func.decl.ty);
1200 defer cc_result.deinit(func.gpa);1200 defer cc_result.deinit(func.gpa);
...@@ -1269,10 +1269,10 @@ fn genFunc(func: *CodeGen) InnerError!void {...@@ -1269,10 +1269,10 @@ fn genFunc(func: *CodeGen) InnerError!void {
12691269
1270 var emit: Emit = .{1270 var emit: Emit = .{
1271 .mir = mir,1271 .mir = mir,
1272 .bin_file = &func.bin_file.base,1272 .bin_file = func.bin_file,
1273 .code = func.code,1273 .code = func.code,
1274 .locals = func.locals.items,1274 .locals = func.locals.items,
1275 .decl = func.decl,1275 .decl_index = func.decl_index,
1276 .dbg_output = func.debug_output,1276 .dbg_output = func.debug_output,
1277 .prev_di_line = 0,1277 .prev_di_line = 0,
1278 .prev_di_column = 0,1278 .prev_di_column = 0,
...@@ -2117,33 +2117,31 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -2117,33 +2117,31 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2117 const fn_info = fn_ty.fnInfo();2117 const fn_info = fn_ty.fnInfo();
2118 const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type, func.target);2118 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: {
2121 const func_val = func.air.value(pl_op.operand) orelse break :blk null;2121 const func_val = func.air.value(pl_op.operand) orelse break :blk null;
2122 const module = func.bin_file.base.options.module.?;2122 const module = func.bin_file.base.options.module.?;
21232123
2124 if (func_val.castTag(.function)) |function| {2124 if (func_val.castTag(.function)) |function| {
2125 const decl = module.declPtr(function.data.owner_decl);2125 _ = try func.bin_file.getOrCreateAtomForDecl(function.data.owner_decl);
2126 try decl.link.wasm.ensureInitialized(func.bin_file);2126 break :blk function.data.owner_decl;
2127 break :blk decl;
2128 } else if (func_val.castTag(.extern_fn)) |extern_fn| {2127 } else if (func_val.castTag(.extern_fn)) |extern_fn| {
2129 const ext_decl = module.declPtr(extern_fn.data.owner_decl);2128 const ext_decl = module.declPtr(extern_fn.data.owner_decl);
2130 const ext_info = ext_decl.ty.fnInfo();2129 const ext_info = ext_decl.ty.fnInfo();
2131 var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target);2130 var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target);
2132 defer func_type.deinit(func.gpa);2131 defer func_type.deinit(func.gpa);
2133 const atom = &ext_decl.link.wasm;2132 const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_fn.data.owner_decl);
2134 try atom.ensureInitialized(func.bin_file);2133 const atom = func.bin_file.getAtomPtr(atom_index);
2135 ext_decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type);2134 ext_decl.fn_link.?.type_index = try func.bin_file.putOrGetFuncType(func_type);
2136 try func.bin_file.addOrUpdateImport(2135 try func.bin_file.addOrUpdateImport(
2137 mem.sliceTo(ext_decl.name, 0),2136 mem.sliceTo(ext_decl.name, 0),
2138 atom.getSymbolIndex().?,2137 atom.getSymbolIndex().?,
2139 ext_decl.getExternFn().?.lib_name,2138 ext_decl.getExternFn().?.lib_name,
2140 ext_decl.fn_link.wasm.type_index,2139 ext_decl.fn_link.?.type_index,
2141 );2140 );
2142 break :blk ext_decl;2141 break :blk extern_fn.data.owner_decl;
2143 } else if (func_val.castTag(.decl_ref)) |decl_ref| {2142 } else if (func_val.castTag(.decl_ref)) |decl_ref| {
2144 const decl = module.declPtr(decl_ref.data);2143 _ = try func.bin_file.getOrCreateAtomForDecl(decl_ref.data);
2145 try decl.link.wasm.ensureInitialized(func.bin_file);2144 break :blk decl_ref.data;
2146 break :blk decl;
2147 }2145 }
2148 return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()});2146 return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()});
2149 };2147 };
...@@ -2164,7 +2162,8 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -2164,7 +2162,8 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2164 }2162 }
21652163
2166 if (callee) |direct| {2164 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);
2168 } else {2167 } else {
2169 // in this case we call a function pointer2168 // in this case we call a function pointer
2170 // so load its value onto the stack2169 // so load its value onto the stack
...@@ -2477,7 +2476,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2477,7 +2476,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2477 .dwarf => |dwarf| {2476 .dwarf => |dwarf| {
2478 const src_index = func.air.instructions.items(.data)[inst].arg.src_index;2477 const src_index = func.air.instructions.items(.data)[inst].arg.src_index;
2479 const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, src_index);2478 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, .{
2481 .wasm_local = arg.local.value,2480 .wasm_local = arg.local.value,
2482 });2481 });
2483 },2482 },
...@@ -2760,9 +2759,10 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind...@@ -2760,9 +2759,10 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind
2760 }2759 }
27612760
2762 module.markDeclAlive(decl);2761 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;
2766 if (decl.ty.zigTypeTag() == .Fn) {2766 if (decl.ty.zigTypeTag() == .Fn) {
2767 try func.bin_file.addTableFunction(target_sym_index);2767 try func.bin_file.addTableFunction(target_sym_index);
2768 return WValue{ .function_index = target_sym_index };2768 return WValue{ .function_index = target_sym_index };
...@@ -5547,7 +5547,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void {...@@ -5547,7 +5547,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void {
5547 break :blk .nop;5547 break :blk .nop;
5548 },5548 },
5549 };5549 };
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
5552 func.finishAir(inst, .none, &.{});5552 func.finishAir(inst, .none, &.{});
5553}5553}
src/arch/wasm/Emit.zig+18-11
...@@ -11,8 +11,8 @@ const leb128 = std.leb;...@@ -11,8 +11,8 @@ const leb128 = std.leb;
1111
12/// Contains our list of instructions12/// Contains our list of instructions
13mir: Mir,13mir: Mir,
14/// Reference to the file handler14/// Reference to the Wasm module linker
15bin_file: *link.File,15bin_file: *link.File.Wasm,
16/// Possible error message. When set, the value is allocated and16/// Possible error message. When set, the value is allocated and
17/// must be freed manually.17/// must be freed manually.
18error_msg: ?*Module.ErrorMsg = null,18error_msg: ?*Module.ErrorMsg = null,
...@@ -21,7 +21,7 @@ code: *std.ArrayList(u8),...@@ -21,7 +21,7 @@ code: *std.ArrayList(u8),
21/// List of allocated locals.21/// List of allocated locals.
22locals: []const u8,22locals: []const u8,
23/// The declaration that code is being generated for.23/// The declaration that code is being generated for.
24decl: *Module.Decl,24decl_index: Module.Decl.Index,
2525
26// Debug information26// Debug information
27/// Holds the debug information for this emission27/// Holds the debug information for this emission
...@@ -252,8 +252,8 @@ fn offset(self: Emit) u32 {...@@ -252,8 +252,8 @@ fn offset(self: Emit) u32 {
252fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {252fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
253 @setCold(true);253 @setCold(true);
254 std.debug.assert(emit.error_msg == null);254 std.debug.assert(emit.error_msg == null);
255 // TODO: Determine the source location.255 const mod = emit.bin_file.base.options.module.?;
256 emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.allocator, emit.decl.srcLoc(), format, args);256 emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.base.allocator, mod.declPtr(emit.decl_index).srcLoc(), format, args);
257 return error.EmitFail;257 return error.EmitFail;
258}258}
259259
...@@ -304,8 +304,9 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {...@@ -304,8 +304,9 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {
304 const global_offset = emit.offset();304 const global_offset = emit.offset();
305 try emit.code.appendSlice(&buf);305 try emit.code.appendSlice(&buf);
306306
307 // globals can have index 0 as it represents the stack pointer307 const atom_index = emit.bin_file.decls.get(emit.decl_index).?;
308 try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{308 const atom = emit.bin_file.getAtomPtr(atom_index);
309 try atom.relocs.append(emit.bin_file.base.allocator, .{
309 .index = label,310 .index = label,
310 .offset = global_offset,311 .offset = global_offset,
311 .relocation_type = .R_WASM_GLOBAL_INDEX_LEB,312 .relocation_type = .R_WASM_GLOBAL_INDEX_LEB,
...@@ -361,7 +362,9 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -361,7 +362,9 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {
361 try emit.code.appendSlice(&buf);362 try emit.code.appendSlice(&buf);
362363
363 if (label != 0) {364 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, .{
365 .offset = call_offset,368 .offset = call_offset,
366 .index = label,369 .index = label,
367 .relocation_type = .R_WASM_FUNCTION_INDEX_LEB,370 .relocation_type = .R_WASM_FUNCTION_INDEX_LEB,
...@@ -387,7 +390,9 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -387,7 +390,9 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
387 try emit.code.appendSlice(&buf);390 try emit.code.appendSlice(&buf);
388391
389 if (symbol_index != 0) {392 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, .{
391 .offset = index_offset,396 .offset = index_offset,
392 .index = symbol_index,397 .index = symbol_index,
393 .relocation_type = .R_WASM_TABLE_INDEX_SLEB,398 .relocation_type = .R_WASM_TABLE_INDEX_SLEB,
...@@ -399,7 +404,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -399,7 +404,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
399 const extra_index = emit.mir.instructions.items(.data)[inst].payload;404 const extra_index = emit.mir.instructions.items(.data)[inst].payload;
400 const mem = emit.mir.extraData(Mir.Memory, extra_index).data;405 const mem = emit.mir.extraData(Mir.Memory, extra_index).data;
401 const mem_offset = emit.offset() + 1;406 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;
403 if (is_wasm32) {408 if (is_wasm32) {
404 try emit.code.append(std.wasm.opcode(.i32_const));409 try emit.code.append(std.wasm.opcode(.i32_const));
405 var buf: [5]u8 = undefined;410 var buf: [5]u8 = undefined;
...@@ -413,7 +418,9 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -413,7 +418,9 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
413 }418 }
414419
415 if (mem.pointer != 0) {420 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, .{
417 .offset = mem_offset,424 .offset = mem_offset,
418 .index = mem.pointer,425 .index = mem.pointer,
419 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_LEB else .R_WASM_MEMORY_ADDR_LEB64,426 .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...@@ -2668,12 +2668,13 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2668 switch (ptr) {2668 switch (ptr) {
2669 .linker_load => |load_struct| {2669 .linker_load => |load_struct| {
2670 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));2670 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));
2671 const mod = self.bin_file.options.module.?;2671 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
2672 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);2672 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
2673 const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag)2673 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
2674 fn_owner_decl.link.macho.getSymbolIndex().?2674 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
2675 else2675 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
2676 fn_owner_decl.link.coff.getSymbolIndex().?;2676 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
2677 } else unreachable;
2677 const flags: u2 = switch (load_struct.type) {2678 const flags: u2 = switch (load_struct.type) {
2678 .got => 0b00,2679 .got => 0b00,
2679 .direct => 0b01,2680 .direct => 0b01,
...@@ -3835,7 +3836,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {...@@ -3835,7 +3836,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
3835 },3836 },
3836 else => unreachable, // not a valid function parameter3837 else => unreachable, // not a valid function parameter
3837 };3838 };
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);
3839 },3840 },
3840 .plan9 => {},3841 .plan9 => {},
3841 .none => {},3842 .none => {},
...@@ -3875,7 +3876,7 @@ fn genVarDbgInfo(...@@ -3875,7 +3876,7 @@ fn genVarDbgInfo(
3875 break :blk .nop;3876 break :blk .nop;
3876 },3877 },
3877 };3878 };
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);
3879 },3880 },
3880 .plan9 => {},3881 .plan9 => {},
3881 .none => {},3882 .none => {},
...@@ -3995,19 +3996,19 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -3995,19 +3996,19 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
3995 if (self.air.value(callee)) |func_value| {3996 if (self.air.value(callee)) |func_value| {
3996 if (func_value.castTag(.function)) |func_payload| {3997 if (func_value.castTag(.function)) |func_payload| {
3997 const func = func_payload.data;3998 const func = func_payload.data;
3998 const fn_owner_decl = mod.declPtr(func.owner_decl);
39993999
4000 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4000 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4001 try fn_owner_decl.link.elf.ensureInitialized(elf_file);4001 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4002 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));4002 const atom = elf_file.getAtom(atom_index);
4003 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
4003 _ = try self.addInst(.{4004 _ = try self.addInst(.{
4004 .tag = .call,4005 .tag = .call,
4005 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),4006 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4006 .data = .{ .imm = got_addr },4007 .data = .{ .imm = got_addr },
4007 });4008 });
4008 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {4009 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4009 try fn_owner_decl.link.coff.ensureInitialized(coff_file);4010 const atom_index = try coff_file.getOrCreateAtomForDecl(func.owner_decl);
4010 const sym_index = fn_owner_decl.link.coff.getSymbolIndex().?;4011 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
4011 try self.genSetReg(Type.initTag(.usize), .rax, .{4012 try self.genSetReg(Type.initTag(.usize), .rax, .{
4012 .linker_load = .{4013 .linker_load = .{
4013 .type = .got,4014 .type = .got,
...@@ -4023,8 +4024,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4023,8 +4024,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4023 .data = undefined,4024 .data = undefined,
4024 });4025 });
4025 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4026 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4026 try fn_owner_decl.link.macho.ensureInitialized(macho_file);4027 const atom_index = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
4027 const sym_index = fn_owner_decl.link.macho.getSymbolIndex().?;4028 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
4028 try self.genSetReg(Type.initTag(.usize), .rax, .{4029 try self.genSetReg(Type.initTag(.usize), .rax, .{
4029 .linker_load = .{4030 .linker_load = .{
4030 .type = .got,4031 .type = .got,
...@@ -4040,11 +4041,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4040,11 +4041,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4040 .data = undefined,4041 .data = undefined,
4041 });4042 });
4042 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {4043 } 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);
4044 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4046 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4045 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4047 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4046 const got_addr = p9.bases.data;4048 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.?;
4048 const fn_got_addr = got_addr + got_index * ptr_bytes;4050 const fn_got_addr = got_addr + got_index * ptr_bytes;
4049 _ = try self.addInst(.{4051 _ = try self.addInst(.{
4050 .tag = .call,4052 .tag = .call,
...@@ -4080,15 +4082,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4080,15 +4082,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4080 });4082 });
4081 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4083 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4082 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));4084 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().?;
4083 _ = try self.addInst(.{4087 _ = try self.addInst(.{
4084 .tag = .call_extern,4088 .tag = .call_extern,
4085 .ops = undefined,4089 .ops = undefined,
4086 .data = .{4090 .data = .{ .relocation = .{
4087 .relocation = .{4091 .atom_index = atom_index,
4088 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?,4092 .sym_index = sym_index,
4089 .sym_index = sym_index,4093 } },
4090 },
4091 },
4092 });4094 });
4093 } else {4095 } else {
4094 return self.fail("TODO implement calling extern functions", .{});4096 return self.fail("TODO implement calling extern functions", .{});
...@@ -6719,23 +6721,27 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6719,23 +6721,27 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6719 module.markDeclAlive(decl);6721 module.markDeclAlive(decl);
67206722
6721 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6723 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6722 try decl.link.elf.ensureInitialized(elf_file);6724 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6723 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };6725 const atom = elf_file.getAtom(atom_index);
6726 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
6724 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {6727 } 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().?;
6726 return MCValue{ .linker_load = .{6730 return MCValue{ .linker_load = .{
6727 .type = .got,6731 .type = .got,
6728 .sym_index = decl.link.macho.getSymbolIndex().?,6732 .sym_index = sym_index,
6729 } };6733 } };
6730 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {6734 } 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().?;
6732 return MCValue{ .linker_load = .{6737 return MCValue{ .linker_load = .{
6733 .type = .got,6738 .type = .got,
6734 .sym_index = decl.link.coff.getSymbolIndex().?,6739 .sym_index = sym_index,
6735 } };6740 } };
6736 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {6741 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6737 try p9.seeDecl(decl_index);6742 const decl_block_index = try p9.seeDecl(decl_index);
6738 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;6743 const decl_block = p9.getDeclBlock(decl_block_index);
6744 const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes;
6739 return MCValue{ .memory = got_addr };6745 return MCValue{ .memory = got_addr };
6740 } else {6746 } else {
6741 return self.fail("TODO codegen non-ELF const Decl pointer", .{});6747 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
...@@ -6748,8 +6754,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -6748,8 +6754,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
6748 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});6754 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
6749 };6755 };
6750 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6756 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6751 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;6757 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
6752 return MCValue{ .memory = vaddr };
6753 } else if (self.bin_file.cast(link.File.MachO)) |_| {6758 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6754 return MCValue{ .linker_load = .{6759 return MCValue{ .linker_load = .{
6755 .type = .direct,6760 .type = .direct,
src/arch/x86_64/Emit.zig+8-8
...@@ -1001,8 +1001,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1001,8 +1001,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1001 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),1001 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
1002 else => unreachable,1002 else => unreachable,
1003 };1003 };
1004 const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;1004 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
1005 try atom.addRelocation(macho_file, .{1005 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
1006 .type = reloc_type,1006 .type = reloc_type,
1007 .target = .{ .sym_index = relocation.sym_index, .file = null },1007 .target = .{ .sym_index = relocation.sym_index, .file = null },
1008 .offset = @intCast(u32, end_offset - 4),1008 .offset = @intCast(u32, end_offset - 4),
...@@ -1011,8 +1011,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1011,8 +1011,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1011 .length = 2,1011 .length = 2,
1012 });1012 });
1013 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {1013 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
1014 const atom = coff_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;1014 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
1015 try atom.addRelocation(coff_file, .{1015 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
1016 .type = switch (ops.flags) {1016 .type = switch (ops.flags) {
1017 0b00 => .got,1017 0b00 => .got,
1018 0b01 => .direct,1018 0b01 => .direct,
...@@ -1140,9 +1140,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1140,9 +1140,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
11401140
1141 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {1141 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
1142 // Add relocation to the decl.1142 // 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 }).?;
1144 const target = macho_file.getGlobalByIndex(relocation.sym_index);1144 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, .{
1146 .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),1146 .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
1147 .target = target,1147 .target = target,
1148 .offset = offset,1148 .offset = offset,
...@@ -1152,9 +1152,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1152,9 +1152,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1152 });1152 });
1153 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {1153 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
1154 // Add relocation to the decl.1154 // 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 }).?;
1156 const target = coff_file.getGlobalByIndex(relocation.sym_index);1156 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, .{
1158 .type = .direct,1158 .type = .direct,
1159 .target = target,1159 .target = target,
1160 .offset = offset,1160 .offset = offset,
src/codegen/spirv.zig+19-11
...@@ -49,7 +49,7 @@ pub const DeclGen = struct {...@@ -49,7 +49,7 @@ pub const DeclGen = struct {
49 spv: *SpvModule,49 spv: *SpvModule,
5050
51 /// The decl we are currently generating code for.51 /// The decl we are currently generating code for.
52 decl: *Decl,52 decl_index: Decl.Index,
5353
54 /// The intermediate code of the declaration we are currently generating. Note: If54 /// The intermediate code of the declaration we are currently generating. Note: If
55 /// the declaration is not a function, this value will be undefined!55 /// the declaration is not a function, this value will be undefined!
...@@ -59,6 +59,8 @@ pub const DeclGen = struct {...@@ -59,6 +59,8 @@ pub const DeclGen = struct {
59 /// Note: If the declaration is not a function, this value will be undefined!59 /// Note: If the declaration is not a function, this value will be undefined!
60 liveness: Liveness,60 liveness: Liveness,
6161
62 ids: *const std.AutoHashMap(Decl.Index, IdResult),
63
62 /// An array of function argument result-ids. Each index corresponds with the64 /// An array of function argument result-ids. Each index corresponds with the
63 /// function argument of the same index.65 /// function argument of the same index.
64 args: std.ArrayListUnmanaged(IdRef) = .{},66 args: std.ArrayListUnmanaged(IdRef) = .{},
...@@ -133,14 +135,20 @@ pub const DeclGen = struct {...@@ -133,14 +135,20 @@ pub const DeclGen = struct {
133135
134 /// Initialize the common resources of a DeclGen. Some fields are left uninitialized,136 /// Initialize the common resources of a DeclGen. Some fields are left uninitialized,
135 /// only set when `gen` is called.137 /// 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 {
137 return .{144 return .{
138 .gpa = allocator,145 .gpa = allocator,
139 .module = module,146 .module = module,
140 .spv = spv,147 .spv = spv,
141 .decl = undefined,148 .decl_index = undefined,
142 .air = undefined,149 .air = undefined,
143 .liveness = undefined,150 .liveness = undefined,
151 .ids = ids,
144 .next_arg_index = undefined,152 .next_arg_index = undefined,
145 .current_block_label_id = undefined,153 .current_block_label_id = undefined,
146 .error_msg = undefined,154 .error_msg = undefined,
...@@ -150,9 +158,9 @@ pub const DeclGen = struct {...@@ -150,9 +158,9 @@ pub const DeclGen = struct {
150 /// Generate the code for `decl`. If a reportable error occurred during code generation,158 /// Generate the code for `decl`. If a reportable error occurred during code generation,
151 /// a message is returned by this function. Callee owns the memory. If this function159 /// a message is returned by this function. Callee owns the memory. If this function
152 /// returns such a reportable error, it is valid to be called again for a different decl.160 /// 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 {
154 // Reset internal resources, we don't want to re-allocate these.162 // Reset internal resources, we don't want to re-allocate these.
155 self.decl = decl;163 self.decl_index = decl_index;
156 self.air = air;164 self.air = air;
157 self.liveness = liveness;165 self.liveness = liveness;
158 self.args.items.len = 0;166 self.args.items.len = 0;
...@@ -194,7 +202,7 @@ pub const DeclGen = struct {...@@ -194,7 +202,7 @@ pub const DeclGen = struct {
194 pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {202 pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
195 @setCold(true);203 @setCold(true);
196 const src = LazySrcLoc.nodeOffset(0);204 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));
198 assert(self.error_msg == null);206 assert(self.error_msg == null);
199 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);207 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);
200 return error.CodegenFail;208 return error.CodegenFail;
...@@ -332,7 +340,7 @@ pub const DeclGen = struct {...@@ -332,7 +340,7 @@ pub const DeclGen = struct {
332 };340 };
333 const decl = self.module.declPtr(fn_decl_index);341 const decl = self.module.declPtr(fn_decl_index);
334 self.module.markDeclAlive(decl);342 self.module.markDeclAlive(decl);
335 return decl.fn_link.spirv.id.toRef();343 return self.ids.get(fn_decl_index).?.toRef();
336 }344 }
337345
338 const target = self.getTarget();346 const target = self.getTarget();
...@@ -553,8 +561,8 @@ pub const DeclGen = struct {...@@ -553,8 +561,8 @@ pub const DeclGen = struct {
553 }561 }
554562
555 fn genDecl(self: *DeclGen) !void {563 fn genDecl(self: *DeclGen) !void {
556 const decl = self.decl;564 const result_id = self.ids.get(self.decl_index).?;
557 const result_id = decl.fn_link.spirv.id;565 const decl = self.module.declPtr(self.decl_index);
558566
559 if (decl.val.castTag(.function)) |_| {567 if (decl.val.castTag(.function)) |_| {
560 assert(decl.ty.zigTypeTag() == .Fn);568 assert(decl.ty.zigTypeTag() == .Fn);
...@@ -945,7 +953,7 @@ pub const DeclGen = struct {...@@ -945,7 +953,7 @@ pub const DeclGen = struct {
945953
946 fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void {954 fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void {
947 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;955 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));
949 try self.func.body.emit(self.spv.gpa, .OpLine, .{957 try self.func.body.emit(self.spv.gpa, .OpLine, .{
950 .file = src_fname_id,958 .file = src_fname_id,
951 .line = dbg_stmt.line,959 .line = dbg_stmt.line,
...@@ -1106,7 +1114,7 @@ pub const DeclGen = struct {...@@ -1106,7 +1114,7 @@ pub const DeclGen = struct {
1106 assert(as.errors.items.len != 0);1114 assert(as.errors.items.len != 0);
1107 assert(self.error_msg == null);1115 assert(self.error_msg == null);
1108 const loc = LazySrcLoc.nodeOffset(0);1116 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));
1110 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});1118 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});
1111 const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len);1119 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 {...@@ -261,39 +261,6 @@ pub const File = struct {
261 /// of this linking operation.261 /// of this linking operation.
262 lock: ?Cache.Lock = null,262 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
297 /// Attempts incremental linking, if the file already exists. If264 /// Attempts incremental linking, if the file already exists. If
298 /// incremental linking fails, falls back to truncating the file and265 /// incremental linking fails, falls back to truncating the file and
299 /// rewriting it. A malicious file is detected as incremental link failure266 /// rewriting it. A malicious file is detected as incremental link failure
...@@ -580,22 +547,23 @@ pub const File = struct {...@@ -580,22 +547,23 @@ pub const File = struct {
580 }547 }
581 }548 }
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);
584 log.debug("updateDeclLineNumber {*} ({s}), line={}", .{552 log.debug("updateDeclLineNumber {*} ({s}), line={}", .{
585 decl, decl.name, decl.src_line + 1,553 decl, decl.name, decl.src_line + 1,
586 });554 });
587 assert(decl.has_tv);555 assert(decl.has_tv);
588 if (build_options.only_c) {556 if (build_options.only_c) {
589 assert(base.tag == .c);557 assert(base.tag == .c);
590 return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl);558 return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index);
591 }559 }
592 switch (base.tag) {560 switch (base.tag) {
593 .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl),561 .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl_index),
594 .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl),562 .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl_index),
595 .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl),563 .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl_index),
596 .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl),564 .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index),
597 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl),565 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl_index),
598 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl),566 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl_index),
599 .spirv, .nvptx => {},567 .spirv, .nvptx => {},
600 }568 }
601 }569 }
src/link/C.zig+2-2
...@@ -219,12 +219,12 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi...@@ -219,12 +219,12 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
219 code.shrinkAndFree(module.gpa, code.items.len);219 code.shrinkAndFree(module.gpa, code.items.len);
220}220}
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 {
223 // The C backend does not have the ability to fix line numbers without re-generating223 // The C backend does not have the ability to fix line numbers without re-generating
224 // the entire Decl.224 // the entire Decl.
225 _ = self;225 _ = self;
226 _ = module;226 _ = module;
227 _ = decl;227 _ = decl_index;
228}228}
229229
230pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void {230pub 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,...@@ -79,13 +79,13 @@ entry_addr: ?u32 = null,
79/// We store them here so that we can properly dispose of any allocated79/// We store them here so that we can properly dispose of any allocated
80/// memory within the atom in the incremental linker.80/// memory within the atom in the incremental linker.
81/// TODO consolidate this.81/// TODO consolidate this.
82decls: std.AutoHashMapUnmanaged(Module.Decl.Index, ?u16) = .{},82decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
8383
84/// List of atoms that are either synthetic or map directly to the Zig source program.84/// 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
87/// Table of atoms indexed by the symbol index.87/// 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
90/// Table of unnamed constants associated with a parent `Decl`.90/// Table of unnamed constants associated with a parent `Decl`.
91/// We store them here so that we can free the constants whenever the `Decl`91/// We store them here so that we can free the constants whenever the `Decl`
...@@ -124,9 +124,9 @@ const Entry = struct {...@@ -124,9 +124,9 @@ const Entry = struct {
124 sym_index: u32,124 sym_index: u32,
125};125};
126126
127const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation));127const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
128const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32));128const BaseRelocationTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
129const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));129const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
130130
131const default_file_alignment: u16 = 0x200;131const default_file_alignment: u16 = 0x200;
132const default_size_of_stack_reserve: u32 = 0x1000000;132const default_size_of_stack_reserve: u32 = 0x1000000;
...@@ -137,7 +137,7 @@ const default_size_of_heap_commit: u32 = 0x1000;...@@ -137,7 +137,7 @@ const default_size_of_heap_commit: u32 = 0x1000;
137const Section = struct {137const Section = struct {
138 header: coff.SectionHeader,138 header: coff.SectionHeader,
139139
140 last_atom: ?*Atom = null,140 last_atom_index: ?Atom.Index = null,
141141
142 /// A list of atoms that have surplus capacity. This list can have false142 /// A list of atoms that have surplus capacity. This list can have false
143 /// positives, as functions grow and shrink over time, only sometimes being added143 /// positives, as functions grow and shrink over time, only sometimes being added
...@@ -154,7 +154,34 @@ const Section = struct {...@@ -154,7 +154,34 @@ const Section = struct {
154 /// overcapacity can be negative. A simple way to have negative overcapacity is to154 /// overcapacity can be negative. A simple way to have negative overcapacity is to
155 /// allocate a fresh atom, which will have ideal capacity, and then grow it155 /// allocate a fresh atom, which will have ideal capacity, and then grow it
156 /// by 1 byte. It will then have -1 overcapacity.156 /// 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 }
158};185};
159186
160pub const PtrWidth = enum {187pub const PtrWidth = enum {
...@@ -168,11 +195,6 @@ pub const PtrWidth = enum {...@@ -168,11 +195,6 @@ pub const PtrWidth = enum {
168 };195 };
169 }196 }
170};197};
171pub const SrcFn = void;
172
173pub const Export = struct {
174 sym_index: ?u32 = null,
175};
176198
177pub const SymbolWithLoc = struct {199pub const SymbolWithLoc = struct {
178 // Index into the respective symbol table.200 // Index into the respective symbol table.
...@@ -271,11 +293,7 @@ pub fn deinit(self: *Coff) void {...@@ -271,11 +293,7 @@ pub fn deinit(self: *Coff) void {
271 }293 }
272 self.sections.deinit(gpa);294 self.sections.deinit(gpa);
273295
274 for (self.managed_atoms.items) |atom| {296 self.atoms.deinit(gpa);
275 gpa.destroy(atom);
276 }
277 self.managed_atoms.deinit(gpa);
278
279 self.locals.deinit(gpa);297 self.locals.deinit(gpa);
280 self.globals.deinit(gpa);298 self.globals.deinit(gpa);
281299
...@@ -297,7 +315,15 @@ pub fn deinit(self: *Coff) void {...@@ -297,7 +315,15 @@ pub fn deinit(self: *Coff) void {
297 self.imports.deinit(gpa);315 self.imports.deinit(gpa);
298 self.imports_free_list.deinit(gpa);316 self.imports_free_list.deinit(gpa);
299 self.imports_table.deinit(gpa);317 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
301 self.atom_by_index_table.deinit(gpa);327 self.atom_by_index_table.deinit(gpa);
302328
303 {329 {
...@@ -461,17 +487,18 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {...@@ -461,17 +487,18 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {
461 // TODO: enforce order by increasing VM addresses in self.sections container.487 // TODO: enforce order by increasing VM addresses in self.sections container.
462 // This is required by the loader anyhow as far as I can tell.488 // This is required by the loader anyhow as far as I can tell.
463 for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| {489 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];
465 next_header.virtual_address += diff;491 next_header.virtual_address += diff;
466492
467 if (maybe_last_atom.*) |last_atom| {493 if (maybe_last_atom_index) |last_atom_index| {
468 var atom = last_atom;494 var atom_index = last_atom_index;
469 while (true) {495 while (true) {
496 const atom = self.getAtom(atom_index);
470 const sym = atom.getSymbolPtr(self);497 const sym = atom.getSymbolPtr(self);
471 sym.value += diff;498 sym.value += diff;
472499
473 if (atom.prev) |prev| {500 if (atom.prev_index) |prev_index| {
474 atom = prev;501 atom_index = prev_index;
475 } else break;502 } else break;
476 }503 }
477 }504 }
...@@ -480,14 +507,15 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {...@@ -480,14 +507,15 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {
480 header.virtual_size = increased_size;507 header.virtual_size = increased_size;
481}508}
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 {
484 const tracy = trace(@src());511 const tracy = trace(@src());
485 defer tracy.end();512 defer tracy.end();
486513
514 const atom = self.getAtom(atom_index);
487 const sect_id = @enumToInt(atom.getSymbol(self).section_number) - 1;515 const sect_id = @enumToInt(atom.getSymbol(self).section_number) - 1;
488 const header = &self.sections.items(.header)[sect_id];516 const header = &self.sections.items(.header)[sect_id];
489 const free_list = &self.sections.items(.free_list)[sect_id];517 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];
491 const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size;519 const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size;
492520
493 // We use these to indicate our intention to update metadata, placing the new atom,521 // 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...@@ -495,7 +523,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
495 // It would be simpler to do it inside the for loop below, but that would cause a523 // It would be simpler to do it inside the for loop below, but that would cause a
496 // problem if an error was returned later in the function. So this action524 // problem if an error was returned later in the function. So this action
497 // is actually carried out at the end of the function, when errors are no longer possible.525 // 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;
499 var free_list_removal: ?usize = null;527 var free_list_removal: ?usize = null;
500528
501 // First we look for an appropriately sized free list node.529 // 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...@@ -503,7 +531,8 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
503 var vaddr = blk: {531 var vaddr = blk: {
504 var i: usize = 0;532 var i: usize = 0;
505 while (i < free_list.items.len) {533 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);
507 // We now have a pointer to a live atom that has too much capacity.536 // We now have a pointer to a live atom that has too much capacity.
508 // Is it enough that we could fit this new atom?537 // Is it enough that we could fit this new atom?
509 const sym = big_atom.getSymbol(self);538 const sym = big_atom.getSymbol(self);
...@@ -531,34 +560,43 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u...@@ -531,34 +560,43 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
531 const keep_free_list_node = remaining_capacity >= min_text_capacity;560 const keep_free_list_node = remaining_capacity >= min_text_capacity;
532561
533 // Set up the metadata to be updated, after errors are no longer possible.562 // Set up the metadata to be updated, after errors are no longer possible.
534 atom_placement = big_atom;563 atom_placement = big_atom_index;
535 if (!keep_free_list_node) {564 if (!keep_free_list_node) {
536 free_list_removal = i;565 free_list_removal = i;
537 }566 }
538 break :blk new_start_vaddr;567 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);
540 const last_symbol = last.getSymbol(self);570 const last_symbol = last.getSymbol(self);
541 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;571 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
542 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;572 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;
543 const new_start_vaddr = mem.alignForwardGeneric(u32, ideal_capacity_end_vaddr, alignment);573 const new_start_vaddr = mem.alignForwardGeneric(u32, ideal_capacity_end_vaddr, alignment);
544 atom_placement = last;574 atom_placement = last_index;
545 break :blk new_start_vaddr;575 break :blk new_start_vaddr;
546 } else {576 } else {
547 break :blk mem.alignForwardGeneric(u32, header.virtual_address, alignment);577 break :blk mem.alignForwardGeneric(u32, header.virtual_address, alignment);
548 }578 }
549 };579 };
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;
552 if (expand_section) {585 if (expand_section) {
553 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);586 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
554 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;587 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;
555 if (needed_size > sect_capacity) {588 if (needed_size > sect_capacity) {
556 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);589 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);
558 const sym = last_atom.getSymbol(self);592 const sym = last_atom.getSymbol(self);
559 break :blk (sym.value + last_atom.size) - header.virtual_address;593 break :blk (sym.value + last_atom.size) - header.virtual_address;
560 } else 0;594 } 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 });
562 const amt = try self.base.file.?.copyRangeAll(600 const amt = try self.base.file.?.copyRangeAll(
563 header.pointer_to_raw_data,601 header.pointer_to_raw_data,
564 self.base.file.?,602 self.base.file.?,
...@@ -577,26 +615,34 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u...@@ -577,26 +615,34 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
577615
578 header.virtual_size = @max(header.virtual_size, needed_size);616 header.virtual_size = @max(header.virtual_size, needed_size);
579 header.size_of_raw_data = needed_size;617 header.size_of_raw_data = needed_size;
580 maybe_last_atom.* = atom;618 maybe_last_atom_index.* = atom_index;
581 }619 }
582620
583 atom.size = new_atom_size;621 {
584 atom.alignment = alignment;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| {627 if (atom.prev_index) |prev_index| {
587 prev.next = atom.next;628 const prev = self.getAtomPtr(prev_index);
629 prev.next_index = atom.next_index;
588 }630 }
589 if (atom.next) |next| {631 if (atom.next_index) |next_index| {
590 next.prev = atom.prev;632 const next = self.getAtomPtr(next_index);
633 next.prev_index = atom.prev_index;
591 }634 }
592635
593 if (atom_placement) |big_atom| {636 if (atom_placement) |big_atom_index| {
594 atom.prev = big_atom;637 const big_atom = self.getAtomPtr(big_atom_index);
595 atom.next = big_atom.next;638 const atom_ptr = self.getAtomPtr(atom_index);
596 big_atom.next = atom;639 atom_ptr.prev_index = big_atom_index;
640 atom_ptr.next_index = big_atom.next_index;
641 big_atom.next_index = atom_index;
597 } else {642 } else {
598 atom.prev = null;643 const atom_ptr = self.getAtomPtr(atom_index);
599 atom.next = null;644 atom_ptr.prev_index = null;
645 atom_ptr.next_index = null;
600 }646 }
601 if (free_list_removal) |i| {647 if (free_list_removal) |i| {
602 _ = free_list.swapRemove(i);648 _ = free_list.swapRemove(i);
...@@ -701,24 +747,37 @@ pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 {...@@ -701,24 +747,37 @@ pub fn allocateImportEntry(self: *Coff, target: SymbolWithLoc) !u32 {
701 return index;747 return index;
702}748}
703749
704fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {750pub fn createAtom(self: *Coff) !Atom.Index {
705 const gpa = self.base.allocator;751 const gpa = self.base.allocator;
706 const atom = try gpa.create(Atom);752 const atom_index = @intCast(Atom.Index, self.atoms.items.len);
707 errdefer gpa.destroy(atom);753 const atom = try self.atoms.addOne(gpa);
708 atom.* = Atom.empty;754 const sym_index = try self.allocateSymbol();
709 try atom.ensureInitialized(self);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);
710 atom.size = @sizeOf(u64);771 atom.size = @sizeOf(u64);
711 atom.alignment = @alignOf(u64);772 atom.alignment = @alignOf(u64);
712773
713 try self.managed_atoms.append(gpa, atom);
714
715 const sym = atom.getSymbolPtr(self);774 const sym = atom.getSymbolPtr(self);
716 sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1);775 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
719 log.debug("allocated GOT atom at 0x{x}", .{sym.value});778 log.debug("allocated GOT atom at 0x{x}", .{sym.value});
720779
721 try atom.addRelocation(self, .{780 try Atom.addRelocation(self, atom_index, .{
722 .type = .direct,781 .type = .direct,
723 .target = target,782 .target = target,
724 .offset = 0,783 .offset = 0,
...@@ -732,49 +791,46 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {...@@ -732,49 +791,46 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
732 .UNDEFINED => @panic("TODO generate a binding for undefined GOT target"),791 .UNDEFINED => @panic("TODO generate a binding for undefined GOT target"),
733 .ABSOLUTE => {},792 .ABSOLUTE => {},
734 .DEBUG => unreachable, // not possible793 .DEBUG => unreachable, // not possible
735 else => try atom.addBaseRelocation(self, 0),794 else => try Atom.addBaseRelocation(self, atom_index, 0),
736 }795 }
737796
738 return atom;797 return atom_index;
739}798}
740799
741fn createImportAtom(self: *Coff) !*Atom {800fn createImportAtom(self: *Coff) !Atom.Index {
742 const gpa = self.base.allocator;801 const atom_index = try self.createAtom();
743 const atom = try gpa.create(Atom);802 const atom = self.getAtomPtr(atom_index);
744 errdefer gpa.destroy(atom);
745 atom.* = Atom.empty;
746 try atom.ensureInitialized(self);
747 atom.size = @sizeOf(u64);803 atom.size = @sizeOf(u64);
748 atom.alignment = @alignOf(u64);804 atom.alignment = @alignOf(u64);
749805
750 try self.managed_atoms.append(gpa, atom);
751
752 const sym = atom.getSymbolPtr(self);806 const sym = atom.getSymbolPtr(self);
753 sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1);807 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
756 log.debug("allocated import atom at 0x{x}", .{sym.value});810 log.debug("allocated import atom at 0x{x}", .{sym.value});
757811
758 return atom;812 return atom_index;
759}813}
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);
762 const sym = atom.getSymbol(self);817 const sym = atom.getSymbol(self);
763 const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value;818 const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value;
764 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);819 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
765 if (!need_realloc) return sym.value;820 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);
767}822}
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 {
770 _ = self;825 _ = self;
771 _ = atom;826 _ = atom_index;
772 _ = new_block_size;827 _ = new_block_size;
773 // TODO check the new capacity, and if it crosses the size threshold into a big enough828 // TODO check the new capacity, and if it crosses the size threshold into a big enough
774 // capacity, insert a free list node for it.829 // capacity, insert a free list node for it.
775}830}
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);
778 const sym = atom.getSymbol(self);834 const sym = atom.getSymbol(self);
779 const section = self.sections.get(@enumToInt(sym.section_number) - 1);835 const section = self.sections.get(@enumToInt(sym.section_number) - 1);
780 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;836 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 {...@@ -784,18 +840,18 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void {
784 file_offset + code.len,840 file_offset + code.len,
785 });841 });
786 try self.base.file.?.pwriteAll(code, file_offset);842 try self.base.file.?.pwriteAll(code, file_offset);
787 try self.resolveRelocs(atom);843 try self.resolveRelocs(atom_index);
788}844}
789845
790fn writePtrWidthAtom(self: *Coff, atom: *Atom) !void {846fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {
791 switch (self.ptr_width) {847 switch (self.ptr_width) {
792 .p32 => {848 .p32 => {
793 var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32);849 var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32);
794 try self.writeAtom(atom, &buffer);850 try self.writeAtom(atom_index, &buffer);
795 },851 },
796 .p64 => {852 .p64 => {
797 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);853 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
798 try self.writeAtom(atom, &buffer);854 try self.writeAtom(atom_index, &buffer);
799 },855 },
800 }856 }
801}857}
...@@ -815,7 +871,8 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {...@@ -815,7 +871,8 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
815 var it = self.relocs.valueIterator();871 var it = self.relocs.valueIterator();
816 while (it.next()) |relocs| {872 while (it.next()) |relocs| {
817 for (relocs.items) |*reloc| {873 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);
819 const target_sym = target_atom.getSymbol(self);876 const target_sym = target_atom.getSymbol(self);
820 if (target_sym.value < addr) continue;877 if (target_sym.value < addr) continue;
821 reloc.dirty = true;878 reloc.dirty = true;
...@@ -823,24 +880,26 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {...@@ -823,24 +880,26 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
823 }880 }
824}881}
825882
826fn resolveRelocs(self: *Coff, atom: *Atom) !void {883fn resolveRelocs(self: *Coff, atom_index: Atom.Index) !void {
827 const relocs = self.relocs.get(atom) orelse return;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
831 for (relocs.items) |*reloc| {888 for (relocs.items) |*reloc| {
832 if (!reloc.dirty) continue;889 if (!reloc.dirty) continue;
833 try reloc.resolve(atom, self);890 try reloc.resolve(atom_index, self);
834 }891 }
835}892}
836893
837fn freeAtom(self: *Coff, atom: *Atom) void {894fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
838 log.debug("freeAtom {*}", .{atom});895 log.debug("freeAtom {d}", .{atom_index});
896
897 const gpa = self.base.allocator;
839898
840 // Remove any relocs and base relocs associated with this Atom899 // 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);
844 const sym = atom.getSymbol(self);903 const sym = atom.getSymbol(self);
845 const sect_id = @enumToInt(sym.section_number) - 1;904 const sect_id = @enumToInt(sym.section_number) - 1;
846 const free_list = &self.sections.items(.free_list)[sect_id];905 const free_list = &self.sections.items(.free_list)[sect_id];
...@@ -849,45 +908,46 @@ fn freeAtom(self: *Coff, atom: *Atom) void {...@@ -849,45 +908,46 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
849 var i: usize = 0;908 var i: usize = 0;
850 // TODO turn free_list into a hash map909 // TODO turn free_list into a hash map
851 while (i < free_list.items.len) {910 while (i < free_list.items.len) {
852 if (free_list.items[i] == atom) {911 if (free_list.items[i] == atom_index) {
853 _ = free_list.swapRemove(i);912 _ = free_list.swapRemove(i);
854 continue;913 continue;
855 }914 }
856 if (free_list.items[i] == atom.prev) {915 if (free_list.items[i] == atom.prev_index) {
857 already_have_free_list_node = true;916 already_have_free_list_node = true;
858 }917 }
859 i += 1;918 i += 1;
860 }919 }
861 }920 }
862921
863 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];922 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
864 if (maybe_last_atom.*) |last_atom| {923 if (maybe_last_atom_index.*) |last_atom_index| {
865 if (last_atom == atom) {924 if (last_atom_index == atom_index) {
866 if (atom.prev) |prev| {925 if (atom.prev_index) |prev_index| {
867 // TODO shrink the section size here926 // TODO shrink the section size here
868 maybe_last_atom.* = prev;927 maybe_last_atom_index.* = prev_index;
869 } else {928 } else {
870 maybe_last_atom.* = null;929 maybe_last_atom_index.* = null;
871 }930 }
872 }931 }
873 }932 }
874933
875 if (atom.prev) |prev| {934 if (atom.prev_index) |prev_index| {
876 prev.next = atom.next;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)) {
879 // The free list is heuristics, it doesn't have to be perfect, so we can939 // The free list is heuristics, it doesn't have to be perfect, so we can
880 // ignore the OOM here.940 // ignore the OOM here.
881 free_list.append(gpa, prev) catch {};941 free_list.append(gpa, prev_index) catch {};
882 }942 }
883 } else {943 } else {
884 atom.prev = null;944 self.getAtomPtr(atom_index).prev_index = null;
885 }945 }
886946
887 if (atom.next) |next| {947 if (atom.next_index) |next_index| {
888 next.prev = atom.prev;948 self.getAtomPtr(next_index).prev_index = atom.prev_index;
889 } else {949 } else {
890 atom.next = null;950 self.getAtomPtr(atom_index).next_index = null;
891 }951 }
892952
893 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.953 // 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 {...@@ -910,7 +970,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
910 self.locals.items[sym_index].section_number = .UNDEFINED;970 self.locals.items[sym_index].section_number = .UNDEFINED;
911 _ = self.atom_by_index_table.remove(sym_index);971 _ = self.atom_by_index_table.remove(sym_index);
912 log.debug(" adding local symbol index {d} to free list", .{sym_index});972 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;
914}974}
915975
916pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {976pub 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...@@ -927,15 +987,10 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
927987
928 const decl_index = func.owner_decl;988 const decl_index = func.owner_decl;
929 const decl = module.declPtr(decl_index);989 const decl = module.declPtr(decl_index);
930 const atom = &decl.link.coff;990
931 try atom.ensureInitialized(self);991 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
932 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);992 self.freeUnnamedConsts(decl_index);
933 if (gop.found_existing) {993 Atom.freeRelocations(self, atom_index);
934 self.freeUnnamedConsts(decl_index);
935 self.freeRelocationsForAtom(&decl.link.coff);
936 } else {
937 gop.value_ptr.* = null;
938 }
939994
940 var code_buffer = std.ArrayList(u8).init(self.base.allocator);995 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
941 defer code_buffer.deinit();996 defer code_buffer.deinit();
...@@ -979,11 +1034,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -979,11 +1034,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
979 }1034 }
980 const unnamed_consts = gop.value_ptr;1035 const unnamed_consts = gop.value_ptr;
9811036
982 const atom = try gpa.create(Atom);1037 const atom_index = try self.createAtom();
983 errdefer gpa.destroy(atom);
984 atom.* = Atom.empty;
985 try atom.ensureInitialized(self);
986 try self.managed_atoms.append(gpa, atom);
9871038
988 const sym_name = blk: {1039 const sym_name = blk: {
989 const decl_name = try decl.getFullyQualifiedName(mod);1040 const decl_name = try decl.getFullyQualifiedName(mod);
...@@ -993,11 +1044,15 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -993,11 +1044,15 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
993 break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });1044 break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
994 };1045 };
995 defer gpa.free(sym_name);1046 defer gpa.free(sym_name);
996 try self.setSymbolName(atom.getSymbolPtr(self), sym_name);1047 {
997 atom.getSymbolPtr(self).section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1);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
999 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{1054 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().?,
1001 });1056 });
1002 const code = switch (res) {1057 const code = switch (res) {
1003 .ok => code_buffer.items,1058 .ok => code_buffer.items,
...@@ -1010,17 +1065,18 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -1010,17 +1065,18 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
1010 };1065 };
10111066
1012 const required_alignment = tv.ty.abiAlignment(self.base.options.target);1067 const required_alignment = tv.ty.abiAlignment(self.base.options.target);
1068 const atom = self.getAtomPtr(atom_index);
1013 atom.alignment = required_alignment;1069 atom.alignment = required_alignment;
1014 atom.size = @intCast(u32, code.len);1070 atom.size = @intCast(u32, code.len);
1015 atom.getSymbolPtr(self).value = try self.allocateAtom(atom, atom.size, atom.alignment);1071 atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, atom.alignment);
1016 errdefer self.freeAtom(atom);1072 errdefer self.freeAtom(atom_index);
10171073
1018 try unnamed_consts.append(gpa, atom);1074 try unnamed_consts.append(gpa, atom_index);
10191075
1020 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value });1076 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value });
1021 log.debug(" (required alignment 0x{x})", .{required_alignment});1077 log.debug(" (required alignment 0x{x})", .{required_alignment});
10221078
1023 try self.writeAtom(atom, code);1079 try self.writeAtom(atom_index, code);
10241080
1025 return atom.getSymbolIndex().?;1081 return atom.getSymbolIndex().?;
1026}1082}
...@@ -1047,14 +1103,9 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1047,14 +1103,9 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1047 }1103 }
1048 }1104 }
10491105
1050 const atom = &decl.link.coff;1106 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
1051 try atom.ensureInitialized(self);1107 Atom.freeRelocations(self, atom_index);
1052 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);1108 const atom = self.getAtom(atom_index);
1053 if (gop.found_existing) {
1054 self.freeRelocationsForAtom(atom);
1055 } else {
1056 gop.value_ptr.* = null;
1057 }
10581109
1059 var code_buffer = std.ArrayList(u8).init(self.base.allocator);1110 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
1060 defer code_buffer.deinit();1111 defer code_buffer.deinit();
...@@ -1064,7 +1115,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1064,7 +1115,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1064 .ty = decl.ty,1115 .ty = decl.ty,
1065 .val = decl_val,1116 .val = decl_val,
1066 }, &code_buffer, .none, .{1117 }, &code_buffer, .none, .{
1067 .parent_atom_index = decl.link.coff.getSymbolIndex().?,1118 .parent_atom_index = atom.getSymbolIndex().?,
1068 });1119 });
1069 const code = switch (res) {1120 const code = switch (res) {
1070 .ok => code_buffer.items,1121 .ok => code_buffer.items,
...@@ -1082,7 +1133,20 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1082,7 +1133,20 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1082 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));1133 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
1083}1134}
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);
1086 const ty = decl.ty;1150 const ty = decl.ty;
1087 const zig_ty = ty.zigTypeTag();1151 const zig_ty = ty.zigTypeTag();
1088 const val = decl.val;1152 const val = decl.val;
...@@ -1117,14 +1181,11 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,...@@ -1117,14 +1181,11 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
1117 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });1181 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
1118 const required_alignment = decl.getAlignment(self.base.options.target);1182 const required_alignment = decl.getAlignment(self.base.options.target);
11191183
1120 const decl_ptr = self.decls.getPtr(decl_index).?;1184 const decl_metadata = self.decls.get(decl_index).?;
1121 if (decl_ptr.* == null) {1185 const atom_index = decl_metadata.atom;
1122 decl_ptr.* = self.getDeclOutputSection(decl);1186 const atom = self.getAtom(atom_index);
1123 }1187 const sect_index = decl_metadata.section;
1124 const sect_index = decl_ptr.*.?;
1125
1126 const code_len = @intCast(u32, code.len);1188 const code_len = @intCast(u32, code.len);
1127 const atom = &decl.link.coff;
11281189
1129 if (atom.size != 0) {1190 if (atom.size != 0) {
1130 const sym = atom.getSymbolPtr(self);1191 const sym = atom.getSymbolPtr(self);
...@@ -1135,7 +1196,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,...@@ -1135,7 +1196,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
1135 const capacity = atom.capacity(self);1196 const capacity = atom.capacity(self);
1136 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);1197 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
1137 if (need_realloc) {1198 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);
1139 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });1200 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });
1140 log.debug(" (required alignment 0x{x}", .{required_alignment});1201 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,...@@ -1143,49 +1204,43 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
1143 sym.value = vaddr;1204 sym.value = vaddr;
1144 log.debug(" (updating GOT entry)", .{});1205 log.debug(" (updating GOT entry)", .{});
1145 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };1206 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).?;
1147 self.markRelocsDirtyByTarget(got_target);1208 self.markRelocsDirtyByTarget(got_target);
1148 try self.writePtrWidthAtom(got_atom);1209 try self.writePtrWidthAtom(got_atom_index);
1149 }1210 }
1150 } else if (code_len < atom.size) {1211 } else if (code_len < atom.size) {
1151 self.shrinkAtom(atom, code_len);1212 self.shrinkAtom(atom_index, code_len);
1152 }1213 }
1153 atom.size = code_len;1214 self.getAtomPtr(atom_index).size = code_len;
1154 } else {1215 } else {
1155 const sym = atom.getSymbolPtr(self);1216 const sym = atom.getSymbolPtr(self);
1156 try self.setSymbolName(sym, decl_name);1217 try self.setSymbolName(sym, decl_name);
1157 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);1218 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
1158 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };1219 sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
11591220
1160 const vaddr = try self.allocateAtom(atom, code_len, required_alignment);1221 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
1161 errdefer self.freeAtom(atom);1222 errdefer self.freeAtom(atom_index);
1162 log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr });1223 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;
1164 sym.value = vaddr;1225 sym.value = vaddr;
11651226
1166 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };1227 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };
1167 const got_index = try self.allocateGotEntry(got_target);1228 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);
1169 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;1231 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
1170 try self.writePtrWidthAtom(got_atom);1232 try self.writePtrWidthAtom(got_atom_index);
1171 }1233 }
11721234
1173 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());1235 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
1174 try self.writeAtom(atom, code);1236 try self.writeAtom(atom_index, 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);
1182}1237}
11831238
1184fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void {1239fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void {
1185 const gpa = self.base.allocator;1240 const gpa = self.base.allocator;
1186 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;1241 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
1187 for (unnamed_consts.items) |atom| {1242 for (unnamed_consts.items) |atom_index| {
1188 self.freeAtom(atom);1243 self.freeAtom(atom_index);
1189 }1244 }
1190 unnamed_consts.clearAndFree(gpa);1245 unnamed_consts.clearAndFree(gpa);
1191}1246}
...@@ -1200,11 +1255,11 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {...@@ -1200,11 +1255,11 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
12001255
1201 log.debug("freeDecl {*}", .{decl});1256 log.debug("freeDecl {*}", .{decl});
12021257
1203 if (self.decls.fetchRemove(decl_index)) |kv| {1258 if (self.decls.fetchRemove(decl_index)) |const_kv| {
1204 if (kv.value) |_| {1259 var kv = const_kv;
1205 self.freeAtom(&decl.link.coff);1260 self.freeAtom(kv.value.atom);
1206 self.freeUnnamedConsts(decl_index);1261 self.freeUnnamedConsts(decl_index);
1207 }1262 kv.value.exports.deinit(self.base.allocator);
1208 }1263 }
1209}1264}
12101265
...@@ -1257,16 +1312,10 @@ pub fn updateDeclExports(...@@ -1257,16 +1312,10 @@ pub fn updateDeclExports(
1257 const gpa = self.base.allocator;1312 const gpa = self.base.allocator;
12581313
1259 const decl = module.declPtr(decl_index);1314 const decl = module.declPtr(decl_index);
1260 const atom = &decl.link.coff;1315 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
12611316 const atom = self.getAtom(atom_index);
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
1269 const decl_sym = atom.getSymbol(self);1317 const decl_sym = atom.getSymbol(self);
1318 const decl_metadata = self.decls.getPtr(decl_index).?;
12701319
1271 for (exports) |exp| {1320 for (exports) |exp| {
1272 log.debug("adding new export '{s}'", .{exp.options.name});1321 log.debug("adding new export '{s}'", .{exp.options.name});
...@@ -1301,9 +1350,9 @@ pub fn updateDeclExports(...@@ -1301,9 +1350,9 @@ pub fn updateDeclExports(
1301 continue;1350 continue;
1302 }1351 }
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: {
1305 const sym_index = try self.allocateSymbol();1354 const sym_index = try self.allocateSymbol();
1306 exp.link.coff.sym_index = sym_index;1355 try decl_metadata.exports.append(gpa, sym_index);
1307 break :blk sym_index;1356 break :blk sym_index;
1308 };1357 };
1309 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };1358 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
...@@ -1326,16 +1375,15 @@ pub fn updateDeclExports(...@@ -1326,16 +1375,15 @@ pub fn updateDeclExports(
1326 }1375 }
1327}1376}
13281377
1329pub fn deleteExport(self: *Coff, exp: Export) void {1378pub fn deleteDeclExport(self: *Coff, decl_index: Module.Decl.Index, name: []const u8) void {
1330 if (self.llvm_object) |_| return;1379 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
1333 const gpa = self.base.allocator;1383 const gpa = self.base.allocator;
13341384 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
1335 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1336 const sym = self.getSymbolPtr(sym_loc);1385 const sym = self.getSymbolPtr(sym_loc);
1337 const sym_name = self.getSymbolName(sym_loc);1386 log.debug("deleting export '{s}'", .{name});
1338 log.debug("deleting export '{s}'", .{sym_name});
1339 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);1387 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
1340 sym.* = .{1388 sym.* = .{
1341 .name = [_]u8{0} ** 8,1389 .name = [_]u8{0} ** 8,
...@@ -1345,9 +1393,9 @@ pub fn deleteExport(self: *Coff, exp: Export) void {...@@ -1345,9 +1393,9 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
1345 .storage_class = .NULL,1393 .storage_class = .NULL,
1346 .number_of_aux_symbols = 0,1394 .number_of_aux_symbols = 0,
1347 };1395 };
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| {
1351 defer gpa.free(entry.key);1399 defer gpa.free(entry.key);
1352 self.globals_free_list.append(gpa, entry.value) catch {};1400 self.globals_free_list.append(gpa, entry.value) catch {};
1353 self.globals.items[entry.value] = .{1401 self.globals.items[entry.value] = .{
...@@ -1355,6 +1403,8 @@ pub fn deleteExport(self: *Coff, exp: Export) void {...@@ -1355,6 +1403,8 @@ pub fn deleteExport(self: *Coff, exp: Export) void {
1355 .file = null,1403 .file = null,
1356 };1404 };
1357 }1405 }
1406
1407 sym_index.* = 0;
1358}1408}
13591409
1360fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {1410fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
...@@ -1419,9 +1469,10 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1419,9 +1469,10 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1419 if (self.imports_table.contains(global)) continue;1469 if (self.imports_table.contains(global)) continue;
14201470
1421 const import_index = try self.allocateImportEntry(global);1471 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);
1423 self.imports.items[import_index].sym_index = import_atom.getSymbolIndex().?;1474 self.imports.items[import_index].sym_index = import_atom.getSymbolIndex().?;
1424 try self.writePtrWidthAtom(import_atom);1475 try self.writePtrWidthAtom(import_atom_index);
1425 }1476 }
14261477
1427 if (build_options.enable_logging) {1478 if (build_options.enable_logging) {
...@@ -1455,22 +1506,14 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1455,22 +1506,14 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1455 }1506 }
1456}1507}
14571508
1458pub fn getDeclVAddr(1509pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
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
1466 assert(self.llvm_object == null);1510 assert(self.llvm_object == null);
14671511
1468 try decl.link.coff.ensureInitialized(self);1512 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
1469 const sym_index = decl.link.coff.getSymbolIndex().?;1513 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
14701514 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
1471 const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
1472 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };1515 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1473 try atom.addRelocation(self, .{1516 try Atom.addRelocation(self, atom_index, .{
1474 .type = .direct,1517 .type = .direct,
1475 .target = target,1518 .target = target,
1476 .offset = @intCast(u32, reloc_info.offset),1519 .offset = @intCast(u32, reloc_info.offset),
...@@ -1478,7 +1521,7 @@ pub fn getDeclVAddr(...@@ -1478,7 +1521,7 @@ pub fn getDeclVAddr(
1478 .pcrel = false,1521 .pcrel = false,
1479 .length = 3,1522 .length = 3,
1480 });1523 });
1481 try atom.addBaseRelocation(self, @intCast(u32, reloc_info.offset));1524 try Atom.addBaseRelocation(self, atom_index, @intCast(u32, reloc_info.offset));
14821525
1483 return 0;1526 return 0;
1484}1527}
...@@ -1505,10 +1548,10 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {...@@ -1505,10 +1548,10 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
1505 return global_index;1548 return global_index;
1506}1549}
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 {
1509 _ = self;1552 _ = self;
1510 _ = module;1553 _ = module;
1511 _ = decl;1554 _ = decl_index;
1512 log.debug("TODO implement updateDeclLineNumber", .{});1555 log.debug("TODO implement updateDeclLineNumber", .{});
1513}1556}
15141557
...@@ -1529,7 +1572,8 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1529,7 +1572,8 @@ fn writeBaseRelocations(self: *Coff) !void {
15291572
1530 var it = self.base_relocs.iterator();1573 var it = self.base_relocs.iterator();
1531 while (it.next()) |entry| {1574 while (it.next()) |entry| {
1532 const atom = entry.key_ptr.*;1575 const atom_index = entry.key_ptr.*;
1576 const atom = self.getAtom(atom_index);
1533 const offsets = entry.value_ptr.*;1577 const offsets = entry.value_ptr.*;
15341578
1535 for (offsets.items) |offset| {1579 for (offsets.items) |offset| {
...@@ -1613,7 +1657,8 @@ fn writeImportTable(self: *Coff) !void {...@@ -1613,7 +1657,8 @@ fn writeImportTable(self: *Coff) !void {
1613 const gpa = self.base.allocator;1657 const gpa = self.base.allocator;
16141658
1615 const section = self.sections.get(self.idata_section_index.?);1659 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
1618 const iat_rva = section.header.virtual_address;1663 const iat_rva = section.header.virtual_address;
1619 const iat_size = last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer1664 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...@@ -2051,27 +2096,37 @@ pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult
2051 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };2096 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
2052}2097}
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
2054/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.2109/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.
2055/// Returns null on failure.2110/// Returns null on failure.
2056pub fn getAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {2111pub fn getAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
2057 assert(sym_loc.file == null); // TODO linking with object files2112 assert(sym_loc.file == null); // TODO linking with object files
2058 return self.atom_by_index_table.get(sym_loc.sym_index);2113 return self.atom_by_index_table.get(sym_loc.sym_index);
2059}2114}
20602115
2061/// Returns GOT atom that references `sym_loc` if one exists.2116/// Returns GOT atom that references `sym_loc` if one exists.
2062/// Returns null otherwise.2117/// Returns null otherwise.
2063pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {2118pub fn getGotAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
2064 const got_index = self.got_entries_table.get(sym_loc) orelse return null;2119 const got_index = self.got_entries_table.get(sym_loc) orelse return null;
2065 const got_entry = self.got_entries.items[got_index];2120 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 });
2067}2122}
20682123
2069/// Returns import atom that references `sym_loc` if one exists.2124/// Returns import atom that references `sym_loc` if one exists.
2070/// Returns null otherwise.2125/// Returns null otherwise.
2071pub fn getImportAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {2126pub fn getImportAtomIndexForSymbol(self: *const Coff, sym_loc: SymbolWithLoc) ?Atom.Index {
2072 const imports_index = self.imports_table.get(sym_loc) orelse return null;2127 const imports_index = self.imports_table.get(sym_loc) orelse return null;
2073 const imports_entry = self.imports.items[imports_index];2128 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 });
2075}2130}
20762131
2077fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {2132fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {
src/link/Coff/Atom.zig+24-24
...@@ -27,23 +27,10 @@ alignment: u32,...@@ -27,23 +27,10 @@ alignment: u32,
2727
28/// Points to the previous and next neighbors, based on the `text_offset`.28/// Points to the previous and next neighbors, based on the `text_offset`.
29/// This can be used to find, for example, the capacity of this `Atom`.29/// This can be used to find, for example, the capacity of this `Atom`.
30prev: ?*Atom,30prev_index: ?Index,
31next: ?*Atom,31next_index: ?Index,
3232
33pub const empty = Atom{33pub const Index = u32;
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}
4734
48pub fn getSymbolIndex(self: Atom) ?u32 {35pub fn getSymbolIndex(self: Atom) ?u32 {
49 if (self.sym_index == 0) return null;36 if (self.sym_index == 0) return null;
...@@ -85,7 +72,8 @@ pub fn getName(self: Atom, coff_file: *const Coff) []const u8 {...@@ -85,7 +72,8 @@ pub fn getName(self: Atom, coff_file: *const Coff) []const u8 {
85/// Returns how much room there is to grow in virtual address space.72/// Returns how much room there is to grow in virtual address space.
86pub fn capacity(self: Atom, coff_file: *const Coff) u32 {73pub fn capacity(self: Atom, coff_file: *const Coff) u32 {
87 const self_sym = self.getSymbol(coff_file);74 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);
89 const next_sym = next.getSymbol(coff_file);77 const next_sym = next.getSymbol(coff_file);
90 return next_sym.value - self_sym.value;78 return next_sym.value - self_sym.value;
91 } else {79 } else {
...@@ -97,7 +85,8 @@ pub fn capacity(self: Atom, coff_file: *const Coff) u32 {...@@ -97,7 +85,8 @@ pub fn capacity(self: Atom, coff_file: *const Coff) u32 {
9785
98pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {86pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
99 // No need to keep a free list node for the last atom.87 // 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);
101 const self_sym = self.getSymbol(coff_file);90 const self_sym = self.getSymbol(coff_file);
102 const next_sym = next.getSymbol(coff_file);91 const next_sym = next.getSymbol(coff_file);
103 const cap = next_sym.value - self_sym.value;92 const cap = next_sym.value - self_sym.value;
...@@ -107,22 +96,33 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {...@@ -107,22 +96,33 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
107 return surplus >= Coff.min_text_capacity;96 return surplus >= Coff.min_text_capacity;
108}97}
10998
110pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Relocation) !void {99pub fn addRelocation(coff_file: *Coff, atom_index: Index, reloc: Relocation) !void {
111 const gpa = coff_file.base.allocator;100 const gpa = coff_file.base.allocator;
112 log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.type), reloc.target.sym_index });101 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);
114 if (!gop.found_existing) {103 if (!gop.found_existing) {
115 gop.value_ptr.* = .{};104 gop.value_ptr.* = .{};
116 }105 }
117 try gop.value_ptr.append(gpa, reloc);106 try gop.value_ptr.append(gpa, reloc);
118}107}
119108
120pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void {109pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void {
121 const gpa = coff_file.base.allocator;110 const gpa = coff_file.base.allocator;
122 log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ offset, self.sym_index });111 log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{
123 const gop = try coff_file.base_relocs.getOrPut(gpa, self);112 offset,
113 coff_file.getAtom(atom_index).getSymbolIndex().?,
114 });
115 const gop = try coff_file.base_relocs.getOrPut(gpa, atom_index);
124 if (!gop.found_existing) {116 if (!gop.found_existing) {
125 gop.value_ptr.* = .{};117 gop.value_ptr.* = .{};
126 }118 }
127 try gop.value_ptr.append(gpa, offset);119 try gop.value_ptr.append(gpa, offset);
128}120}
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,...@@ -46,33 +46,35 @@ length: u2,
46dirty: bool = true,46dirty: bool = true,
4747
48/// Returns an Atom which is the target node of this relocation edge (if any).48/// 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 {
50 switch (self.type) {50 switch (self.type) {
51 .got,51 .got,
52 .got_page,52 .got_page,
53 .got_pageoff,53 .got_pageoff,
54 => return coff_file.getGotAtomForSymbol(self.target),54 => return coff_file.getGotAtomIndexForSymbol(self.target),
5555
56 .direct,56 .direct,
57 .page,57 .page,
58 .pageoff,58 .pageoff,
59 => return coff_file.getAtomForSymbol(self.target),59 => return coff_file.getAtomIndexForSymbol(self.target),
6060
61 .import,61 .import,
62 .import_page,62 .import_page,
63 .import_pageoff,63 .import_pageoff,
64 => return coff_file.getImportAtomForSymbol(self.target),64 => return coff_file.getImportAtomIndexForSymbol(self.target),
65 }65 }
66}66}
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);
69 const source_sym = atom.getSymbol(coff_file);70 const source_sym = atom.getSymbol(coff_file);
70 const source_section = coff_file.sections.get(@enumToInt(source_sym.section_number) - 1).header;71 const source_section = coff_file.sections.get(@enumToInt(source_sym.section_number) - 1).header;
71 const source_vaddr = source_sym.value + self.offset;72 const source_vaddr = source_sym.value + self.offset;
7273
73 const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address;74 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);
76 const target_vaddr = target_atom.getSymbol(coff_file).value;78 const target_vaddr = target_atom.getSymbol(coff_file).value;
77 const target_vaddr_with_addend = target_vaddr + self.addend;79 const target_vaddr_with_addend = target_vaddr + self.addend;
7880
...@@ -107,7 +109,7 @@ const Context = struct {...@@ -107,7 +109,7 @@ const Context = struct {
107 image_base: u64,109 image_base: u64,
108};110};
109111
110fn resolveAarch64(self: *Relocation, ctx: Context, coff_file: *Coff) !void {112fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {
111 var buffer: [@sizeOf(u64)]u8 = undefined;113 var buffer: [@sizeOf(u64)]u8 = undefined;
112 switch (self.length) {114 switch (self.length) {
113 2 => {115 2 => {
...@@ -197,7 +199,7 @@ fn resolveAarch64(self: *Relocation, ctx: Context, coff_file: *Coff) !void {...@@ -197,7 +199,7 @@ fn resolveAarch64(self: *Relocation, ctx: Context, coff_file: *Coff) !void {
197 }199 }
198}200}
199201
200fn resolveX86(self: *Relocation, ctx: Context, coff_file: *Coff) !void {202fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void {
201 switch (self.type) {203 switch (self.type) {
202 .got_page => unreachable,204 .got_page => unreachable,
203 .got_pageoff => unreachable,205 .got_pageoff => unreachable,
src/link/Dwarf.zig+320-259
...@@ -18,31 +18,36 @@ const LinkBlock = File.LinkBlock;...@@ -18,31 +18,36 @@ const LinkBlock = File.LinkBlock;
18const LinkFn = File.LinkFn;18const LinkFn = File.LinkFn;
19const LinkerLoad = @import("../codegen.zig").LinkerLoad;19const LinkerLoad = @import("../codegen.zig").LinkerLoad;
20const Module = @import("../Module.zig");20const Module = @import("../Module.zig");
21const Value = @import("../value.zig").Value;21const StringTable = @import("strtab.zig").StringTable;
22const Type = @import("../type.zig").Type;22const Type = @import("../type.zig").Type;
23const Value = @import("../value.zig").Value;
2324
24allocator: Allocator,25allocator: Allocator,
25bin_file: *File,26bin_file: *File,
26ptr_width: PtrWidth,27ptr_width: PtrWidth,
27target: std.Target,28target: std.Target,
2829
29/// A list of `File.LinkFn` whose Line Number Programs have surplus capacity.30/// A list of `Atom`s whose Line Number Programs have surplus capacity.
30/// This is the same concept as `text_block_free_list`; see those doc comments.31/// This is the same concept as `Section.free_list` in Elf; see those doc comments.
31dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{},32src_fn_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},
32dbg_line_fn_first: ?*SrcFn = null,33src_fn_first_index: ?Atom.Index = null,
33dbg_line_fn_last: ?*SrcFn = null,34src_fn_last_index: ?Atom.Index = null,
35src_fns: std.ArrayListUnmanaged(Atom) = .{},
36src_fn_decls: AtomTable = .{},
3437
35/// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity.38/// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity.
36/// This is the same concept as `text_block_free_list`; see those doc comments.39/// This is the same concept as `text_block_free_list`; see those doc comments.
37atom_free_list: std.AutoHashMapUnmanaged(*Atom, void) = .{},40di_atom_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},
38atom_first: ?*Atom = null,41di_atom_first_index: ?Atom.Index = null,
39atom_last: ?*Atom = null,42di_atom_last_index: ?Atom.Index = null,
43di_atoms: std.ArrayListUnmanaged(Atom) = .{},
44di_atom_decls: AtomTable = .{},
4045
41abbrev_table_offset: ?u64 = null,46abbrev_table_offset: ?u64 = null,
4247
43/// TODO replace with InternPool48/// TODO replace with InternPool
44/// Table of debug symbol names.49/// Table of debug symbol names.
45strtab: std.ArrayListUnmanaged(u8) = .{},50strtab: StringTable(.strtab) = .{},
4651
47/// Quick lookup array of all defined source files referenced by at least one Decl.52/// Quick lookup array of all defined source files referenced by at least one Decl.
48/// They will end up in the DWARF debug_line header as two lists:53/// They will end up in the DWARF debug_line header as two lists:
...@@ -50,22 +55,23 @@ strtab: std.ArrayListUnmanaged(u8) = .{},...@@ -50,22 +55,23 @@ strtab: std.ArrayListUnmanaged(u8) = .{},
50/// * []file_names55/// * []file_names
51di_files: std.AutoArrayHashMapUnmanaged(*const Module.File, void) = .{},56di_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
58global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},58global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
5959
60pub const Atom = struct {60const AtomTable = std.AutoHashMapUnmanaged(Module.Decl.Index, Atom.Index);
61 /// Previous/next linked list pointers.61
62 /// This is the linked list node for this Decl's corresponding .debug_info tag.62const Atom = struct {
63 prev: ?*Atom,63 /// Offset into .debug_info pointing to the tag for this Decl, or
64 next: ?*Atom,64 /// offset from the beginning of the Debug Line Program header that contains this function.
65 /// Offset into .debug_info pointing to the tag for this Decl.
66 off: u32,65 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.
68 len: u32,69 len: u32,
70
71 prev_index: ?Index,
72 next_index: ?Index,
73
74 pub const Index = u32;
69};75};
7076
71/// Represents state of the analysed Decl.77/// Represents state of the analysed Decl.
...@@ -75,6 +81,7 @@ pub const Atom = struct {...@@ -75,6 +81,7 @@ pub const Atom = struct {
75pub const DeclState = struct {81pub const DeclState = struct {
76 gpa: Allocator,82 gpa: Allocator,
77 mod: *Module,83 mod: *Module,
84 di_atom_decls: *const AtomTable,
78 dbg_line: std.ArrayList(u8),85 dbg_line: std.ArrayList(u8),
79 dbg_info: std.ArrayList(u8),86 dbg_info: std.ArrayList(u8),
80 abbrev_type_arena: std.heap.ArenaAllocator,87 abbrev_type_arena: std.heap.ArenaAllocator,
...@@ -88,10 +95,11 @@ pub const DeclState = struct {...@@ -88,10 +95,11 @@ pub const DeclState = struct {
88 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},95 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
89 exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{},96 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 {
92 return .{99 return .{
93 .gpa = gpa,100 .gpa = gpa,
94 .mod = mod,101 .mod = mod,
102 .di_atom_decls = di_atom_decls,
95 .dbg_line = std.ArrayList(u8).init(gpa),103 .dbg_line = std.ArrayList(u8).init(gpa),
96 .dbg_info = std.ArrayList(u8).init(gpa),104 .dbg_info = std.ArrayList(u8).init(gpa),
97 .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),105 .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),
...@@ -119,11 +127,11 @@ pub const DeclState = struct {...@@ -119,11 +127,11 @@ pub const DeclState = struct {
119127
120 /// Adds local type relocation of the form: @offset => @this + addend128 /// Adds local type relocation of the form: @offset => @this + addend
121 /// @this signifies the offset within the .debug_abbrev section of the containing atom.129 /// @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 {
123 log.debug("{x}: @this + {x}", .{ offset, addend });131 log.debug("{x}: @this + {x}", .{ offset, addend });
124 try self.abbrev_relocs.append(self.gpa, .{132 try self.abbrev_relocs.append(self.gpa, .{
125 .target = null,133 .target = null,
126 .atom = atom,134 .atom_index = atom_index,
127 .offset = offset,135 .offset = offset,
128 .addend = addend,136 .addend = addend,
129 });137 });
...@@ -132,13 +140,13 @@ pub const DeclState = struct {...@@ -132,13 +140,13 @@ pub const DeclState = struct {
132 /// Adds global type relocation of the form: @offset => @symbol + 0140 /// Adds global type relocation of the form: @offset => @symbol + 0
133 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section141 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section
134 /// which we use as our target of the relocation.142 /// 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 {
136 const resolv = self.abbrev_resolver.getContext(ty, .{144 const resolv = self.abbrev_resolver.getContext(ty, .{
137 .mod = self.mod,145 .mod = self.mod,
138 }) orelse blk: {146 }) orelse blk: {
139 const sym_index = @intCast(u32, self.abbrev_table.items.len);147 const sym_index = @intCast(u32, self.abbrev_table.items.len);
140 try self.abbrev_table.append(self.gpa, .{148 try self.abbrev_table.append(self.gpa, .{
141 .atom = atom,149 .atom_index = atom_index,
142 .type = ty,150 .type = ty,
143 .offset = undefined,151 .offset = undefined,
144 });152 });
...@@ -153,7 +161,7 @@ pub const DeclState = struct {...@@ -153,7 +161,7 @@ pub const DeclState = struct {
153 log.debug("{x}: %{d} + 0", .{ offset, resolv });161 log.debug("{x}: %{d} + 0", .{ offset, resolv });
154 try self.abbrev_relocs.append(self.gpa, .{162 try self.abbrev_relocs.append(self.gpa, .{
155 .target = resolv,163 .target = resolv,
156 .atom = atom,164 .atom_index = atom_index,
157 .offset = offset,165 .offset = offset,
158 .addend = 0,166 .addend = 0,
159 });167 });
...@@ -162,7 +170,7 @@ pub const DeclState = struct {...@@ -162,7 +170,7 @@ pub const DeclState = struct {
162 fn addDbgInfoType(170 fn addDbgInfoType(
163 self: *DeclState,171 self: *DeclState,
164 module: *Module,172 module: *Module,
165 atom: *Atom,173 atom_index: Atom.Index,
166 ty: Type,174 ty: Type,
167 ) error{OutOfMemory}!void {175 ) error{OutOfMemory}!void {
168 const arena = self.abbrev_type_arena.allocator();176 const arena = self.abbrev_type_arena.allocator();
...@@ -227,7 +235,7 @@ pub const DeclState = struct {...@@ -227,7 +235,7 @@ pub const DeclState = struct {
227 // DW.AT.type, DW.FORM.ref4235 // DW.AT.type, DW.FORM.ref4
228 var index = dbg_info_buffer.items.len;236 var index = dbg_info_buffer.items.len;
229 try dbg_info_buffer.resize(index + 4);237 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));
231 // DW.AT.data_member_location, DW.FORM.sdata239 // DW.AT.data_member_location, DW.FORM.sdata
232 try dbg_info_buffer.ensureUnusedCapacity(6);240 try dbg_info_buffer.ensureUnusedCapacity(6);
233 dbg_info_buffer.appendAssumeCapacity(0);241 dbg_info_buffer.appendAssumeCapacity(0);
...@@ -239,7 +247,7 @@ pub const DeclState = struct {...@@ -239,7 +247,7 @@ pub const DeclState = struct {
239 // DW.AT.type, DW.FORM.ref4247 // DW.AT.type, DW.FORM.ref4
240 index = dbg_info_buffer.items.len;248 index = dbg_info_buffer.items.len;
241 try dbg_info_buffer.resize(index + 4);249 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));
243 // DW.AT.data_member_location, DW.FORM.sdata251 // DW.AT.data_member_location, DW.FORM.sdata
244 const offset = abi_size - payload_ty.abiSize(target);252 const offset = abi_size - payload_ty.abiSize(target);
245 try leb128.writeULEB128(dbg_info_buffer.writer(), offset);253 try leb128.writeULEB128(dbg_info_buffer.writer(), offset);
...@@ -270,7 +278,7 @@ pub const DeclState = struct {...@@ -270,7 +278,7 @@ pub const DeclState = struct {
270 try dbg_info_buffer.resize(index + 4);278 try dbg_info_buffer.resize(index + 4);
271 var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);279 var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
272 const ptr_ty = ty.slicePtrFieldType(buf);280 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));
274 // DW.AT.data_member_location, DW.FORM.sdata282 // DW.AT.data_member_location, DW.FORM.sdata
275 try dbg_info_buffer.ensureUnusedCapacity(6);283 try dbg_info_buffer.ensureUnusedCapacity(6);
276 dbg_info_buffer.appendAssumeCapacity(0);284 dbg_info_buffer.appendAssumeCapacity(0);
...@@ -282,7 +290,7 @@ pub const DeclState = struct {...@@ -282,7 +290,7 @@ pub const DeclState = struct {
282 // DW.AT.type, DW.FORM.ref4290 // DW.AT.type, DW.FORM.ref4
283 index = dbg_info_buffer.items.len;291 index = dbg_info_buffer.items.len;
284 try dbg_info_buffer.resize(index + 4);292 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));
286 // DW.AT.data_member_location, DW.FORM.sdata294 // DW.AT.data_member_location, DW.FORM.sdata
287 try dbg_info_buffer.ensureUnusedCapacity(2);295 try dbg_info_buffer.ensureUnusedCapacity(2);
288 dbg_info_buffer.appendAssumeCapacity(ptr_bytes);296 dbg_info_buffer.appendAssumeCapacity(ptr_bytes);
...@@ -294,7 +302,7 @@ pub const DeclState = struct {...@@ -294,7 +302,7 @@ pub const DeclState = struct {
294 // DW.AT.type, DW.FORM.ref4302 // DW.AT.type, DW.FORM.ref4
295 const index = dbg_info_buffer.items.len;303 const index = dbg_info_buffer.items.len;
296 try dbg_info_buffer.resize(index + 4);304 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));
298 }306 }
299 },307 },
300 .Array => {308 .Array => {
...@@ -305,13 +313,13 @@ pub const DeclState = struct {...@@ -305,13 +313,13 @@ pub const DeclState = struct {
305 // DW.AT.type, DW.FORM.ref4313 // DW.AT.type, DW.FORM.ref4
306 var index = dbg_info_buffer.items.len;314 var index = dbg_info_buffer.items.len;
307 try dbg_info_buffer.resize(index + 4);315 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));
309 // DW.AT.subrange_type317 // DW.AT.subrange_type
310 try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim));318 try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim));
311 // DW.AT.type, DW.FORM.ref4319 // DW.AT.type, DW.FORM.ref4
312 index = dbg_info_buffer.items.len;320 index = dbg_info_buffer.items.len;
313 try dbg_info_buffer.resize(index + 4);321 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));
315 // DW.AT.count, DW.FORM.udata323 // DW.AT.count, DW.FORM.udata
316 const len = ty.arrayLenIncludingSentinel();324 const len = ty.arrayLenIncludingSentinel();
317 try leb128.writeULEB128(dbg_info_buffer.writer(), len);325 try leb128.writeULEB128(dbg_info_buffer.writer(), len);
...@@ -339,7 +347,7 @@ pub const DeclState = struct {...@@ -339,7 +347,7 @@ pub const DeclState = struct {
339 // DW.AT.type, DW.FORM.ref4347 // DW.AT.type, DW.FORM.ref4
340 var index = dbg_info_buffer.items.len;348 var index = dbg_info_buffer.items.len;
341 try dbg_info_buffer.resize(index + 4);349 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));
343 // DW.AT.data_member_location, DW.FORM.sdata351 // DW.AT.data_member_location, DW.FORM.sdata
344 const field_off = ty.structFieldOffset(field_index, target);352 const field_off = ty.structFieldOffset(field_index, target);
345 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);353 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
...@@ -371,7 +379,7 @@ pub const DeclState = struct {...@@ -371,7 +379,7 @@ pub const DeclState = struct {
371 // DW.AT.type, DW.FORM.ref4379 // DW.AT.type, DW.FORM.ref4
372 var index = dbg_info_buffer.items.len;380 var index = dbg_info_buffer.items.len;
373 try dbg_info_buffer.resize(index + 4);381 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));
375 // DW.AT.data_member_location, DW.FORM.sdata383 // DW.AT.data_member_location, DW.FORM.sdata
376 const field_off = ty.structFieldOffset(field_index, target);384 const field_off = ty.structFieldOffset(field_index, target);
377 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);385 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
...@@ -454,7 +462,7 @@ pub const DeclState = struct {...@@ -454,7 +462,7 @@ pub const DeclState = struct {
454 // DW.AT.type, DW.FORM.ref4462 // DW.AT.type, DW.FORM.ref4
455 const inner_union_index = dbg_info_buffer.items.len;463 const inner_union_index = dbg_info_buffer.items.len;
456 try dbg_info_buffer.resize(inner_union_index + 4);464 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);
458 // DW.AT.data_member_location, DW.FORM.sdata466 // DW.AT.data_member_location, DW.FORM.sdata
459 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);467 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
460 }468 }
...@@ -481,7 +489,7 @@ pub const DeclState = struct {...@@ -481,7 +489,7 @@ pub const DeclState = struct {
481 // DW.AT.type, DW.FORM.ref4489 // DW.AT.type, DW.FORM.ref4
482 const index = dbg_info_buffer.items.len;490 const index = dbg_info_buffer.items.len;
483 try dbg_info_buffer.resize(index + 4);491 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));
485 // DW.AT.data_member_location, DW.FORM.sdata493 // DW.AT.data_member_location, DW.FORM.sdata
486 try dbg_info_buffer.append(0);494 try dbg_info_buffer.append(0);
487 }495 }
...@@ -498,7 +506,7 @@ pub const DeclState = struct {...@@ -498,7 +506,7 @@ pub const DeclState = struct {
498 // DW.AT.type, DW.FORM.ref4506 // DW.AT.type, DW.FORM.ref4
499 const index = dbg_info_buffer.items.len;507 const index = dbg_info_buffer.items.len;
500 try dbg_info_buffer.resize(index + 4);508 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));
502 // DW.AT.data_member_location, DW.FORM.sdata510 // DW.AT.data_member_location, DW.FORM.sdata
503 try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);511 try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
504512
...@@ -541,7 +549,7 @@ pub const DeclState = struct {...@@ -541,7 +549,7 @@ pub const DeclState = struct {
541 // DW.AT.type, DW.FORM.ref4549 // DW.AT.type, DW.FORM.ref4
542 var index = dbg_info_buffer.items.len;550 var index = dbg_info_buffer.items.len;
543 try dbg_info_buffer.resize(index + 4);551 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));
545 // DW.AT.data_member_location, DW.FORM.sdata553 // DW.AT.data_member_location, DW.FORM.sdata
546 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);554 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
547555
...@@ -554,7 +562,7 @@ pub const DeclState = struct {...@@ -554,7 +562,7 @@ pub const DeclState = struct {
554 // DW.AT.type, DW.FORM.ref4562 // DW.AT.type, DW.FORM.ref4
555 index = dbg_info_buffer.items.len;563 index = dbg_info_buffer.items.len;
556 try dbg_info_buffer.resize(index + 4);564 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));
558 // DW.AT.data_member_location, DW.FORM.sdata566 // DW.AT.data_member_location, DW.FORM.sdata
559 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);567 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
560568
...@@ -587,12 +595,11 @@ pub const DeclState = struct {...@@ -587,12 +595,11 @@ pub const DeclState = struct {
587 self: *DeclState,595 self: *DeclState,
588 name: [:0]const u8,596 name: [:0]const u8,
589 ty: Type,597 ty: Type,
590 tag: File.Tag,
591 owner_decl: Module.Decl.Index,598 owner_decl: Module.Decl.Index,
592 loc: DbgInfoLoc,599 loc: DbgInfoLoc,
593 ) error{OutOfMemory}!void {600 ) error{OutOfMemory}!void {
594 const dbg_info = &self.dbg_info;601 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).?;
596 const name_with_null = name.ptr[0 .. name.len + 1];603 const name_with_null = name.ptr[0 .. name.len + 1];
597604
598 switch (loc) {605 switch (loc) {
...@@ -637,7 +644,7 @@ pub const DeclState = struct {...@@ -637,7 +644,7 @@ pub const DeclState = struct {
637 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);644 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
638 const index = dbg_info.items.len;645 const index = dbg_info.items.len;
639 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4646 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.ref4647 try self.addTypeRelocGlobal(atom_index, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4
641 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string648 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
642 }649 }
643650
...@@ -645,13 +652,12 @@ pub const DeclState = struct {...@@ -645,13 +652,12 @@ pub const DeclState = struct {
645 self: *DeclState,652 self: *DeclState,
646 name: [:0]const u8,653 name: [:0]const u8,
647 ty: Type,654 ty: Type,
648 tag: File.Tag,
649 owner_decl: Module.Decl.Index,655 owner_decl: Module.Decl.Index,
650 is_ptr: bool,656 is_ptr: bool,
651 loc: DbgInfoLoc,657 loc: DbgInfoLoc,
652 ) error{OutOfMemory}!void {658 ) error{OutOfMemory}!void {
653 const dbg_info = &self.dbg_info;659 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).?;
655 const name_with_null = name.ptr[0 .. name.len + 1];661 const name_with_null = name.ptr[0 .. name.len + 1];
656 try dbg_info.append(@enumToInt(AbbrevKind.variable));662 try dbg_info.append(@enumToInt(AbbrevKind.variable));
657 const target = self.mod.getTarget();663 const target = self.mod.getTarget();
...@@ -781,7 +787,7 @@ pub const DeclState = struct {...@@ -781,7 +787,7 @@ pub const DeclState = struct {
781 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);787 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
782 const index = dbg_info.items.len;788 const index = dbg_info.items.len;
783 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4789 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));
785 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string791 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
786 }792 }
787793
...@@ -814,7 +820,7 @@ pub const DeclState = struct {...@@ -814,7 +820,7 @@ pub const DeclState = struct {
814};820};
815821
816pub const AbbrevEntry = struct {822pub const AbbrevEntry = struct {
817 atom: *const Atom,823 atom_index: Atom.Index,
818 type: Type,824 type: Type,
819 offset: u32,825 offset: u32,
820};826};
...@@ -823,7 +829,7 @@ pub const AbbrevRelocation = struct {...@@ -823,7 +829,7 @@ pub const AbbrevRelocation = struct {
823 /// If target is null, we deal with a local relocation that is based on simple offset + addend829 /// If target is null, we deal with a local relocation that is based on simple offset + addend
824 /// only.830 /// only.
825 target: ?u32,831 target: ?u32,
826 atom: *const Atom,832 atom_index: Atom.Index,
827 offset: u32,833 offset: u32,
828 addend: u32,834 addend: u32,
829};835};
...@@ -840,26 +846,6 @@ pub const ExprlocRelocation = struct {...@@ -840,26 +846,6 @@ pub const ExprlocRelocation = struct {
840 offset: u32,846 offset: u32,
841};847};
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
863pub const PtrWidth = enum { p32, p64 };849pub const PtrWidth = enum { p32, p64 };
864850
865pub const AbbrevKind = enum(u8) {851pub const AbbrevKind = enum(u8) {
...@@ -909,16 +895,18 @@ pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf {...@@ -909,16 +895,18 @@ pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf {
909895
910pub fn deinit(self: *Dwarf) void {896pub fn deinit(self: *Dwarf) void {
911 const gpa = self.allocator;897 const gpa = self.allocator;
912 self.dbg_line_fn_free_list.deinit(gpa);898
913 self.atom_free_list.deinit(gpa);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
914 self.strtab.deinit(gpa);907 self.strtab.deinit(gpa);
915 self.di_files.deinit(gpa);908 self.di_files.deinit(gpa);
916 self.global_abbrev_relocs.deinit(gpa);909 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);
922}910}
923911
924/// Initializes Decl's state and its matching output buffers.912/// 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)...@@ -934,15 +922,19 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
934 log.debug("initDeclState {s}{*}", .{ decl_name, decl });922 log.debug("initDeclState {s}{*}", .{ decl_name, decl });
935923
936 const gpa = self.allocator;924 const gpa = self.allocator;
937 var decl_state = DeclState.init(gpa, mod);925 var decl_state = DeclState.init(gpa, mod, &self.di_atom_decls);
938 errdefer decl_state.deinit();926 errdefer decl_state.deinit();
939 const dbg_line_buffer = &decl_state.dbg_line;927 const dbg_line_buffer = &decl_state.dbg_line;
940 const dbg_info_buffer = &decl_state.dbg_info;928 const dbg_info_buffer = &decl_state.dbg_info;
941929
930 const di_atom_index = try self.getOrCreateAtomForDecl(.di_atom, decl_index);
931
942 assert(decl.has_tv);932 assert(decl.has_tv);
943933
944 switch (decl.ty.zigTypeTag()) {934 switch (decl.ty.zigTypeTag()) {
945 .Fn => {935 .Fn => {
936 _ = try self.getOrCreateAtomForDecl(.src_fn, decl_index);
937
946 // For functions we need to add a prologue to the debug line program.938 // For functions we need to add a prologue to the debug line program.
947 try dbg_line_buffer.ensureTotalCapacity(26);939 try dbg_line_buffer.ensureTotalCapacity(26);
948940
...@@ -1002,8 +994,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)...@@ -1002,8 +994,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
1002 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4994 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
1003 //995 //
1004 if (fn_ret_has_bits) {996 if (fn_ret_has_bits) {
1005 const atom = getDbgInfoAtom(self.bin_file.tag, mod, decl_index);997 try decl_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
1006 try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
1007 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4998 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
1008 }999 }
10091000
...@@ -1075,31 +1066,28 @@ pub fn commitDeclState(...@@ -1075,31 +1066,28 @@ pub fn commitDeclState(
1075 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for1066 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
1076 // `TextBlock` and the .debug_info. If you are editing this logic, you1067 // `TextBlock` and the .debug_info. If you are editing this logic, you
1077 // probably need to edit that logic too.1068 // probably need to edit that logic too.
1078 const src_fn = switch (self.bin_file.tag) {1069 const src_fn_index = self.src_fn_decls.get(decl_index).?;
1079 .elf => &decl.fn_link.elf,1070 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
1080 .macho => &decl.fn_link.macho,
1081 .wasm => &decl.fn_link.wasm.src_fn,
1082 else => unreachable, // TODO
1083 };
1084 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);1071 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
10851072
1086 if (self.dbg_line_fn_last) |last| blk: {1073 if (self.src_fn_last_index) |last_index| blk: {
1087 if (src_fn == last) break :blk;1074 if (src_fn_index == last_index) break :blk;
1088 if (src_fn.next) |next| {1075 if (src_fn.next_index) |next_index| {
1076 const next = self.getAtomPtr(.src_fn, next_index);
1089 // Update existing function - non-last item.1077 // Update existing function - non-last item.
1090 if (src_fn.off + src_fn.len + min_nop_size > next.off) {1078 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
1091 // It grew too big, so we move it to a new location.1079 // It grew too big, so we move it to a new location.
1092 if (src_fn.prev) |prev| {1080 if (src_fn.prev_index) |prev_index| {
1093 self.dbg_line_fn_free_list.put(gpa, prev, {}) catch {};1081 self.src_fn_free_list.put(gpa, prev_index, {}) catch {};
1094 prev.next = src_fn.next;1082 self.getAtomPtr(.src_fn, prev_index).next_index = src_fn.next_index;
1095 }1083 }
1096 next.prev = src_fn.prev;1084 next.prev_index = src_fn.prev_index;
1097 src_fn.next = null;1085 src_fn.next_index = null;
1098 // Populate where it used to be with NOPs.1086 // Populate where it used to be with NOPs.
1099 switch (self.bin_file.tag) {1087 switch (self.bin_file.tag) {
1100 .elf => {1088 .elf => {
1101 const elf_file = self.bin_file.cast(File.Elf).?;1089 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.?];
1103 const file_pos = debug_line_sect.sh_offset + src_fn.off;1091 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1104 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);1092 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
1105 },1093 },
...@@ -1111,39 +1099,48 @@ pub fn commitDeclState(...@@ -1111,39 +1099,48 @@ pub fn commitDeclState(
1111 },1099 },
1112 .wasm => {1100 .wasm => {
1113 const wasm_file = self.bin_file.cast(File.Wasm).?;1101 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;
1115 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);1103 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);
1116 },1104 },
1117 else => unreachable,1105 else => unreachable,
1118 }1106 }
1119 // TODO Look at the free list before appending at the end.1107 // TODO Look at the free list before appending at the end.
1120 src_fn.prev = last;1108 src_fn.prev_index = last_index;
1121 last.next = src_fn;1109 const last = self.getAtomPtr(.src_fn, last_index);
1122 self.dbg_line_fn_last = src_fn;1110 last.next_index = src_fn_index;
1111 self.src_fn_last_index = src_fn_index;
11231112
1124 src_fn.off = last.off + padToIdeal(last.len);1113 src_fn.off = last.off + padToIdeal(last.len);
1125 }1114 }
1126 } else if (src_fn.prev == null) {1115 } else if (src_fn.prev_index == null) {
1127 // Append new function.1116 // Append new function.
1128 // TODO Look at the free list before appending at the end.1117 // TODO Look at the free list before appending at the end.
1129 src_fn.prev = last;1118 src_fn.prev_index = last_index;
1130 last.next = src_fn;1119 const last = self.getAtomPtr(.src_fn, last_index);
1131 self.dbg_line_fn_last = src_fn;1120 last.next_index = src_fn_index;
1121 self.src_fn_last_index = src_fn_index;
11321122
1133 src_fn.off = last.off + padToIdeal(last.len);1123 src_fn.off = last.off + padToIdeal(last.len);
1134 }1124 }
1135 } else {1125 } else {
1136 // This is the first function of the Line Number Program.1126 // This is the first function of the Line Number Program.
1137 self.dbg_line_fn_first = src_fn;1127 self.src_fn_first_index = src_fn_index;
1138 self.dbg_line_fn_last = src_fn;1128 self.src_fn_last_index = src_fn_index;
11391129
1140 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));1130 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));
1141 }1131 }
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);
1144 const needed_size = last_src_fn.off + last_src_fn.len;1135 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;1136 const prev_padding_size: u32 = if (src_fn.prev_index) |prev_index| blk: {
1146 const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;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
1148 // We only have support for one compilation unit so far, so the offsets are directly1145 // We only have support for one compilation unit so far, so the offsets are directly
1149 // from the .debug_line section.1146 // from the .debug_line section.
...@@ -1152,7 +1149,7 @@ pub fn commitDeclState(...@@ -1152,7 +1149,7 @@ pub fn commitDeclState(
1152 const elf_file = self.bin_file.cast(File.Elf).?;1149 const elf_file = self.bin_file.cast(File.Elf).?;
1153 const shdr_index = elf_file.debug_line_section_index.?;1150 const shdr_index = elf_file.debug_line_section_index.?;
1154 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);1151 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];
1156 const file_pos = debug_line_sect.sh_offset + src_fn.off;1153 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1157 try pwriteDbgLineNops(1154 try pwriteDbgLineNops(
1158 elf_file.base.file.?,1155 elf_file.base.file.?,
...@@ -1180,7 +1177,7 @@ pub fn commitDeclState(...@@ -1180,7 +1177,7 @@ pub fn commitDeclState(
11801177
1181 .wasm => {1178 .wasm => {
1182 const wasm_file = self.bin_file.cast(File.Wasm).?;1179 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.?);
1184 const debug_line = &atom.code;1181 const debug_line = &atom.code;
1185 const segment_size = debug_line.items.len;1182 const segment_size = debug_line.items.len;
1186 if (needed_size != segment_size) {1183 if (needed_size != segment_size) {
...@@ -1212,7 +1209,7 @@ pub fn commitDeclState(...@@ -1212,7 +1209,7 @@ pub fn commitDeclState(
1212 if (dbg_info_buffer.items.len == 0)1209 if (dbg_info_buffer.items.len == 0)
1213 return;1210 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).?;
1216 if (decl_state.abbrev_table.items.len > 0) {1213 if (decl_state.abbrev_table.items.len > 0) {
1217 // Now we emit the .debug_info types of the Decl. These will count towards the size of1214 // Now we emit the .debug_info types of the Decl. These will count towards the size of
1218 // the buffer, so we have to do it before computing the offset, and we can't perform the actual1215 // 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(...@@ -1234,12 +1231,12 @@ pub fn commitDeclState(
1234 if (deferred) continue;1231 if (deferred) continue;
12351232
1236 symbol.offset = @intCast(u32, dbg_info_buffer.items.len);1233 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);
1238 }1235 }
1239 }1236 }
12401237
1241 log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name});1238 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
1244 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {1241 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
1245 if (reloc.target) |target| {1242 if (reloc.target) |target| {
...@@ -1260,11 +1257,12 @@ pub fn commitDeclState(...@@ -1260,11 +1257,12 @@ pub fn commitDeclState(
1260 try self.global_abbrev_relocs.append(gpa, .{1257 try self.global_abbrev_relocs.append(gpa, .{
1261 .target = null,1258 .target = null,
1262 .offset = reloc.offset,1259 .offset = reloc.offset,
1263 .atom = reloc.atom,1260 .atom_index = reloc.atom_index,
1264 .addend = reloc.addend,1261 .addend = reloc.addend,
1265 });1262 });
1266 } else {1263 } 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;
1268 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() });1266 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() });
1269 mem.writeInt(1267 mem.writeInt(
1270 u32,1268 u32,
...@@ -1274,10 +1272,11 @@ pub fn commitDeclState(...@@ -1274,10 +1272,11 @@ pub fn commitDeclState(
1274 );1272 );
1275 }1273 }
1276 } else {1274 } else {
1275 const atom = self.getAtom(.di_atom, reloc.atom_index);
1277 mem.writeInt(1276 mem.writeInt(
1278 u32,1277 u32,
1279 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],1278 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
1280 reloc.atom.off + reloc.offset + reloc.addend,1279 atom.off + reloc.offset + reloc.addend,
1281 target_endian,1280 target_endian,
1282 );1281 );
1283 }1282 }
...@@ -1293,7 +1292,7 @@ pub fn commitDeclState(...@@ -1293,7 +1292,7 @@ pub fn commitDeclState(
1293 .got_load => .got_load,1292 .got_load => .got_load,
1294 },1293 },
1295 .target = reloc.target,1294 .target = reloc.target,
1296 .offset = reloc.offset + atom.off,1295 .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
1297 .addend = 0,1296 .addend = 0,
1298 .prev_vaddr = 0,1297 .prev_vaddr = 0,
1299 });1298 });
...@@ -1303,10 +1302,10 @@ pub fn commitDeclState(...@@ -1303,10 +1302,10 @@ pub fn commitDeclState(
1303 }1302 }
13041303
1305 log.debug("writeDeclDebugInfo for '{s}", .{decl.name});1304 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);
1307}1306}
13081307
1309fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {1308fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) !void {
1310 const tracy = trace(@src());1309 const tracy = trace(@src());
1311 defer tracy.end();1310 defer tracy.end();
13121311
...@@ -1315,24 +1314,26 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {...@@ -1315,24 +1314,26 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
1315 // probably need to edit that logic too.1314 // probably need to edit that logic too.
1316 const gpa = self.allocator;1315 const gpa = self.allocator;
13171316
1317 const atom = self.getAtomPtr(.di_atom, atom_index);
1318 atom.len = len;1318 atom.len = len;
1319 if (self.atom_last) |last| blk: {1319 if (self.di_atom_last_index) |last_index| blk: {
1320 if (atom == last) break :blk;1320 if (atom_index == last_index) break :blk;
1321 if (atom.next) |next| {1321 if (atom.next_index) |next_index| {
1322 const next = self.getAtomPtr(.di_atom, next_index);
1322 // Update existing Decl - non-last item.1323 // Update existing Decl - non-last item.
1323 if (atom.off + atom.len + min_nop_size > next.off) {1324 if (atom.off + atom.len + min_nop_size > next.off) {
1324 // It grew too big, so we move it to a new location.1325 // It grew too big, so we move it to a new location.
1325 if (atom.prev) |prev| {1326 if (atom.prev_index) |prev_index| {
1326 self.atom_free_list.put(gpa, prev, {}) catch {};1327 self.di_atom_free_list.put(gpa, prev_index, {}) catch {};
1327 prev.next = atom.next;1328 self.getAtomPtr(.di_atom, prev_index).next_index = atom.next_index;
1328 }1329 }
1329 next.prev = atom.prev;1330 next.prev_index = atom.prev_index;
1330 atom.next = null;1331 atom.next_index = null;
1331 // Populate where it used to be with NOPs.1332 // Populate where it used to be with NOPs.
1332 switch (self.bin_file.tag) {1333 switch (self.bin_file.tag) {
1333 .elf => {1334 .elf => {
1334 const elf_file = self.bin_file.cast(File.Elf).?;1335 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.?];
1336 const file_pos = debug_info_sect.sh_offset + atom.off;1337 const file_pos = debug_info_sect.sh_offset + atom.off;
1337 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);1338 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
1338 },1339 },
...@@ -1344,37 +1345,40 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {...@@ -1344,37 +1345,40 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
1344 },1345 },
1345 .wasm => {1346 .wasm => {
1346 const wasm_file = self.bin_file.cast(File.Wasm).?;1347 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;
1348 try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);1350 try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);
1349 },1351 },
1350 else => unreachable,1352 else => unreachable,
1351 }1353 }
1352 // TODO Look at the free list before appending at the end.1354 // TODO Look at the free list before appending at the end.
1353 atom.prev = last;1355 atom.prev_index = last_index;
1354 last.next = atom;1356 const last = self.getAtomPtr(.di_atom, last_index);
1355 self.atom_last = atom;1357 last.next_index = atom_index;
1358 self.di_atom_last_index = atom_index;
13561359
1357 atom.off = last.off + padToIdeal(last.len);1360 atom.off = last.off + padToIdeal(last.len);
1358 }1361 }
1359 } else if (atom.prev == null) {1362 } else if (atom.prev_index == null) {
1360 // Append new Decl.1363 // Append new Decl.
1361 // TODO Look at the free list before appending at the end.1364 // TODO Look at the free list before appending at the end.
1362 atom.prev = last;1365 atom.prev_index = last_index;
1363 last.next = atom;1366 const last = self.getAtomPtr(.di_atom, last_index);
1364 self.atom_last = atom;1367 last.next_index = atom_index;
1368 self.di_atom_last_index = atom_index;
13651369
1366 atom.off = last.off + padToIdeal(last.len);1370 atom.off = last.off + padToIdeal(last.len);
1367 }1371 }
1368 } else {1372 } else {
1369 // This is the first Decl of the .debug_info1373 // This is the first Decl of the .debug_info
1370 self.atom_first = atom;1374 self.di_atom_first_index = atom_index;
1371 self.atom_last = atom;1375 self.di_atom_last_index = atom_index;
13721376
1373 atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes()));1377 atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes()));
1374 }1378 }
1375}1379}
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 {
1378 const tracy = trace(@src());1382 const tracy = trace(@src());
1379 defer tracy.end();1383 defer tracy.end();
13801384
...@@ -1383,14 +1387,22 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void...@@ -1383,14 +1387,22 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
1383 // probably need to edit that logic too.1387 // probably need to edit that logic too.
1384 const gpa = self.allocator;1388 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);
1387 // +1 for a trailing zero to end the children of the decl tag.1393 // +1 for a trailing zero to end the children of the decl tag.
1388 const needed_size = last_decl.off + last_decl.len + 1;1394 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;1395 const prev_padding_size: u32 = if (atom.prev_index) |prev_index| blk: {
1390 const next_padding_size: u32 = if (atom.next) |next| next.off - (atom.off + atom.len) else 0;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
1392 // To end the children of the decl tag.1404 // To end the children of the decl tag.
1393 const trailing_zero = atom.next == null;1405 const trailing_zero = atom.next_index == null;
13941406
1395 // We only have support for one compilation unit so far, so the offsets are directly1407 // We only have support for one compilation unit so far, so the offsets are directly
1396 // from the .debug_info section.1408 // from the .debug_info section.
...@@ -1399,7 +1411,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void...@@ -1399,7 +1411,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
1399 const elf_file = self.bin_file.cast(File.Elf).?;1411 const elf_file = self.bin_file.cast(File.Elf).?;
1400 const shdr_index = elf_file.debug_info_section_index.?;1412 const shdr_index = elf_file.debug_info_section_index.?;
1401 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);1413 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];
1403 const file_pos = debug_info_sect.sh_offset + atom.off;1415 const file_pos = debug_info_sect.sh_offset + atom.off;
1404 try pwriteDbgInfoNops(1416 try pwriteDbgInfoNops(
1405 elf_file.base.file.?,1417 elf_file.base.file.?,
...@@ -1430,7 +1442,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void...@@ -1430,7 +1442,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
1430 .wasm => {1442 .wasm => {
1431 const wasm_file = self.bin_file.cast(File.Wasm).?;1443 const wasm_file = self.bin_file.cast(File.Wasm).?;
1432 const info_atom = wasm_file.debug_info_atom.?;1444 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;
1434 const segment_size = debug_info.items.len;1446 const segment_size = debug_info.items.len;
1435 if (needed_size != segment_size) {1447 if (needed_size != segment_size) {
1436 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});1448 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...@@ -1458,10 +1470,15 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
1458 }1470 }
1459}1471}
14601472
1461pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {1473pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.Decl.Index) !void {
1462 const tracy = trace(@src());1474 const tracy = trace(@src());
1463 defer tracy.end();1475 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);
1465 const func = decl.val.castTag(.function).?.data;1482 const func = decl.val.castTag(.function).?.data;
1466 log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{1483 log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{
1467 decl.src_line,1484 decl.src_line,
...@@ -1475,79 +1492,81 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {...@@ -1475,79 +1492,81 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {
1475 switch (self.bin_file.tag) {1492 switch (self.bin_file.tag) {
1476 .elf => {1493 .elf => {
1477 const elf_file = self.bin_file.cast(File.Elf).?;1494 const elf_file = self.bin_file.cast(File.Elf).?;
1478 const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?];1495 const shdr = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
1479 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();1496 const file_pos = shdr.sh_offset + atom.off + self.getRelocDbgLineOff();
1480 try elf_file.base.file.?.pwriteAll(&data, file_pos);1497 try elf_file.base.file.?.pwriteAll(&data, file_pos);
1481 },1498 },
1482 .macho => {1499 .macho => {
1483 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;1500 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
1484 const sect = d_sym.getSection(d_sym.debug_line_section_index.?);1501 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();
1486 try d_sym.file.pwriteAll(&data, file_pos);1503 try d_sym.file.pwriteAll(&data, file_pos);
1487 },1504 },
1488 .wasm => {1505 .wasm => {
1489 const wasm_file = self.bin_file.cast(File.Wasm).?;1506 const wasm_file = self.bin_file.cast(File.Wasm).?;
1490 const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff();1507 const offset = atom.off + self.getRelocDbgLineOff();
1491 const atom = wasm_file.debug_line_atom.?;1508 const line_atom_index = wasm_file.debug_line_atom.?;
1492 mem.copy(u8, atom.code.items[offset..], &data);1509 mem.copy(u8, wasm_file.getAtomPtr(line_atom_index).code.items[offset..], &data);
1493 },1510 },
1494 else => unreachable,1511 else => unreachable,
1495 }1512 }
1496}1513}
14971514
1498pub fn freeAtom(self: *Dwarf, atom: *Atom) void {1515pub fn freeDecl(self: *Dwarf, decl_index: Module.Decl.Index) void {
1499 if (self.atom_first == atom) {1516 const gpa = self.allocator;
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;
15091517
1510 // TODO the free list logic like we do for text blocks above1518 // Free SrcFn atom
1511 } else {1519 if (self.src_fn_decls.fetchRemove(decl_index)) |kv| {
1512 atom.prev = null;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 }
1513 }1543 }
15141544
1515 if (atom.next) |next| {1545 // Free DI atom
1516 next.prev = atom.prev;1546 if (self.di_atom_decls.fetchRemove(decl_index)) |kv| {
1517 } else {1547 const di_atom_index = kv.value;
1518 atom.next = null;1548 const di_atom = self.getAtomPtr(.di_atom, di_atom_index);
1519 }
1520}
15211549
1522pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {1550 if (self.di_atom_first_index == di_atom_index) {
1523 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing1551 self.di_atom_first_index = di_atom.next_index;
1524 // is desired for both.1552 }
1525 const gpa = self.allocator;1553 if (self.di_atom_last_index == di_atom_index) {
1526 const fn_link = switch (self.bin_file.tag) {1554 // TODO shrink the .debug_info section size here
1527 .elf => &decl.fn_link.elf,1555 self.di_atom_last_index = di_atom.prev_index;
1528 .macho => &decl.fn_link.macho,1556 }
1529 .wasm => &decl.fn_link.wasm.src_fn,
1530 else => unreachable,
1531 };
1532 _ = self.dbg_line_fn_free_list.remove(fn_link);
15331557
1534 if (fn_link.prev) |prev| {1558 if (di_atom.prev_index) |prev_index| {
1535 self.dbg_line_fn_free_list.put(gpa, prev, {}) catch {};1559 self.getAtomPtr(.di_atom, prev_index).next_index = di_atom.next_index;
1536 prev.next = fn_link.next;1560 // TODO the free list logic like we do for SrcFn above
1537 if (fn_link.next) |next| {
1538 next.prev = prev;
1539 } else {1561 } 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;
1541 }1569 }
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;
1551 }1570 }
1552}1571}
15531572
...@@ -1690,7 +1709,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {...@@ -1690,7 +1709,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
1690 const elf_file = self.bin_file.cast(File.Elf).?;1709 const elf_file = self.bin_file.cast(File.Elf).?;
1691 const shdr_index = elf_file.debug_abbrev_section_index.?;1710 const shdr_index = elf_file.debug_abbrev_section_index.?;
1692 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false);1711 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];
1694 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;1713 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;
1695 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);1714 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
1696 },1715 },
...@@ -1704,7 +1723,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {...@@ -1704,7 +1723,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
1704 },1723 },
1705 .wasm => {1724 .wasm => {
1706 const wasm_file = self.bin_file.cast(File.Wasm).?;1725 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;
1708 try debug_abbrev.resize(wasm_file.base.allocator, needed_size);1727 try debug_abbrev.resize(wasm_file.base.allocator, needed_size);
1709 mem.copy(u8, debug_abbrev.items, &abbrev_buf);1728 mem.copy(u8, debug_abbrev.items, &abbrev_buf);
1710 },1729 },
...@@ -1770,11 +1789,11 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u...@@ -1770,11 +1789,11 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
1770 },1789 },
1771 }1790 }
1772 // Write the form for the compile unit, which must match the abbrev table above.1791 // 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);
1774 var compile_unit_dir_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;1793 var compile_unit_dir_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
1775 const compile_unit_dir = resolveCompilationDir(module, &compile_unit_dir_buffer);1794 const compile_unit_dir = resolveCompilationDir(module, &compile_unit_dir_buffer);
1776 const comp_dir_strp = try self.makeString(compile_unit_dir);1795 const comp_dir_strp = try self.strtab.insert(self.allocator, compile_unit_dir);
1777 const producer_strp = try self.makeString(link.producer_string);1796 const producer_strp = try self.strtab.insert(self.allocator, link.producer_string);
17781797
1779 di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit));1798 di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit));
1780 if (self.bin_file.tag == .macho) {1799 if (self.bin_file.tag == .macho) {
...@@ -1805,7 +1824,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u...@@ -1805,7 +1824,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
1805 switch (self.bin_file.tag) {1824 switch (self.bin_file.tag) {
1806 .elf => {1825 .elf => {
1807 const elf_file = self.bin_file.cast(File.Elf).?;1826 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.?];
1809 const file_pos = debug_info_sect.sh_offset;1828 const file_pos = debug_info_sect.sh_offset;
1810 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);1829 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
1811 },1830 },
...@@ -1817,7 +1836,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u...@@ -1817,7 +1836,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
1817 },1836 },
1818 .wasm => {1837 .wasm => {
1819 const wasm_file = self.bin_file.cast(File.Wasm).?;1838 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;
1821 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);1840 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
1822 },1841 },
1823 else => unreachable,1842 else => unreachable,
...@@ -2124,7 +2143,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {...@@ -2124,7 +2143,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2124 const elf_file = self.bin_file.cast(File.Elf).?;2143 const elf_file = self.bin_file.cast(File.Elf).?;
2125 const shdr_index = elf_file.debug_aranges_section_index.?;2144 const shdr_index = elf_file.debug_aranges_section_index.?;
2126 try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false);2145 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];
2128 const file_pos = debug_aranges_sect.sh_offset;2147 const file_pos = debug_aranges_sect.sh_offset;
2129 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);2148 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
2130 },2149 },
...@@ -2138,7 +2157,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {...@@ -2138,7 +2157,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2138 },2157 },
2139 .wasm => {2158 .wasm => {
2140 const wasm_file = self.bin_file.cast(File.Wasm).?;2159 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;
2142 try debug_ranges.resize(wasm_file.base.allocator, needed_size);2161 try debug_ranges.resize(wasm_file.base.allocator, needed_size);
2143 mem.copy(u8, debug_ranges.items, di_buf.items);2162 mem.copy(u8, debug_ranges.items, di_buf.items);
2144 },2163 },
...@@ -2275,19 +2294,23 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2275,19 +2294,23 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2275 const needed_with_padding = padToIdeal(needed_bytes);2294 const needed_with_padding = padToIdeal(needed_bytes);
2276 const delta = needed_with_padding - dbg_line_prg_off;2295 const delta = needed_with_padding - dbg_line_prg_off;
22772296
2278 var src_fn = self.dbg_line_fn_first.?;2297 const first_fn_index = self.src_fn_first_index.?;
2279 const last_fn = self.dbg_line_fn_last.?;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);
2282 defer gpa.free(buffer);2305 defer gpa.free(buffer);
22832306
2284 switch (self.bin_file.tag) {2307 switch (self.bin_file.tag) {
2285 .elf => {2308 .elf => {
2286 const elf_file = self.bin_file.cast(File.Elf).?;2309 const elf_file = self.bin_file.cast(File.Elf).?;
2287 const shdr_index = elf_file.debug_line_section_index.?;2310 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;
2289 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);2312 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
2292 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);2315 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
2293 if (amt != buffer.len) return error.InputOutput;2316 if (amt != buffer.len) return error.InputOutput;
...@@ -2299,7 +2322,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2299,7 +2322,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2299 const sect_index = d_sym.debug_line_section_index.?;2322 const sect_index = d_sym.debug_line_section_index.?;
2300 const needed_size = @intCast(u32, d_sym.getSection(sect_index).size + delta);2323 const needed_size = @intCast(u32, d_sym.getSection(sect_index).size + delta);
2301 try d_sym.growSection(sect_index, needed_size, true);2324 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
2304 const amt = try d_sym.file.preadAll(buffer, file_pos);2327 const amt = try d_sym.file.preadAll(buffer, file_pos);
2305 if (amt != buffer.len) return error.InputOutput;2328 if (amt != buffer.len) return error.InputOutput;
...@@ -2308,19 +2331,20 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2308,19 +2331,20 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2308 },2331 },
2309 .wasm => {2332 .wasm => {
2310 const wasm_file = self.bin_file.cast(File.Wasm).?;2333 const wasm_file = self.bin_file.cast(File.Wasm).?;
2311 const debug_line = &wasm_file.debug_line_atom.?.code;2334 const debug_line = &wasm_file.getAtomPtr(wasm_file.debug_line_atom.?).code;
2312 mem.copy(u8, buffer, debug_line.items[src_fn.off..]);2335 mem.copy(u8, buffer, debug_line.items[first_fn.off..]);
2313 try debug_line.resize(self.allocator, debug_line.items.len + delta);2336 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);
2315 },2338 },
2316 else => unreachable,2339 else => unreachable,
2317 }2340 }
23182341
2319 while (true) {2342 while (true) {
2343 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
2320 src_fn.off += delta;2344 src_fn.off += delta;
23212345
2322 if (src_fn.next) |next| {2346 if (src_fn.next_index) |next_index| {
2323 src_fn = next;2347 src_fn_index = next_index;
2324 } else break;2348 } else break;
2325 }2349 }
2326 }2350 }
...@@ -2346,7 +2370,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2346,7 +2370,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2346 switch (self.bin_file.tag) {2370 switch (self.bin_file.tag) {
2347 .elf => {2371 .elf => {
2348 const elf_file = self.bin_file.cast(File.Elf).?;2372 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.?];
2350 const file_pos = debug_line_sect.sh_offset;2374 const file_pos = debug_line_sect.sh_offset;
2351 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);2375 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
2352 },2376 },
...@@ -2358,7 +2382,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2358,7 +2382,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2358 },2382 },
2359 .wasm => {2383 .wasm => {
2360 const wasm_file = self.bin_file.cast(File.Wasm).?;2384 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;
2362 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);2386 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);
2363 },2387 },
2364 else => unreachable,2388 else => unreachable,
...@@ -2366,22 +2390,26 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2366,22 +2390,26 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2366}2390}
23672391
2368fn getDebugInfoOff(self: Dwarf) ?u32 {2392fn 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);
2370 return first.off;2395 return first.off;
2371}2396}
23722397
2373fn getDebugInfoEnd(self: Dwarf) ?u32 {2398fn 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);
2375 return last.off + last.len;2401 return last.off + last.len;
2376}2402}
23772403
2378fn getDebugLineProgramOff(self: Dwarf) ?u32 {2404fn 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);
2380 return first.off;2407 return first.off;
2381}2408}
23822409
2383fn getDebugLineProgramEnd(self: Dwarf) ?u32 {2410fn 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);
2385 return last.off + last.len;2413 return last.off + last.len;
2386}2414}
23872415
...@@ -2435,15 +2463,6 @@ fn getRelocDbgInfoSubprogramHighPC(self: Dwarf) u32 {...@@ -2435,15 +2463,6 @@ fn getRelocDbgInfoSubprogramHighPC(self: Dwarf) u32 {
2435 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();2463 return dbg_info_low_pc_reloc_index + self.ptrWidthBytes();
2436}2464}
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
2447fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {2466fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
2448 return actual_size +| (actual_size / ideal_factor);2467 return actual_size +| (actual_size / ideal_factor);
2449}2468}
...@@ -2465,29 +2484,20 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {...@@ -2465,29 +2484,20 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
2465 }2484 }
2466 error_set.names = names;2485 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
2477 var dbg_info_buffer = std.ArrayList(u8).init(arena);2487 var dbg_info_buffer = std.ArrayList(u8).init(arena);
2478 try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer);2488 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);
2481 log.debug("updateDeclDebugInfoAllocation in flushModule", .{});2491 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));
2483 log.debug("writeDeclDebugInfo in flushModule", .{});2493 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
2486 const file_pos = blk: {2496 const file_pos = blk: {
2487 switch (self.bin_file.tag) {2497 switch (self.bin_file.tag) {
2488 .elf => {2498 .elf => {
2489 const elf_file = self.bin_file.cast(File.Elf).?;2499 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.?];
2491 break :blk debug_info_sect.sh_offset;2501 break :blk debug_info_sect.sh_offset;
2492 },2502 },
2493 .macho => {2503 .macho => {
...@@ -2502,22 +2512,23 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {...@@ -2502,22 +2512,23 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
2502 };2512 };
25032513
2504 var buf: [@sizeOf(u32)]u8 = undefined;2514 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
2507 while (self.global_abbrev_relocs.popOrNull()) |reloc| {2517 while (self.global_abbrev_relocs.popOrNull()) |reloc| {
2518 const atom = self.getAtom(.di_atom, reloc.atom_index);
2508 switch (self.bin_file.tag) {2519 switch (self.bin_file.tag) {
2509 .elf => {2520 .elf => {
2510 const elf_file = self.bin_file.cast(File.Elf).?;2521 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);
2512 },2523 },
2513 .macho => {2524 .macho => {
2514 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;2525 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);
2516 },2527 },
2517 .wasm => {2528 .wasm => {
2518 const wasm_file = self.bin_file.cast(File.Wasm).?;2529 const wasm_file = self.bin_file.cast(File.Wasm).?;
2519 const debug_info = wasm_file.debug_info_atom.?.code;2530 const debug_info = wasm_file.getAtomPtr(wasm_file.debug_info_atom.?).code;
2520 mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf);2531 mem.copy(u8, debug_info.items[atom.off + reloc.offset ..], &buf);
2521 },2532 },
2522 else => unreachable,2533 else => unreachable,
2523 }2534 }
...@@ -2635,12 +2646,62 @@ fn addDbgInfoErrorSet(...@@ -2635,12 +2646,62 @@ fn addDbgInfoErrorSet(
2635 try dbg_info_buffer.append(0);2646 try dbg_info_buffer.append(0);
2636}2647}
26372648
2638fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *Atom {2649const Kind = enum { src_fn, di_atom };
2639 const decl = mod.declPtr(decl_index);2650
2640 return switch (tag) {2651fn createAtom(self: *Dwarf, comptime kind: Kind) !Atom.Index {
2641 .elf => &decl.link.elf.dbg_info_atom,2652 const index = blk: {
2642 .macho => &decl.link.macho.dbg_info_atom,2653 switch (kind) {
2643 .wasm => &decl.link.wasm.dbg_info_atom,2654 .src_fn => {
2644 else => unreachable,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],
2645 };2706 };
2646}2707}
src/link/Elf.zig+636-570
...@@ -1,43 +1,89 @@...@@ -1,43 +1,89 @@
1const Elf = @This();1const Elf = @This();
22
3const std = @import("std");3const std = @import("std");
4const build_options = @import("build_options");
4const builtin = @import("builtin");5const builtin = @import("builtin");
5const math = std.math;
6const mem = std.mem;
7const assert = std.debug.assert;6const assert = std.debug.assert;
8const Allocator = std.mem.Allocator;
9const fs = std.fs;
10const elf = std.elf;7const elf = std.elf;
8const fs = std.fs;
11const log = std.log.scoped(.link);9const 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");
17const codegen = @import("../codegen.zig");13const 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");
28const glibc = @import("../glibc.zig");14const glibc = @import("../glibc.zig");
15const link = @import("../link.zig");
16const lldMain = @import("../main.zig").lldMain;
29const musl = @import("../musl.zig");17const musl = @import("../musl.zig");
30const Cache = @import("../Cache.zig");18const target_util = @import("../target.zig");
19const trace = @import("../tracy.zig").trace;
20
31const Air = @import("../Air.zig");21const 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;
32const Liveness = @import("../Liveness.zig");28const Liveness = @import("../Liveness.zig");
33const LlvmObject = @import("../codegen/llvm.zig").Object;29const LlvmObject = @import("../codegen/llvm.zig").Object;
3430const Module = @import("../Module.zig");
35pub const TextBlock = Atom;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
37const default_entry_addr = 0x8000000;37const default_entry_addr = 0x8000000;
3838
39pub const base_tag: File.Tag = .elf;39pub 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
41base: File,87base: File,
42dwarf: ?Dwarf = null,88dwarf: ?Dwarf = null,
4389
...@@ -48,12 +94,12 @@ llvm_object: ?*LlvmObject = null,...@@ -48,12 +94,12 @@ llvm_object: ?*LlvmObject = null,
4894
49/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.95/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
50/// Same order as in the file.96/// Same order as in the file.
51sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){},97sections: std.MultiArrayList(Section) = .{},
52shdr_table_offset: ?u64 = null,98shdr_table_offset: ?u64 = null,
5399
54/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.100/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
55/// Same order as in the file.101/// 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) = .{},
57phdr_table_offset: ?u64 = null,103phdr_table_offset: ?u64 = null,
58/// The index into the program headers of a PT_LOAD program header with Read and Execute flags104/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
59phdr_load_re_index: ?u16 = null,105phdr_load_re_index: ?u16 = null,
...@@ -65,12 +111,10 @@ phdr_load_ro_index: ?u16 = null,...@@ -65,12 +111,10 @@ phdr_load_ro_index: ?u16 = null,
65/// The index into the program headers of a PT_LOAD program header with Write flag111/// The index into the program headers of a PT_LOAD program header with Write flag
66phdr_load_rw_index: ?u16 = null,112phdr_load_rw_index: ?u16 = null,
67113
68phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
69
70entry_addr: ?u64 = null,114entry_addr: ?u64 = null,
71page_size: u32,115page_size: u32,
72116
73shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},117shstrtab: StringTable(.strtab) = .{},
74shstrtab_index: ?u16 = null,118shstrtab_index: ?u16 = null,
75119
76symtab_section_index: ?u16 = null,120symtab_section_index: ?u16 = null,
...@@ -113,39 +157,14 @@ debug_line_header_dirty: bool = false,...@@ -113,39 +157,14 @@ debug_line_header_dirty: bool = false,
113157
114error_flags: File.ErrorFlags = File.ErrorFlags{},158error_flags: File.ErrorFlags = File.ErrorFlags{},
115159
116/// Pointer to the last allocated atom160/// Table of tracked Decls.
117atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{},161decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
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) = .{},
141162
142/// List of atoms that are owned directly by the linker.163/// List of atoms that are owned directly by the linker.
143/// Currently these are only atoms that are the result of linking164atoms: std.ArrayListUnmanaged(Atom) = .{},
144/// object files. Atoms which take part in incremental linking are165
145/// at present owned by Module.Decl.166/// Table of atoms indexed by the symbol index.
146/// TODO consolidate this.167atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},
148atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{},
149168
150/// Table of unnamed constants associated with a parent `Decl`.169/// Table of unnamed constants associated with a parent `Decl`.
151/// We store them here so that we can free the constants whenever the `Decl`170/// We store them here so that we can free the constants whenever the `Decl`
...@@ -173,15 +192,8 @@ unnamed_const_atoms: UnnamedConstTable = .{},...@@ -173,15 +192,8 @@ unnamed_const_atoms: UnnamedConstTable = .{},
173/// this will be a table indexed by index into the list of Atoms.192/// this will be a table indexed by index into the list of Atoms.
174relocs: RelocTable = .{},193relocs: RelocTable = .{},
175194
176const Reloc = struct {195const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
177 target: u32,196const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
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));
185197
186/// When allocating, the ideal_capacity is calculated by198/// When allocating, the ideal_capacity is calculated by
187/// actual_capacity + (actual_capacity / ideal_factor)199/// actual_capacity + (actual_capacity / ideal_factor)
...@@ -190,15 +202,11 @@ const ideal_factor = 3;...@@ -190,15 +202,11 @@ const ideal_factor = 3;
190/// In order for a slice of bytes to be considered eligible to keep metadata pointing at202/// In order for a slice of bytes to be considered eligible to keep metadata pointing at
191/// it as a possible place to put new symbols, it must have enough room for this many bytes203/// it as a possible place to put new symbols, it must have enough room for this many bytes
192/// (plus extra for reserved capacity).204/// (plus extra for reserved capacity).
193const minimum_text_block_size = 64;205const minimum_atom_size = 64;
194pub const min_text_capacity = padToIdeal(minimum_text_block_size);206pub const min_text_capacity = padToIdeal(minimum_atom_size);
195207
196pub const PtrWidth = enum { p32, p64 };208pub const PtrWidth = enum { p32, p64 };
197209
198pub const Export = struct {
199 sym_index: ?u32 = null,
200};
201
202pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {210pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
203 assert(options.target.ofmt == .elf);211 assert(options.target.ofmt == .elf);
204212
...@@ -230,16 +238,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -230,16 +238,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
230238
231 // There must always be a null section in index 0239 // There must always be a null section in index 0
232 try self.sections.append(allocator, .{240 try self.sections.append(allocator, .{
233 .sh_name = 0,241 .shdr = .{
234 .sh_type = elf.SHT_NULL,242 .sh_name = 0,
235 .sh_flags = 0,243 .sh_type = elf.SHT_NULL,
236 .sh_addr = 0,244 .sh_flags = 0,
237 .sh_offset = 0,245 .sh_addr = 0,
238 .sh_size = 0,246 .sh_offset = 0,
239 .sh_link = 0,247 .sh_size = 0,
240 .sh_info = 0,248 .sh_link = 0,
241 .sh_addralign = 0,249 .sh_info = 0,
242 .sh_entsize = 0,250 .sh_addralign = 0,
251 .sh_entsize = 0,
252 },
253 .phdr_index = undefined,
243 });254 });
244255
245 try self.populateMissingMetadata();256 try self.populateMissingMetadata();
...@@ -286,75 +297,67 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {...@@ -286,75 +297,67 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
286}297}
287298
288pub fn deinit(self: *Elf) void {299pub fn deinit(self: *Elf) void {
300 const gpa = self.base.allocator;
301
289 if (build_options.have_llvm) {302 if (build_options.have_llvm) {
290 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);303 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
291 }304 }
292305
293 self.sections.deinit(self.base.allocator);306 for (self.sections.items(.free_list)) |*free_list| {
294 self.program_headers.deinit(self.base.allocator);307 free_list.deinit(gpa);
295 self.shstrtab.deinit(self.base.allocator);308 }
296 self.local_symbols.deinit(self.base.allocator);309 self.sections.deinit(gpa);
297 self.global_symbols.deinit(self.base.allocator);310
298 self.global_symbol_free_list.deinit(self.base.allocator);311 self.program_headers.deinit(gpa);
299 self.local_symbol_free_list.deinit(self.base.allocator);312 self.shstrtab.deinit(gpa);
300 self.offset_table_free_list.deinit(self.base.allocator);313 self.local_symbols.deinit(gpa);
301 self.offset_table.deinit(self.base.allocator);314 self.global_symbols.deinit(gpa);
302 self.phdr_shdr_table.deinit(self.base.allocator);315 self.global_symbol_free_list.deinit(gpa);
303 self.decls.deinit(self.base.allocator);316 self.local_symbol_free_list.deinit(gpa);
304317 self.offset_table_free_list.deinit(gpa);
305 self.atoms.deinit(self.base.allocator);318 self.offset_table.deinit(gpa);
319
306 {320 {
307 var it = self.atom_free_lists.valueIterator();321 var it = self.decls.iterator();
308 while (it.next()) |free_list| {322 while (it.next()) |entry| {
309 free_list.deinit(self.base.allocator);323 entry.value_ptr.exports.deinit(gpa);
310 }324 }
311 self.atom_free_lists.deinit(self.base.allocator);325 self.decls.deinit(gpa);
312 }326 }
313327
314 for (self.managed_atoms.items) |atom| {328 self.atoms.deinit(gpa);
315 self.base.allocator.destroy(atom);329 self.atom_by_index_table.deinit(gpa);
316 }
317 self.managed_atoms.deinit(self.base.allocator);
318330
319 {331 {
320 var it = self.unnamed_const_atoms.valueIterator();332 var it = self.unnamed_const_atoms.valueIterator();
321 while (it.next()) |atoms| {333 while (it.next()) |atoms| {
322 atoms.deinit(self.base.allocator);334 atoms.deinit(gpa);
323 }335 }
324 self.unnamed_const_atoms.deinit(self.base.allocator);336 self.unnamed_const_atoms.deinit(gpa);
325 }337 }
326338
327 {339 {
328 var it = self.relocs.valueIterator();340 var it = self.relocs.valueIterator();
329 while (it.next()) |relocs| {341 while (it.next()) |relocs| {
330 relocs.deinit(self.base.allocator);342 relocs.deinit(gpa);
331 }343 }
332 self.relocs.deinit(self.base.allocator);344 self.relocs.deinit(gpa);
333 }345 }
334346
335 self.atom_by_index_table.deinit(self.base.allocator);
336
337 if (self.dwarf) |*dw| {347 if (self.dwarf) |*dw| {
338 dw.deinit();348 dw.deinit();
339 }349 }
340}350}
341351
342pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 {352pub 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
346 assert(self.llvm_object == null);353 assert(self.llvm_object == null);
347354
348 try decl.link.elf.ensureInitialized(self);355 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
349 const target = decl.link.elf.getSymbolIndex().?;356 const this_atom = self.getAtom(this_atom_index);
350357 const target = this_atom.getSymbolIndex().?;
351 const vaddr = self.local_symbols.items[target].st_value;358 const vaddr = this_atom.getSymbol(self).st_value;
352 const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?;359 const atom_index = self.getAtomIndexForSymbol(reloc_info.parent_atom_index).?;
353 const gop = try self.relocs.getOrPut(self.base.allocator, atom);360 try Atom.addRelocation(self, atom_index, .{
354 if (!gop.found_existing) {
355 gop.value_ptr.* = .{};
356 }
357 try gop.value_ptr.append(self.base.allocator, .{
358 .target = target,361 .target = target,
359 .offset = reloc_info.offset,362 .offset = reloc_info.offset,
360 .addend = reloc_info.addend,363 .addend = reloc_info.addend,
...@@ -375,7 +378,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -375,7 +378,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
375378
376 if (self.shdr_table_offset) |off| {379 if (self.shdr_table_offset) |off| {
377 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);380 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;
379 const increased_size = padToIdeal(tight_size);382 const increased_size = padToIdeal(tight_size);
380 const test_end = off + increased_size;383 const test_end = off + increased_size;
381 if (end > off and start < test_end) {384 if (end > off and start < test_end) {
...@@ -385,7 +388,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -385,7 +388,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
385388
386 if (self.phdr_table_offset) |off| {389 if (self.phdr_table_offset) |off| {
387 const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);390 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;
389 const increased_size = padToIdeal(tight_size);392 const increased_size = padToIdeal(tight_size);
390 const test_end = off + increased_size;393 const test_end = off + increased_size;
391 if (end > off and start < test_end) {394 if (end > off and start < test_end) {
...@@ -393,7 +396,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -393,7 +396,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
393 }396 }
394 }397 }
395398
396 for (self.sections.items) |section| {399 for (self.sections.items(.shdr)) |section| {
397 const increased_size = padToIdeal(section.sh_size);400 const increased_size = padToIdeal(section.sh_size);
398 const test_end = section.sh_offset + increased_size;401 const test_end = section.sh_offset + increased_size;
399 if (end > section.sh_offset and start < test_end) {402 if (end > section.sh_offset and start < test_end) {
...@@ -420,7 +423,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {...@@ -420,7 +423,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
420 if (self.phdr_table_offset) |off| {423 if (self.phdr_table_offset) |off| {
421 if (off > start and off < min_pos) min_pos = off;424 if (off > start and off < min_pos) min_pos = off;
422 }425 }
423 for (self.sections.items) |section| {426 for (self.sections.items(.shdr)) |section| {
424 if (section.sh_offset <= start) continue;427 if (section.sh_offset <= start) continue;
425 if (section.sh_offset < min_pos) min_pos = section.sh_offset;428 if (section.sh_offset < min_pos) min_pos = section.sh_offset;
426 }429 }
...@@ -439,31 +442,10 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {...@@ -439,31 +442,10 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
439 return start;442 return start;
440}443}
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
464pub fn populateMissingMetadata(self: *Elf) !void {445pub fn populateMissingMetadata(self: *Elf) !void {
465 assert(self.llvm_object == null);446 assert(self.llvm_object == null);
466447
448 const gpa = self.base.allocator;
467 const small_ptr = switch (self.ptr_width) {449 const small_ptr = switch (self.ptr_width) {
468 .p32 => true,450 .p32 => true,
469 .p64 => false,451 .p64 => false,
...@@ -477,7 +459,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -477,7 +459,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
477 const off = self.findFreeSpace(file_size, p_align);459 const off = self.findFreeSpace(file_size, p_align);
478 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });460 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
479 const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;461 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, .{
481 .p_type = elf.PT_LOAD,463 .p_type = elf.PT_LOAD,
482 .p_offset = off,464 .p_offset = off,
483 .p_filesz = file_size,465 .p_filesz = file_size,
...@@ -487,7 +469,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -487,7 +469,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
487 .p_align = p_align,469 .p_align = p_align,
488 .p_flags = elf.PF_X | elf.PF_R,470 .p_flags = elf.PF_X | elf.PF_R,
489 });471 });
490 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_re_index.?, .{});
491 self.entry_addr = null;472 self.entry_addr = null;
492 self.phdr_table_dirty = true;473 self.phdr_table_dirty = true;
493 }474 }
...@@ -504,7 +485,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -504,7 +485,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
504 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something485 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
505 // else in virtual memory.486 // else in virtual memory.
506 const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;487 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, .{
508 .p_type = elf.PT_LOAD,489 .p_type = elf.PT_LOAD,
509 .p_offset = off,490 .p_offset = off,
510 .p_filesz = file_size,491 .p_filesz = file_size,
...@@ -527,7 +508,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -527,7 +508,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
527 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });508 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
528 // TODO Same as for GOT509 // TODO Same as for GOT
529 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;510 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, .{
531 .p_type = elf.PT_LOAD,512 .p_type = elf.PT_LOAD,
532 .p_offset = off,513 .p_offset = off,
533 .p_filesz = file_size,514 .p_filesz = file_size,
...@@ -537,7 +518,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -537,7 +518,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
537 .p_align = p_align,518 .p_align = p_align,
538 .p_flags = elf.PF_R,519 .p_flags = elf.PF_R,
539 });520 });
540 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_ro_index.?, .{});
541 self.phdr_table_dirty = true;521 self.phdr_table_dirty = true;
542 }522 }
543523
...@@ -551,7 +531,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -551,7 +531,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
551 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });531 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
552 // TODO Same as for GOT532 // TODO Same as for GOT
553 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;533 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, .{
555 .p_type = elf.PT_LOAD,535 .p_type = elf.PT_LOAD,
556 .p_offset = off,536 .p_offset = off,
557 .p_filesz = file_size,537 .p_filesz = file_size,
...@@ -561,148 +541,145 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -561,148 +541,145 @@ pub fn populateMissingMetadata(self: *Elf) !void {
561 .p_align = p_align,541 .p_align = p_align,
562 .p_flags = elf.PF_R | elf.PF_W,542 .p_flags = elf.PF_R | elf.PF_W,
563 });543 });
564 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_rw_index.?, .{});
565 self.phdr_table_dirty = true;544 self.phdr_table_dirty = true;
566 }545 }
567546
568 if (self.shstrtab_index == null) {547 if (self.shstrtab_index == null) {
569 self.shstrtab_index = @intCast(u16, self.sections.items.len);548 self.shstrtab_index = @intCast(u16, self.sections.slice().len);
570 assert(self.shstrtab.items.len == 0);549 assert(self.shstrtab.buffer.items.len == 0);
571 try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0550 try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0
572 const off = self.findFreeSpace(self.shstrtab.items.len, 1);551 const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);
573 log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.items.len });552 log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.buffer.items.len });
574 try self.sections.append(self.base.allocator, .{553 try self.sections.append(gpa, .{
575 .sh_name = try self.makeString(".shstrtab"),554 .shdr = .{
576 .sh_type = elf.SHT_STRTAB,555 .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"),
577 .sh_flags = 0,556 .sh_type = elf.SHT_STRTAB,
578 .sh_addr = 0,557 .sh_flags = 0,
579 .sh_offset = off,558 .sh_addr = 0,
580 .sh_size = self.shstrtab.items.len,559 .sh_offset = off,
581 .sh_link = 0,560 .sh_size = self.shstrtab.buffer.items.len,
582 .sh_info = 0,561 .sh_link = 0,
583 .sh_addralign = 1,562 .sh_info = 0,
584 .sh_entsize = 0,563 .sh_addralign = 1,
564 .sh_entsize = 0,
565 },
566 .phdr_index = undefined,
585 });567 });
586 self.shstrtab_dirty = true;568 self.shstrtab_dirty = true;
587 self.shdr_table_dirty = true;569 self.shdr_table_dirty = true;
588 }570 }
589571
590 if (self.text_section_index == null) {572 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);
592 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];574 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
593575
594 try self.sections.append(self.base.allocator, .{576 try self.sections.append(gpa, .{
595 .sh_name = try self.makeString(".text"),577 .shdr = .{
596 .sh_type = elf.SHT_PROGBITS,578 .sh_name = try self.shstrtab.insert(gpa, ".text"),
597 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,579 .sh_type = elf.SHT_PROGBITS,
598 .sh_addr = phdr.p_vaddr,580 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
599 .sh_offset = phdr.p_offset,581 .sh_addr = phdr.p_vaddr,
600 .sh_size = phdr.p_filesz,582 .sh_offset = phdr.p_offset,
601 .sh_link = 0,583 .sh_size = phdr.p_filesz,
602 .sh_info = 0,584 .sh_link = 0,
603 .sh_addralign = 1,585 .sh_info = 0,
604 .sh_entsize = 0,586 .sh_addralign = 1,
587 .sh_entsize = 0,
588 },
589 .phdr_index = self.phdr_load_re_index.?,
605 });590 });
606 try self.phdr_shdr_table.putNoClobber(
607 self.base.allocator,
608 self.phdr_load_re_index.?,
609 self.text_section_index.?,
610 );
611 self.shdr_table_dirty = true;591 self.shdr_table_dirty = true;
612 }592 }
613593
614 if (self.got_section_index == null) {594 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);
616 const phdr = &self.program_headers.items[self.phdr_got_index.?];596 const phdr = &self.program_headers.items[self.phdr_got_index.?];
617597
618 try self.sections.append(self.base.allocator, .{598 try self.sections.append(gpa, .{
619 .sh_name = try self.makeString(".got"),599 .shdr = .{
620 .sh_type = elf.SHT_PROGBITS,600 .sh_name = try self.shstrtab.insert(gpa, ".got"),
621 .sh_flags = elf.SHF_ALLOC,601 .sh_type = elf.SHT_PROGBITS,
622 .sh_addr = phdr.p_vaddr,602 .sh_flags = elf.SHF_ALLOC,
623 .sh_offset = phdr.p_offset,603 .sh_addr = phdr.p_vaddr,
624 .sh_size = phdr.p_filesz,604 .sh_offset = phdr.p_offset,
625 .sh_link = 0,605 .sh_size = phdr.p_filesz,
626 .sh_info = 0,606 .sh_link = 0,
627 .sh_addralign = @as(u16, ptr_size),607 .sh_info = 0,
628 .sh_entsize = 0,608 .sh_addralign = @as(u16, ptr_size),
609 .sh_entsize = 0,
610 },
611 .phdr_index = self.phdr_got_index.?,
629 });612 });
630 try self.phdr_shdr_table.putNoClobber(
631 self.base.allocator,
632 self.phdr_got_index.?,
633 self.got_section_index.?,
634 );
635 self.shdr_table_dirty = true;613 self.shdr_table_dirty = true;
636 }614 }
637615
638 if (self.rodata_section_index == null) {616 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);
640 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];618 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];
641619
642 try self.sections.append(self.base.allocator, .{620 try self.sections.append(gpa, .{
643 .sh_name = try self.makeString(".rodata"),621 .shdr = .{
644 .sh_type = elf.SHT_PROGBITS,622 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
645 .sh_flags = elf.SHF_ALLOC,623 .sh_type = elf.SHT_PROGBITS,
646 .sh_addr = phdr.p_vaddr,624 .sh_flags = elf.SHF_ALLOC,
647 .sh_offset = phdr.p_offset,625 .sh_addr = phdr.p_vaddr,
648 .sh_size = phdr.p_filesz,626 .sh_offset = phdr.p_offset,
649 .sh_link = 0,627 .sh_size = phdr.p_filesz,
650 .sh_info = 0,628 .sh_link = 0,
651 .sh_addralign = 1,629 .sh_info = 0,
652 .sh_entsize = 0,630 .sh_addralign = 1,
631 .sh_entsize = 0,
632 },
633 .phdr_index = self.phdr_load_ro_index.?,
653 });634 });
654 try self.phdr_shdr_table.putNoClobber(
655 self.base.allocator,
656 self.phdr_load_ro_index.?,
657 self.rodata_section_index.?,
658 );
659 self.shdr_table_dirty = true;635 self.shdr_table_dirty = true;
660 }636 }
661637
662 if (self.data_section_index == null) {638 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);
664 const phdr = &self.program_headers.items[self.phdr_load_rw_index.?];640 const phdr = &self.program_headers.items[self.phdr_load_rw_index.?];
665641
666 try self.sections.append(self.base.allocator, .{642 try self.sections.append(gpa, .{
667 .sh_name = try self.makeString(".data"),643 .shdr = .{
668 .sh_type = elf.SHT_PROGBITS,644 .sh_name = try self.shstrtab.insert(gpa, ".data"),
669 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,645 .sh_type = elf.SHT_PROGBITS,
670 .sh_addr = phdr.p_vaddr,646 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
671 .sh_offset = phdr.p_offset,647 .sh_addr = phdr.p_vaddr,
672 .sh_size = phdr.p_filesz,648 .sh_offset = phdr.p_offset,
673 .sh_link = 0,649 .sh_size = phdr.p_filesz,
674 .sh_info = 0,650 .sh_link = 0,
675 .sh_addralign = @as(u16, ptr_size),651 .sh_info = 0,
676 .sh_entsize = 0,652 .sh_addralign = @as(u16, ptr_size),
653 .sh_entsize = 0,
654 },
655 .phdr_index = self.phdr_load_rw_index.?,
677 });656 });
678 try self.phdr_shdr_table.putNoClobber(
679 self.base.allocator,
680 self.phdr_load_rw_index.?,
681 self.data_section_index.?,
682 );
683 self.shdr_table_dirty = true;657 self.shdr_table_dirty = true;
684 }658 }
685659
686 if (self.symtab_section_index == null) {660 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);
688 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);662 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
689 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);663 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
690 const file_size = self.base.options.symbol_count_hint * each_size;664 const file_size = self.base.options.symbol_count_hint * each_size;
691 const off = self.findFreeSpace(file_size, min_align);665 const off = self.findFreeSpace(file_size, min_align);
692 log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size });666 log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size });
693667
694 try self.sections.append(self.base.allocator, .{668 try self.sections.append(gpa, .{
695 .sh_name = try self.makeString(".symtab"),669 .shdr = .{
696 .sh_type = elf.SHT_SYMTAB,670 .sh_name = try self.shstrtab.insert(gpa, ".symtab"),
697 .sh_flags = 0,671 .sh_type = elf.SHT_SYMTAB,
698 .sh_addr = 0,672 .sh_flags = 0,
699 .sh_offset = off,673 .sh_addr = 0,
700 .sh_size = file_size,674 .sh_offset = off,
701 // The section header index of the associated string table.675 .sh_size = file_size,
702 .sh_link = self.shstrtab_index.?,676 // The section header index of the associated string table.
703 .sh_info = @intCast(u32, self.local_symbols.items.len),677 .sh_link = self.shstrtab_index.?,
704 .sh_addralign = min_align,678 .sh_info = @intCast(u32, self.local_symbols.items.len),
705 .sh_entsize = each_size,679 .sh_addralign = min_align,
680 .sh_entsize = each_size,
681 },
682 .phdr_index = undefined,
706 });683 });
707 self.shdr_table_dirty = true;684 self.shdr_table_dirty = true;
708 try self.writeSymbol(0);685 try self.writeSymbol(0);
...@@ -710,27 +687,30 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -710,27 +687,30 @@ pub fn populateMissingMetadata(self: *Elf) !void {
710687
711 if (self.dwarf) |*dw| {688 if (self.dwarf) |*dw| {
712 if (self.debug_str_section_index == null) {689 if (self.debug_str_section_index == null) {
713 self.debug_str_section_index = @intCast(u16, self.sections.items.len);690 self.debug_str_section_index = @intCast(u16, self.sections.slice().len);
714 assert(dw.strtab.items.len == 0);691 assert(dw.strtab.buffer.items.len == 0);
715 try dw.strtab.append(self.base.allocator, 0);692 try dw.strtab.buffer.append(gpa, 0);
716 try self.sections.append(self.base.allocator, .{693 try self.sections.append(gpa, .{
717 .sh_name = try self.makeString(".debug_str"),694 .shdr = .{
718 .sh_type = elf.SHT_PROGBITS,695 .sh_name = try self.shstrtab.insert(gpa, ".debug_str"),
719 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,696 .sh_type = elf.SHT_PROGBITS,
720 .sh_addr = 0,697 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
721 .sh_offset = 0,698 .sh_addr = 0,
722 .sh_size = 0,699 .sh_offset = 0,
723 .sh_link = 0,700 .sh_size = 0,
724 .sh_info = 0,701 .sh_link = 0,
725 .sh_addralign = 1,702 .sh_info = 0,
726 .sh_entsize = 1,703 .sh_addralign = 1,
704 .sh_entsize = 1,
705 },
706 .phdr_index = undefined,
727 });707 });
728 self.debug_strtab_dirty = true;708 self.debug_strtab_dirty = true;
729 self.shdr_table_dirty = true;709 self.shdr_table_dirty = true;
730 }710 }
731711
732 if (self.debug_info_section_index == null) {712 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
735 const file_size_hint = 200;715 const file_size_hint = 200;
736 const p_align = 1;716 const p_align = 1;
...@@ -739,24 +719,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -739,24 +719,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {
739 off,719 off,
740 off + file_size_hint,720 off + file_size_hint,
741 });721 });
742 try self.sections.append(self.base.allocator, .{722 try self.sections.append(gpa, .{
743 .sh_name = try self.makeString(".debug_info"),723 .shdr = .{
744 .sh_type = elf.SHT_PROGBITS,724 .sh_name = try self.shstrtab.insert(gpa, ".debug_info"),
745 .sh_flags = 0,725 .sh_type = elf.SHT_PROGBITS,
746 .sh_addr = 0,726 .sh_flags = 0,
747 .sh_offset = off,727 .sh_addr = 0,
748 .sh_size = file_size_hint,728 .sh_offset = off,
749 .sh_link = 0,729 .sh_size = file_size_hint,
750 .sh_info = 0,730 .sh_link = 0,
751 .sh_addralign = p_align,731 .sh_info = 0,
752 .sh_entsize = 0,732 .sh_addralign = p_align,
733 .sh_entsize = 0,
734 },
735 .phdr_index = undefined,
753 });736 });
754 self.shdr_table_dirty = true;737 self.shdr_table_dirty = true;
755 self.debug_info_header_dirty = true;738 self.debug_info_header_dirty = true;
756 }739 }
757740
758 if (self.debug_abbrev_section_index == null) {741 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
761 const file_size_hint = 128;744 const file_size_hint = 128;
762 const p_align = 1;745 const p_align = 1;
...@@ -765,24 +748,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -765,24 +748,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {
765 off,748 off,
766 off + file_size_hint,749 off + file_size_hint,
767 });750 });
768 try self.sections.append(self.base.allocator, .{751 try self.sections.append(gpa, .{
769 .sh_name = try self.makeString(".debug_abbrev"),752 .shdr = .{
770 .sh_type = elf.SHT_PROGBITS,753 .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"),
771 .sh_flags = 0,754 .sh_type = elf.SHT_PROGBITS,
772 .sh_addr = 0,755 .sh_flags = 0,
773 .sh_offset = off,756 .sh_addr = 0,
774 .sh_size = file_size_hint,757 .sh_offset = off,
775 .sh_link = 0,758 .sh_size = file_size_hint,
776 .sh_info = 0,759 .sh_link = 0,
777 .sh_addralign = p_align,760 .sh_info = 0,
778 .sh_entsize = 0,761 .sh_addralign = p_align,
762 .sh_entsize = 0,
763 },
764 .phdr_index = undefined,
779 });765 });
780 self.shdr_table_dirty = true;766 self.shdr_table_dirty = true;
781 self.debug_abbrev_section_dirty = true;767 self.debug_abbrev_section_dirty = true;
782 }768 }
783769
784 if (self.debug_aranges_section_index == null) {770 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
787 const file_size_hint = 160;773 const file_size_hint = 160;
788 const p_align = 16;774 const p_align = 16;
...@@ -791,24 +777,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -791,24 +777,27 @@ pub fn populateMissingMetadata(self: *Elf) !void {
791 off,777 off,
792 off + file_size_hint,778 off + file_size_hint,
793 });779 });
794 try self.sections.append(self.base.allocator, .{780 try self.sections.append(gpa, .{
795 .sh_name = try self.makeString(".debug_aranges"),781 .shdr = .{
796 .sh_type = elf.SHT_PROGBITS,782 .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"),
797 .sh_flags = 0,783 .sh_type = elf.SHT_PROGBITS,
798 .sh_addr = 0,784 .sh_flags = 0,
799 .sh_offset = off,785 .sh_addr = 0,
800 .sh_size = file_size_hint,786 .sh_offset = off,
801 .sh_link = 0,787 .sh_size = file_size_hint,
802 .sh_info = 0,788 .sh_link = 0,
803 .sh_addralign = p_align,789 .sh_info = 0,
804 .sh_entsize = 0,790 .sh_addralign = p_align,
791 .sh_entsize = 0,
792 },
793 .phdr_index = undefined,
805 });794 });
806 self.shdr_table_dirty = true;795 self.shdr_table_dirty = true;
807 self.debug_aranges_section_dirty = true;796 self.debug_aranges_section_dirty = true;
808 }797 }
809798
810 if (self.debug_line_section_index == null) {799 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
813 const file_size_hint = 250;802 const file_size_hint = 250;
814 const p_align = 1;803 const p_align = 1;
...@@ -817,17 +806,20 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -817,17 +806,20 @@ pub fn populateMissingMetadata(self: *Elf) !void {
817 off,806 off,
818 off + file_size_hint,807 off + file_size_hint,
819 });808 });
820 try self.sections.append(self.base.allocator, .{809 try self.sections.append(gpa, .{
821 .sh_name = try self.makeString(".debug_line"),810 .shdr = .{
822 .sh_type = elf.SHT_PROGBITS,811 .sh_name = try self.shstrtab.insert(gpa, ".debug_line"),
823 .sh_flags = 0,812 .sh_type = elf.SHT_PROGBITS,
824 .sh_addr = 0,813 .sh_flags = 0,
825 .sh_offset = off,814 .sh_addr = 0,
826 .sh_size = file_size_hint,815 .sh_offset = off,
827 .sh_link = 0,816 .sh_size = file_size_hint,
828 .sh_info = 0,817 .sh_link = 0,
829 .sh_addralign = p_align,818 .sh_info = 0,
830 .sh_entsize = 0,819 .sh_addralign = p_align,
820 .sh_entsize = 0,
821 },
822 .phdr_index = undefined,
831 });823 });
832 self.shdr_table_dirty = true;824 self.shdr_table_dirty = true;
833 self.debug_line_header_dirty = true;825 self.debug_line_header_dirty = true;
...@@ -843,7 +835,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -843,7 +835,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
843 .p64 => @alignOf(elf.Elf64_Shdr),835 .p64 => @alignOf(elf.Elf64_Shdr),
844 };836 };
845 if (self.shdr_table_offset == null) {837 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);
847 self.shdr_table_dirty = true;839 self.shdr_table_dirty = true;
848 }840 }
849841
...@@ -874,7 +866,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -874,7 +866,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
874 // offset + it's filesize.866 // offset + it's filesize.
875 var max_file_offset: u64 = 0;867 var max_file_offset: u64 = 0;
876868
877 for (self.sections.items) |shdr| {869 for (self.sections.items(.shdr)) |shdr| {
878 if (shdr.sh_offset + shdr.sh_size > max_file_offset) {870 if (shdr.sh_offset + shdr.sh_size > max_file_offset) {
879 max_file_offset = shdr.sh_offset + shdr.sh_size;871 max_file_offset = shdr.sh_offset + shdr.sh_size;
880 }872 }
...@@ -884,15 +876,18 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -884,15 +876,18 @@ pub fn populateMissingMetadata(self: *Elf) !void {
884 }876 }
885}877}
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 {
888 // TODO Also detect virtual address collisions.880 // 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];
890 const phdr = &self.program_headers.items[phdr_index];883 const phdr = &self.program_headers.items[phdr_index];
884 const maybe_last_atom_index = self.sections.items(.last_atom_index)[shdr_index];
891885
892 if (needed_size > self.allocatedSize(shdr.sh_offset)) {886 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
893 // Must move the entire section.887 // Must move the entire section.
894 const new_offset = self.findFreeSpace(needed_size, self.page_size);888 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);
896 const sym = last.getSymbol(self);891 const sym = last.getSymbol(self);
897 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;892 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
898 } else if (shdr_index == self.got_section_index.?) blk: {893 } 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...@@ -900,8 +895,8 @@ fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u
900 } else 0;895 } else 0;
901 shdr.sh_size = 0;896 shdr.sh_size = 0;
902897
903 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{898 log.debug("new '{?s}' file offset 0x{x} to 0x{x}", .{
904 self.getString(shdr.sh_name),899 self.shstrtab.get(shdr.sh_name),
905 new_offset,900 new_offset,
906 new_offset + existing_size,901 new_offset + existing_size,
907 });902 });
...@@ -927,7 +922,7 @@ pub fn growNonAllocSection(...@@ -927,7 +922,7 @@ pub fn growNonAllocSection(
927 min_alignment: u32,922 min_alignment: u32,
928 requires_file_copy: bool,923 requires_file_copy: bool,
929) !void {924) !void {
930 const shdr = &self.sections.items[shdr_index];925 const shdr = &self.sections.items(.shdr)[shdr_index];
931926
932 if (needed_size > self.allocatedSize(shdr.sh_offset)) {927 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
933 const existing_size = if (self.symtab_section_index.? == shdr_index) blk: {928 const existing_size = if (self.symtab_section_index.? == shdr_index) blk: {
...@@ -940,7 +935,7 @@ pub fn growNonAllocSection(...@@ -940,7 +935,7 @@ pub fn growNonAllocSection(
940 shdr.sh_size = 0;935 shdr.sh_size = 0;
941 // Move all the symbols to a new file location.936 // Move all the symbols to a new file location.
942 const new_offset = self.findFreeSpace(needed_size, min_alignment);937 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
945 if (requires_file_copy) {940 if (requires_file_copy) {
946 const amt = try self.base.file.?.copyRangeAll(941 const amt = try self.base.file.?.copyRangeAll(
...@@ -1011,6 +1006,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1011,6 +1006,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1011 }1006 }
1012 }1007 }
10131008
1009 const gpa = self.base.allocator;
1014 var sub_prog_node = prog_node.start("ELF Flush", 0);1010 var sub_prog_node = prog_node.start("ELF Flush", 0);
1015 sub_prog_node.activate();1011 sub_prog_node.activate();
1016 defer sub_prog_node.end();1012 defer sub_prog_node.end();
...@@ -1029,12 +1025,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1029,12 +1025,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1029 {1025 {
1030 var it = self.relocs.iterator();1026 var it = self.relocs.iterator();
1031 while (it.next()) |entry| {1027 while (it.next()) |entry| {
1032 const atom = entry.key_ptr.*;1028 const atom_index = entry.key_ptr.*;
1033 const relocs = entry.value_ptr.*;1029 const relocs = entry.value_ptr.*;
1030 const atom = self.getAtom(atom_index);
1034 const source_sym = atom.getSymbol(self);1031 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
1039 for (relocs.items) |*reloc| {1036 for (relocs.items) |*reloc| {
1040 const target_sym = self.local_symbols.items[reloc.target];1037 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...@@ -1045,10 +1042,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1045 const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr;1042 const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr;
1046 const file_offset = source_shdr.sh_offset + section_offset;1043 const file_offset = source_shdr.sh_offset + section_offset;
10471044
1048 log.debug(" ({x}: [() => 0x{x}] ({s}))", .{1045 log.debug(" ({x}: [() => 0x{x}] ({?s}))", .{
1049 reloc.offset,1046 reloc.offset,
1050 target_vaddr,1047 target_vaddr,
1051 self.getString(target_sym.st_name),1048 self.shstrtab.get(target_sym.st_name),
1052 });1049 });
10531050
1054 switch (self.ptr_width) {1051 switch (self.ptr_width) {
...@@ -1126,8 +1123,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1126,8 +1123,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11261123
1127 switch (self.ptr_width) {1124 switch (self.ptr_width) {
1128 .p32 => {1125 .p32 => {
1129 const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);1126 const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
1130 defer self.base.allocator.free(buf);1127 defer gpa.free(buf);
11311128
1132 for (buf) |*phdr, i| {1129 for (buf) |*phdr, i| {
1133 phdr.* = progHeaderTo32(self.program_headers.items[i]);1130 phdr.* = progHeaderTo32(self.program_headers.items[i]);
...@@ -1138,8 +1135,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1138,8 +1135,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1138 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);1135 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
1139 },1136 },
1140 .p64 => {1137 .p64 => {
1141 const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);1138 const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
1142 defer self.base.allocator.free(buf);1139 defer gpa.free(buf);
11431140
1144 for (buf) |*phdr, i| {1141 for (buf) |*phdr, i| {
1145 phdr.* = self.program_headers.items[i];1142 phdr.* = self.program_headers.items[i];
...@@ -1155,20 +1152,20 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1155,20 +1152,20 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11551152
1156 {1153 {
1157 const shdr_index = self.shstrtab_index.?;1154 const shdr_index = self.shstrtab_index.?;
1158 if (self.shstrtab_dirty or self.shstrtab.items.len != self.sections.items[shdr_index].sh_size) {1155 if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
1159 try self.growNonAllocSection(shdr_index, self.shstrtab.items.len, 1, false);1156 try self.growNonAllocSection(shdr_index, self.shstrtab.buffer.items.len, 1, false);
1160 const shstrtab_sect = self.sections.items[shdr_index];1157 const shstrtab_sect = self.sections.items(.shdr)[shdr_index];
1161 try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);1158 try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shstrtab_sect.sh_offset);
1162 self.shstrtab_dirty = false;1159 self.shstrtab_dirty = false;
1163 }1160 }
1164 }1161 }
11651162
1166 if (self.dwarf) |dwarf| {1163 if (self.dwarf) |dwarf| {
1167 const shdr_index = self.debug_str_section_index.?;1164 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) {1165 if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
1169 try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false);1166 try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false);
1170 const debug_strtab_sect = self.sections.items[shdr_index];1167 const debug_strtab_sect = self.sections.items(.shdr)[shdr_index];
1171 try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset);1168 try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset);
1172 self.debug_strtab_dirty = false;1169 self.debug_strtab_dirty = false;
1173 }1170 }
1174 }1171 }
...@@ -1183,7 +1180,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1183,7 +1180,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1183 .p64 => @alignOf(elf.Elf64_Shdr),1180 .p64 => @alignOf(elf.Elf64_Shdr),
1184 };1181 };
1185 const allocated_size = self.allocatedSize(self.shdr_table_offset.?);1182 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
1188 if (needed_size > allocated_size) {1185 if (needed_size > allocated_size) {
1189 self.shdr_table_offset = null; // free the space1186 self.shdr_table_offset = null; // free the space
...@@ -1192,12 +1189,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1192,12 +1189,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11921189
1193 switch (self.ptr_width) {1190 switch (self.ptr_width) {
1194 .p32 => {1191 .p32 => {
1195 const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);1192 const slice = self.sections.slice();
1196 defer self.base.allocator.free(buf);1193 const buf = try gpa.alloc(elf.Elf32_Shdr, slice.len);
1194 defer gpa.free(buf);
11971195
1198 for (buf) |*shdr, i| {1196 for (buf) |*shdr, i| {
1199 shdr.* = sectHeaderTo32(self.sections.items[i]);1197 shdr.* = sectHeaderTo32(slice.items(.shdr)[i]);
1200 log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* });1198 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
1201 if (foreign_endian) {1199 if (foreign_endian) {
1202 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);1200 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
1203 }1201 }
...@@ -1205,12 +1203,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1205,12 +1203,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1205 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);1203 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
1206 },1204 },
1207 .p64 => {1205 .p64 => {
1208 const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);1206 const slice = self.sections.slice();
1209 defer self.base.allocator.free(buf);1207 const buf = try gpa.alloc(elf.Elf64_Shdr, slice.len);
1208 defer gpa.free(buf);
12101209
1211 for (buf) |*shdr, i| {1210 for (buf) |*shdr, i| {
1212 shdr.* = self.sections.items[i];1211 shdr.* = slice.items(.shdr)[i];
1213 log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* });1212 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
1214 if (foreign_endian) {1213 if (foreign_endian) {
1215 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);1214 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
1216 }1215 }
...@@ -2021,7 +2020,7 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2021,7 +2020,7 @@ fn writeElfHeader(self: *Elf) !void {
2021 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);2020 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
2022 index += 2;2021 index += 2;
20232022
2024 const e_shnum = @intCast(u16, self.sections.items.len);2023 const e_shnum = @intCast(u16, self.sections.slice().len);
2025 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);2024 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
2026 index += 2;2025 index += 2;
20272026
...@@ -2033,124 +2032,145 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2033,124 +2032,145 @@ fn writeElfHeader(self: *Elf) !void {
2033 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);2032 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
2034}2033}
20352034
2036fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {2035fn freeAtom(self: *Elf, atom_index: Atom.Index) void {
2037 const local_sym = text_block.getSymbol(self);2036 const atom = self.getAtom(atom_index);
2038 const name_str_index = local_sym.st_name;2037 log.debug("freeAtom {d} ({s})", .{ atom_index, atom.getName(self) });
2039 const name = self.getString(name_str_index);
2040 log.debug("freeTextBlock {*} ({s})", .{ text_block, name });
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];
2045 var already_have_free_list_node = false;2044 var already_have_free_list_node = false;
2046 {2045 {
2047 var i: usize = 0;2046 var i: usize = 0;
2048 // TODO turn free_list into a hash map2047 // TODO turn free_list into a hash map
2049 while (i < free_list.items.len) {2048 while (i < free_list.items.len) {
2050 if (free_list.items[i] == text_block) {2049 if (free_list.items[i] == atom_index) {
2051 _ = free_list.swapRemove(i);2050 _ = free_list.swapRemove(i);
2052 continue;2051 continue;
2053 }2052 }
2054 if (free_list.items[i] == text_block.prev) {2053 if (free_list.items[i] == atom.prev_index) {
2055 already_have_free_list_node = true;2054 already_have_free_list_node = true;
2056 }2055 }
2057 i += 1;2056 i += 1;
2058 }2057 }
2059 }2058 }
20602059
2061 if (self.atoms.getPtr(phdr_index)) |last_block| {2060 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[shndx];
2062 if (last_block.* == text_block) {2061 if (maybe_last_atom_index.*) |last_atom_index| {
2063 if (text_block.prev) |prev| {2062 if (last_atom_index == atom_index) {
2063 if (atom.prev_index) |prev_index| {
2064 // TODO shrink the section size here2064 // TODO shrink the section size here
2065 last_block.* = prev;2065 maybe_last_atom_index.* = prev_index;
2066 } else {2066 } else {
2067 _ = self.atoms.fetchRemove(phdr_index);2067 maybe_last_atom_index.* = null;
2068 }2068 }
2069 }2069 }
2070 }2070 }
20712071
2072 if (text_block.prev) |prev| {2072 if (atom.prev_index) |prev_index| {
2073 prev.next = text_block.next;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)) {
2076 // The free list is heuristics, it doesn't have to be perfect, so we can2077 // The free list is heuristics, it doesn't have to be perfect, so we can
2077 // ignore the OOM here.2078 // ignore the OOM here.
2078 free_list.append(self.base.allocator, prev) catch {};2079 free_list.append(gpa, prev_index) catch {};
2079 }2080 }
2080 } else {2081 } else {
2081 text_block.prev = null;2082 self.getAtomPtr(atom_index).prev_index = null;
2082 }2083 }
20832084
2084 if (text_block.next) |next| {2085 if (atom.next_index) |next_index| {
2085 next.prev = text_block.prev;2086 self.getAtomPtr(next_index).prev_index = atom.prev_index;
2086 } else {2087 } else {
2087 text_block.next = null;2088 self.getAtomPtr(atom_index).next_index = null;
2088 }2089 }
20892090
2090 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.2091 // 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 const local_sym_index = atom.getSymbolIndex().?;
2092 self.local_symbol_free_list.append(self.base.allocator, local_sym_index) catch {};2093
2094 self.local_symbol_free_list.append(gpa, local_sym_index) catch {};
2093 self.local_symbols.items[local_sym_index].st_info = 0;2095 self.local_symbols.items[local_sym_index].st_info = 0;
2096 self.local_symbols.items[local_sym_index].st_shndx = 0;
2094 _ = self.atom_by_index_table.remove(local_sym_index);2097 _ = 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 {};2100 self.offset_table_free_list.append(self.base.allocator, atom.offset_table_index) catch {};
2098
2099 if (self.dwarf) |*dw| {
2100 dw.freeAtom(&text_block.dbg_info_atom);
2101 }
2102}2101}
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 {
2105 _ = self;2104 _ = self;
2106 _ = text_block;2105 _ = atom_index;
2107 _ = new_block_size;2106 _ = new_block_size;
2108 _ = phdr_index;
2109}2107}
21102108
2111fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {2109fn growAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 {
2112 const sym = text_block.getSymbol(self);2110 const atom = self.getAtom(atom_index);
2111 const sym = atom.getSymbol(self);
2113 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;2112 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);
2115 if (!need_realloc) return sym.st_value;2114 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;
2117}2133}
21182134
2119fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {2135fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 {
2120 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;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];
2121 const phdr = &self.program_headers.items[phdr_index];2139 const phdr = &self.program_headers.items[phdr_index];
2122 const shdr = &self.sections.items[shdr_index];2140 const shdr = &self.sections.items(.shdr)[sym.st_shndx];
2123 const new_block_ideal_capacity = padToIdeal(new_block_size);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,
2126 // and possibly removing a free list node.2146 // and possibly removing a free list node.
2127 // It would be simpler to do it inside the for loop below, but that would cause a2147 // It would be simpler to do it inside the for loop below, but that would cause a
2128 // problem if an error was returned later in the function. So this action2148 // problem if an error was returned later in the function. So this action
2129 // is actually carried out at the end of the function, when errors are no longer possible.2149 // 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;
2131 var free_list_removal: ?usize = null;2151 var free_list_removal: ?usize = null;
2132 var free_list = self.atom_free_lists.get(phdr_index).?;
21332152
2134 // First we look for an appropriately sized free list node.2153 // First we look for an appropriately sized free list node.
2135 // The list is unordered. We'll just take the first thing that works.2154 // The list is unordered. We'll just take the first thing that works.
2136 const vaddr = blk: {2155 const vaddr = blk: {
2137 var i: usize = 0;2156 var i: usize = 0;
2138 while (i < free_list.items.len) {2157 while (i < free_list.items.len) {
2139 const big_block = free_list.items[i];2158 const big_atom_index = free_list.items[i];
2140 // We now have a pointer to a live text block that has too much capacity.2159 const big_atom = self.getAtom(big_atom_index);
2141 // Is it enough that we could fit this new text block?2160 // We now have a pointer to a live atom that has too much capacity.
2142 const sym = big_block.getSymbol(self);2161 // Is it enough that we could fit this new atom?
2143 const capacity = big_block.capacity(self);2162 const big_atom_sym = big_atom.getSymbol(self);
2163 const capacity = big_atom.capacity(self);
2144 const ideal_capacity = padToIdeal(capacity);2164 const ideal_capacity = padToIdeal(capacity);
2145 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;2165 const ideal_capacity_end_vaddr = std.math.add(u64, big_atom_sym.st_value, ideal_capacity) catch ideal_capacity;
2146 const capacity_end_vaddr = sym.st_value + capacity;2166 const capacity_end_vaddr = big_atom_sym.st_value + capacity;
2147 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;2167 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
2148 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);2168 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
2149 if (new_start_vaddr < ideal_capacity_end_vaddr) {2169 if (new_start_vaddr < ideal_capacity_end_vaddr) {
2150 // Additional bookkeeping here to notice if this free list node2170 // Additional bookkeeping here to notice if this free list node
2151 // should be deleted because the block that it points to has grown to take up2171 // should be deleted because the block that it points to has grown to take up
2152 // more of the extra capacity.2172 // more of the extra capacity.
2153 if (!big_block.freeListEligible(self)) {2173 if (!big_atom.freeListEligible(self)) {
2154 _ = free_list.swapRemove(i);2174 _ = free_list.swapRemove(i);
2155 } else {2175 } else {
2156 i += 1;2176 i += 1;
...@@ -2164,29 +2184,33 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2164,29 +2184,33 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2164 const keep_free_list_node = remaining_capacity >= min_text_capacity;2184 const keep_free_list_node = remaining_capacity >= min_text_capacity;
21652185
2166 // Set up the metadata to be updated, after errors are no longer possible.2186 // Set up the metadata to be updated, after errors are no longer possible.
2167 block_placement = big_block;2187 atom_placement = big_atom_index;
2168 if (!keep_free_list_node) {2188 if (!keep_free_list_node) {
2169 free_list_removal = i;2189 free_list_removal = i;
2170 }2190 }
2171 break :blk new_start_vaddr;2191 break :blk new_start_vaddr;
2172 } else if (self.atoms.get(phdr_index)) |last| {2192 } else if (maybe_last_atom_index.*) |last_index| {
2173 const sym = last.getSymbol(self);2193 const last = self.getAtom(last_index);
2174 const ideal_capacity = padToIdeal(sym.st_size);2194 const last_sym = last.getSymbol(self);
2175 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;2195 const ideal_capacity = padToIdeal(last_sym.st_size);
2196 const ideal_capacity_end_vaddr = last_sym.st_value + ideal_capacity;
2176 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);2197 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
2177 // Set up the metadata to be updated, after errors are no longer possible.2198 // Set up the metadata to be updated, after errors are no longer possible.
2178 block_placement = last;2199 atom_placement = last_index;
2179 break :blk new_start_vaddr;2200 break :blk new_start_vaddr;
2180 } else {2201 } else {
2181 break :blk phdr.p_vaddr;2202 break :blk phdr.p_vaddr;
2182 }2203 }
2183 };2204 };
21842205
2185 const expand_text_section = block_placement == null or block_placement.?.next == null;2206 const expand_section = if (atom_placement) |placement_index|
2186 if (expand_text_section) {2207 self.getAtom(placement_index).next_index == null
2208 else
2209 true;
2210 if (expand_section) {
2187 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;2211 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
2188 try self.growAllocSection(shdr_index, phdr_index, needed_size);2212 try self.growAllocSection(sym.st_shndx, needed_size);
2189 _ = try self.atoms.put(self.base.allocator, phdr_index, text_block);2213 maybe_last_atom_index.* = atom_index;
21902214
2191 if (self.dwarf) |_| {2215 if (self.dwarf) |_| {
2192 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address2216 // 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...@@ -2201,23 +2225,28 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2201 }2225 }
2202 shdr.sh_addralign = math.max(shdr.sh_addralign, alignment);2226 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.
2205 // In this case we need to "unplug" it from its previous location before2229 // In this case we need to "unplug" it from its previous location before
2206 // plugging it in to its new location.2230 // plugging it in to its new location.
2207 if (text_block.prev) |prev| {2231 if (atom.prev_index) |prev_index| {
2208 prev.next = text_block.next;2232 const prev = self.getAtomPtr(prev_index);
2233 prev.next_index = atom.next_index;
2209 }2234 }
2210 if (text_block.next) |next| {2235 if (atom.next_index) |next_index| {
2211 next.prev = text_block.prev;2236 const next = self.getAtomPtr(next_index);
2237 next.prev_index = atom.prev_index;
2212 }2238 }
22132239
2214 if (block_placement) |big_block| {2240 if (atom_placement) |big_atom_index| {
2215 text_block.prev = big_block;2241 const big_atom = self.getAtomPtr(big_atom_index);
2216 text_block.next = big_block.next;2242 const atom_ptr = self.getAtomPtr(atom_index);
2217 big_block.next = text_block;2243 atom_ptr.prev_index = big_atom_index;
2244 atom_ptr.next_index = big_atom.next_index;
2245 big_atom.next_index = atom_index;
2218 } else {2246 } else {
2219 text_block.prev = null;2247 const atom_ptr = self.getAtomPtr(atom_index);
2220 text_block.next = null;2248 atom_ptr.prev_index = null;
2249 atom_ptr.next_index = null;
2221 }2250 }
2222 if (free_list_removal) |i| {2251 if (free_list_removal) |i| {
2223 _ = free_list.swapRemove(i);2252 _ = free_list.swapRemove(i);
...@@ -2272,15 +2301,10 @@ pub fn allocateGotOffset(self: *Elf) !u32 {...@@ -2272,15 +2301,10 @@ pub fn allocateGotOffset(self: *Elf) !u32 {
2272 return index;2301 return index;
2273}2302}
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
2280fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {2304fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
2281 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;2305 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
2282 for (unnamed_consts.items) |atom| {2306 for (unnamed_consts.items) |atom| {
2283 self.freeTextBlock(atom, self.phdr_load_ro_index.?);2307 self.freeAtom(atom);
2284 }2308 }
2285 unnamed_consts.clearAndFree(self.base.allocator);2309 unnamed_consts.clearAndFree(self.base.allocator);
2286}2310}
...@@ -2295,43 +2319,57 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {...@@ -2295,43 +2319,57 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
22952319
2296 log.debug("freeDecl {*}", .{decl});2320 log.debug("freeDecl {*}", .{decl});
22972321
2298 if (self.decls.fetchRemove(decl_index)) |kv| {2322 if (self.decls.fetchRemove(decl_index)) |const_kv| {
2299 if (kv.value) |index| {2323 var kv = const_kv;
2300 self.freeTextBlock(&decl.link.elf, index);2324 self.freeAtom(kv.value.atom);
2301 self.freeUnnamedConsts(decl_index);2325 self.freeUnnamedConsts(decl_index);
2302 }2326 kv.value.exports.deinit(self.base.allocator);
2303 }2327 }
23042328
2305 if (self.dwarf) |*dw| {2329 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 };
2307 }2342 }
2343 return gop.value_ptr.atom;
2308}2344}
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);
2311 const ty = decl.ty;2348 const ty = decl.ty;
2312 const zig_ty = ty.zigTypeTag();2349 const zig_ty = ty.zigTypeTag();
2313 const val = decl.val;2350 const val = decl.val;
2314 const phdr_index: u16 = blk: {2351 const shdr_index: u16 = blk: {
2315 if (val.isUndefDeep()) {2352 if (val.isUndefDeep()) {
2316 // TODO in release-fast and release-small, we should put undef in .bss2353 // 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.?;
2318 }2355 }
23192356
2320 switch (zig_ty) {2357 switch (zig_ty) {
2321 // TODO: what if this is a function pointer?2358 // 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.?,
2323 else => {2360 else => {
2324 if (val.castTag(.variable)) |_| {2361 if (val.castTag(.variable)) |_| {
2325 break :blk self.phdr_load_rw_index.?;2362 break :blk self.data_section_index.?;
2326 }2363 }
2327 break :blk self.phdr_load_ro_index.?;2364 break :blk self.rodata_section_index.?;
2328 },2365 },
2329 }2366 }
2330 };2367 };
2331 return phdr_index;2368 return shdr_index;
2332}2369}
23332370
2334fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {2371fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
2372 const gpa = self.base.allocator;
2335 const mod = self.base.options.module.?;2373 const mod = self.base.options.module.?;
2336 const decl = mod.declPtr(decl_index);2374 const decl = mod.declPtr(decl_index);
23372375
...@@ -2341,60 +2379,65 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2341,60 +2379,65 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2341 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });2379 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
2342 const required_alignment = decl.getAlignment(self.base.options.target);2380 const required_alignment = decl.getAlignment(self.base.options.target);
23432381
2344 const decl_ptr = self.decls.getPtr(decl_index).?;2382 const decl_metadata = self.decls.get(decl_index).?;
2345 if (decl_ptr.* == null) {2383 const atom_index = decl_metadata.atom;
2346 decl_ptr.* = try self.getDeclPhdrIndex(decl);2384 const atom = self.getAtom(atom_index);
2347 }2385
2348 const phdr_index = decl_ptr.*.?;2386 const shdr_index = decl_metadata.shdr;
2349 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;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);2394 const capacity = atom.capacity(self);
2352 if (local_sym.st_size != 0) {
2353 const capacity = decl.link.elf.capacity(self);
2354 const need_realloc = code.len > capacity or2395 const need_realloc = code.len > capacity or
2355 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);2396 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
2397
2356 if (need_realloc) {2398 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);
2358 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, local_sym.st_value, vaddr });2400 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, local_sym.st_value, vaddr });
2359 if (vaddr != local_sym.st_value) {2401 if (vaddr != local_sym.st_value) {
2360 local_sym.st_value = vaddr;2402 local_sym.st_value = vaddr;
23612403
2362 log.debug(" (writing new offset table entry)", .{});2404 log.debug(" (writing new offset table entry)", .{});
2363 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;2405 self.offset_table.items[atom.offset_table_index] = vaddr;
2364 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);2406 try self.writeOffsetTableEntry(atom.offset_table_index);
2365 }2407 }
2366 } else if (code.len < local_sym.st_size) {2408 } 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);
2368 }2410 }
2369 local_sym.st_size = code.len;2411 local_sym.st_size = code.len;
2370 local_sym.st_name = try self.updateString(local_sym.st_name, decl_name);2412
2371 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
2372 local_sym.st_other = 0;
2373 local_sym.st_shndx = shdr_index;
2374 // TODO this write could be avoided if no fields of the symbol were changed.2413 // 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().?);
2376 } else {2415 } else {
2377 const name_str_index = try self.makeString(decl_name);2416 const local_sym = atom.getSymbolPtr(self);
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
2382 local_sym.* = .{2417 local_sym.* = .{
2383 .st_name = name_str_index,2418 .st_name = try self.shstrtab.insert(gpa, decl_name),
2384 .st_info = (elf.STB_LOCAL << 4) | stt_bits,2419 .st_info = (elf.STB_LOCAL << 4) | stt_bits,
2385 .st_other = 0,2420 .st_other = 0,
2386 .st_shndx = shdr_index,2421 .st_shndx = shdr_index,
2387 .st_value = vaddr,2422 .st_value = 0,
2388 .st_size = code.len,2423 .st_size = 0,
2389 };2424 };
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().?);2429 self.offset_table.items[atom.offset_table_index] = vaddr;
2393 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);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);
2394 }2435 }
23952436
2437 const local_sym = atom.getSymbolPtr(self);
2438 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
2396 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;2439 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;
2398 try self.base.file.?.pwriteAll(code, file_offset);2441 try self.base.file.?.pwriteAll(code, file_offset);
23992442
2400 return local_sym;2443 return local_sym;
...@@ -2413,15 +2456,10 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2413,15 +2456,10 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24132456
2414 const decl_index = func.owner_decl;2457 const decl_index = func.owner_decl;
2415 const decl = module.declPtr(decl_index);2458 const decl = module.declPtr(decl_index);
2416 const atom = &decl.link.elf;2459
2417 try atom.ensureInitialized(self);2460 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2418 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);2461 self.freeUnnamedConsts(decl_index);
2419 if (gop.found_existing) {2462 Atom.freeRelocations(self, atom_index);
2420 self.freeUnnamedConsts(decl_index);
2421 self.freeRelocationsForTextBlock(atom);
2422 } else {
2423 gop.value_ptr.* = null;
2424 }
24252463
2426 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2464 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2427 defer code_buffer.deinit();2465 defer code_buffer.deinit();
...@@ -2483,16 +2521,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2483,16 +2521,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2483 }2521 }
2484 }2522 }
24852523
2486 assert(!self.unnamed_const_atoms.contains(decl_index));2524 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
24872525 Atom.freeRelocations(self, atom_index);
2488 const atom = &decl.link.elf;2526 const atom = self.getAtom(atom_index);
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 }
24962527
2497 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2528 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2498 defer code_buffer.deinit();2529 defer code_buffer.deinit();
...@@ -2509,14 +2540,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2509,14 +2540,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2509 }, &code_buffer, .{2540 }, &code_buffer, .{
2510 .dwarf = ds,2541 .dwarf = ds,
2511 }, .{2542 }, .{
2512 .parent_atom_index = decl.link.elf.getSymbolIndex().?,2543 .parent_atom_index = atom.getSymbolIndex().?,
2513 })2544 })
2514 else2545 else
2515 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{2546 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2516 .ty = decl.ty,2547 .ty = decl.ty,
2517 .val = decl_val,2548 .val = decl_val,
2518 }, &code_buffer, .none, .{2549 }, &code_buffer, .none, .{
2519 .parent_atom_index = decl.link.elf.getSymbolIndex().?,2550 .parent_atom_index = atom.getSymbolIndex().?,
2520 });2551 });
25212552
2522 const code = switch (res) {2553 const code = switch (res) {
...@@ -2545,41 +2576,35 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2545,41 +2576,35 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2545}2576}
25462577
2547pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {2578pub 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);
2549 defer code_buffer.deinit();2582 defer code_buffer.deinit();
25502583
2551 const mod = self.base.options.module.?;2584 const mod = self.base.options.module.?;
2552 const decl = mod.declPtr(decl_index);2585 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
2553
2554 const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index);
2555 if (!gop.found_existing) {2586 if (!gop.found_existing) {
2556 gop.value_ptr.* = .{};2587 gop.value_ptr.* = .{};
2557 }2588 }
2558 const unnamed_consts = gop.value_ptr;2589 const unnamed_consts = gop.value_ptr;
25592590
2560 const atom = try self.base.allocator.create(TextBlock);2591 const decl = mod.declPtr(decl_index);
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
2567 const name_str_index = blk: {2592 const name_str_index = blk: {
2568 const decl_name = try decl.getFullyQualifiedName(mod);2593 const decl_name = try decl.getFullyQualifiedName(mod);
2569 defer self.base.allocator.free(decl_name);2594 defer gpa.free(decl_name);
2570
2571 const index = unnamed_consts.items.len;2595 const index = unnamed_consts.items.len;
2572 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index });2596 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
2573 defer self.base.allocator.free(name);2597 defer gpa.free(name);
25742598 break :blk try self.shstrtab.insert(gpa, name);
2575 break :blk try self.makeString(name);
2576 };2599 };
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
2579 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{2604 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
2580 .none = {},2605 .none = {},
2581 }, .{2606 }, .{
2582 .parent_atom_index = atom.getSymbolIndex().?,2607 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
2583 });2608 });
2584 const code = switch (res) {2609 const code = switch (res) {
2585 .ok => code_buffer.items,2610 .ok => code_buffer.items,
...@@ -2592,31 +2617,27 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2592,31 +2617,27 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2592 };2617 };
25932618
2594 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);2619 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
2595 const phdr_index = self.phdr_load_ro_index.?;2620 const shdr_index = self.rodata_section_index.?;
2596 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;2621 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
2597 const vaddr = try self.allocateTextBlock(atom, code.len, required_alignment, phdr_index);2622 const local_sym = self.getAtom(atom_index).getSymbolPtr(self);
2598 errdefer self.freeTextBlock(atom, phdr_index);2623 local_sym.st_name = name_str_index;
25992624 local_sym.st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT;
2600 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });2625 local_sym.st_other = 0;
26012626 local_sym.st_shndx = shdr_index;
2602 const local_sym = atom.getSymbolPtr(self);2627 local_sym.st_size = code.len;
2603 local_sym.* = .{2628 local_sym.st_value = try self.allocateAtom(atom_index, code.len, required_alignment);
2604 .st_name = name_str_index,2629 errdefer self.freeAtom(atom_index);
2605 .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT,2630
2606 .st_other = 0,2631 log.debug("allocated text block for {s} at 0x{x}", .{ name, local_sym.st_value });
2607 .st_shndx = shdr_index,2632
2608 .st_value = vaddr,2633 try self.writeSymbol(self.getAtom(atom_index).getSymbolIndex().?);
2609 .st_size = code.len,2634 try unnamed_consts.append(gpa, atom_index);
2610 };
2611
2612 try self.writeSymbol(atom.getSymbolIndex().?);
2613 try unnamed_consts.append(self.base.allocator, atom);
26142635
2615 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;2636 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;
2617 try self.base.file.?.pwriteAll(code, file_offset);2638 try self.base.file.?.pwriteAll(code, file_offset);
26182639
2619 return atom.getSymbolIndex().?;2640 return self.getAtom(atom_index).getSymbolIndex().?;
2620}2641}
26212642
2622pub fn updateDeclExports(2643pub fn updateDeclExports(
...@@ -2635,20 +2656,16 @@ pub fn updateDeclExports(...@@ -2635,20 +2656,16 @@ pub fn updateDeclExports(
2635 const tracy = trace(@src());2656 const tracy = trace(@src());
2636 defer tracy.end();2657 defer tracy.end();
26372658
2638 const decl = module.declPtr(decl_index);2659 const gpa = self.base.allocator;
2639 const atom = &decl.link.elf;
2640
2641 if (atom.getSymbolIndex() == null) return;
26422660
2661 const decl = module.declPtr(decl_index);
2662 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2663 const atom = self.getAtom(atom_index);
2643 const decl_sym = atom.getSymbol(self);2664 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);2668 try self.global_symbols.ensureUnusedCapacity(gpa, exports.len);
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).?;
26522669
2653 for (exports) |exp| {2670 for (exports) |exp| {
2654 if (exp.options.section) |section_name| {2671 if (exp.options.section) |section_name| {
...@@ -2681,10 +2698,10 @@ pub fn updateDeclExports(...@@ -2681,10 +2698,10 @@ pub fn updateDeclExports(
2681 },2698 },
2682 };2699 };
2683 const stt_bits: u8 = @truncate(u4, decl_sym.st_info);2700 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| {
2685 const sym = &self.global_symbols.items[i];2702 const sym = &self.global_symbols.items[i];
2686 sym.* = .{2703 sym.* = .{
2687 .st_name = try self.updateString(sym.st_name, exp.options.name),2704 .st_name = try self.shstrtab.insert(gpa, exp.options.name),
2688 .st_info = (stb_bits << 4) | stt_bits,2705 .st_info = (stb_bits << 4) | stt_bits,
2689 .st_other = 0,2706 .st_other = 0,
2690 .st_shndx = shdr_index,2707 .st_shndx = shdr_index,
...@@ -2692,30 +2709,29 @@ pub fn updateDeclExports(...@@ -2692,30 +2709,29 @@ pub fn updateDeclExports(
2692 .st_size = decl_sym.st_size,2709 .st_size = decl_sym.st_size,
2693 };2710 };
2694 } else {2711 } else {
2695 const name = try self.makeString(exp.options.name);
2696 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {2712 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
2697 _ = self.global_symbols.addOneAssumeCapacity();2713 _ = self.global_symbols.addOneAssumeCapacity();
2698 break :blk self.global_symbols.items.len - 1;2714 break :blk self.global_symbols.items.len - 1;
2699 };2715 };
2716 try decl_metadata.exports.append(gpa, @intCast(u32, i));
2700 self.global_symbols.items[i] = .{2717 self.global_symbols.items[i] = .{
2701 .st_name = name,2718 .st_name = try self.shstrtab.insert(gpa, exp.options.name),
2702 .st_info = (stb_bits << 4) | stt_bits,2719 .st_info = (stb_bits << 4) | stt_bits,
2703 .st_other = 0,2720 .st_other = 0,
2704 .st_shndx = shdr_index,2721 .st_shndx = shdr_index,
2705 .st_value = decl_sym.st_value,2722 .st_value = decl_sym.st_value,
2706 .st_size = decl_sym.st_size,2723 .st_size = decl_sym.st_size,
2707 };2724 };
2708
2709 exp.link.elf.sym_index = @intCast(u32, i);
2710 }2725 }
2711 }2726 }
2712}2727}
27132728
2714/// Must be called only after a successful call to `updateDecl`.2729/// 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 {
2716 const tracy = trace(@src());2731 const tracy = trace(@src());
2717 defer tracy.end();2732 defer tracy.end();
27182733
2734 const decl = mod.declPtr(decl_index);
2719 const decl_name = try decl.getFullyQualifiedName(mod);2735 const decl_name = try decl.getFullyQualifiedName(mod);
2720 defer self.base.allocator.free(decl_name);2736 defer self.base.allocator.free(decl_name);
27212737
...@@ -2723,16 +2739,18 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)...@@ -2723,16 +2739,18 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)
27232739
2724 if (self.llvm_object) |_| return;2740 if (self.llvm_object) |_| return;
2725 if (self.dwarf) |*dw| {2741 if (self.dwarf) |*dw| {
2726 try dw.updateDeclLineNumber(decl);2742 try dw.updateDeclLineNumber(mod, decl_index);
2727 }2743 }
2728}2744}
27292745
2730pub fn deleteExport(self: *Elf, exp: Export) void {2746pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void {
2731 if (self.llvm_object) |_| return;2747 if (self.llvm_object) |_| return;
27322748 const metadata = self.decls.getPtr(decl_index) orelse return;
2733 const sym_index = exp.sym_index orelse return;2749 const sym_index = metadata.getExportPtr(self, name) orelse return;
2734 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};2750 log.debug("deleting export '{s}'", .{name});
2735 self.global_symbols.items[sym_index].st_info = 0;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;
2736}2754}
27372755
2738fn writeProgHeader(self: *Elf, index: usize) !void {2756fn writeProgHeader(self: *Elf, index: usize) !void {
...@@ -2761,7 +2779,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {...@@ -2761,7 +2779,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
2761 switch (self.ptr_width) {2779 switch (self.ptr_width) {
2762 .p32 => {2780 .p32 => {
2763 var shdr: [1]elf.Elf32_Shdr = undefined;2781 var shdr: [1]elf.Elf32_Shdr = undefined;
2764 shdr[0] = sectHeaderTo32(self.sections.items[index]);2782 shdr[0] = sectHeaderTo32(self.sections.items(.shdr)[index]);
2765 if (foreign_endian) {2783 if (foreign_endian) {
2766 mem.byteSwapAllFields(elf.Elf32_Shdr, &shdr[0]);2784 mem.byteSwapAllFields(elf.Elf32_Shdr, &shdr[0]);
2767 }2785 }
...@@ -2769,7 +2787,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {...@@ -2769,7 +2787,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
2769 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);2787 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
2770 },2788 },
2771 .p64 => {2789 .p64 => {
2772 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};2790 var shdr = [1]elf.Elf64_Shdr{self.sections.items(.shdr)[index]};
2773 if (foreign_endian) {2791 if (foreign_endian) {
2774 mem.byteSwapAllFields(elf.Elf64_Shdr, &shdr[0]);2792 mem.byteSwapAllFields(elf.Elf64_Shdr, &shdr[0]);
2775 }2793 }
...@@ -2783,11 +2801,11 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {...@@ -2783,11 +2801,11 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
2783 const entry_size: u16 = self.archPtrWidthBytes();2801 const entry_size: u16 = self.archPtrWidthBytes();
2784 if (self.offset_table_count_dirty) {2802 if (self.offset_table_count_dirty) {
2785 const needed_size = self.offset_table.items.len * entry_size;2803 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);
2787 self.offset_table_count_dirty = false;2805 self.offset_table_count_dirty = false;
2788 }2806 }
2789 const endian = self.base.options.target.cpu.arch.endian();2807 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.?];
2791 const off = shdr.sh_offset + @as(u64, entry_size) * index;2809 const off = shdr.sh_offset + @as(u64, entry_size) * index;
2792 switch (entry_size) {2810 switch (entry_size) {
2793 2 => {2811 2 => {
...@@ -2813,7 +2831,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2813,7 +2831,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2813 const tracy = trace(@src());2831 const tracy = trace(@src());
2814 defer tracy.end();2832 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.?];
2817 // Make sure we are not pointlessly writing symbol data that will have to get relocated2835 // Make sure we are not pointlessly writing symbol data that will have to get relocated
2818 // due to running out of space.2836 // due to running out of space.
2819 if (self.local_symbols.items.len != syms_sect.sh_info) {2837 if (self.local_symbols.items.len != syms_sect.sh_info) {
...@@ -2835,7 +2853,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2835,7 +2853,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2835 .p64 => syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index,2853 .p64 => syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index,
2836 };2854 };
2837 const local = self.local_symbols.items[index];2855 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 });
2839 log.debug(" ({})", .{local});2857 log.debug(" ({})", .{local});
2840 switch (self.ptr_width) {2858 switch (self.ptr_width) {
2841 .p32 => {2859 .p32 => {
...@@ -2865,7 +2883,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2865,7 +2883,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2865}2883}
28662884
2867fn writeAllGlobalSymbols(self: *Elf) !void {2885fn 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.?];
2869 const sym_size: u64 = switch (self.ptr_width) {2887 const sym_size: u64 = switch (self.ptr_width) {
2870 .p32 => @sizeOf(elf.Elf32_Sym),2888 .p32 => @sizeOf(elf.Elf32_Sym),
2871 .p64 => @sizeOf(elf.Elf64_Sym),2889 .p64 => @sizeOf(elf.Elf64_Sym),
...@@ -3215,10 +3233,58 @@ const CsuObjects = struct {...@@ -3215,10 +3233,58 @@ const CsuObjects = struct {
3215fn logSymtab(self: Elf) void {3233fn logSymtab(self: Elf) void {
3216 log.debug("locals:", .{});3234 log.debug("locals:", .{});
3217 for (self.local_symbols.items) |sym, id| {3235 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 });
3219 }3237 }
3220 log.debug("globals:", .{});3238 log.debug("globals:", .{});
3221 for (self.global_symbols.items) |sym, id| {3239 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 });
3223 }3241 }
3224}3242}
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");...@@ -4,7 +4,6 @@ const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const elf = std.elf;5const elf = std.elf;
66
7const Dwarf = @import("../Dwarf.zig");
8const Elf = @import("../Elf.zig");7const Elf = @import("../Elf.zig");
98
10/// Each decl always gets a local symbol with the fully qualified name.9/// Each decl always gets a local symbol with the fully qualified name.
...@@ -20,44 +19,33 @@ offset_table_index: u32,...@@ -20,44 +19,33 @@ offset_table_index: u32,
2019
21/// Points to the previous and next neighbors, based on the `text_offset`.20/// Points to the previous and next neighbors, based on the `text_offset`.
22/// This can be used to find, for example, the capacity of this `TextBlock`.21/// This can be used to find, for example, the capacity of this `TextBlock`.
23prev: ?*Atom,22prev_index: ?Index,
24next: ?*Atom,23next_index: ?Index,
2524
26dbg_info_atom: Dwarf.Atom,25pub const Index = u32;
2726
28pub const empty = Atom{27pub const Reloc = struct {
29 .local_sym_index = 0,28 target: u32,
30 .offset_table_index = undefined,29 offset: u64,
31 .prev = null,30 addend: u32,
32 .next = null,31 prev_vaddr: u64,
33 .dbg_info_atom = undefined,
34};32};
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
43pub fn getSymbolIndex(self: Atom) ?u32 {34pub fn getSymbolIndex(self: Atom) ?u32 {
44 if (self.local_sym_index == 0) return null;35 if (self.local_sym_index == 0) return null;
45 return self.local_sym_index;36 return self.local_sym_index;
46}37}
4738
48pub fn getSymbol(self: Atom, elf_file: *Elf) elf.Elf64_Sym {39pub fn getSymbol(self: Atom, elf_file: *const Elf) elf.Elf64_Sym {
49 const sym_index = self.getSymbolIndex().?;40 return elf_file.getSymbol(self.getSymbolIndex().?);
50 return elf_file.local_symbols.items[sym_index];
51}41}
5242
53pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym {43pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym {
54 const sym_index = self.getSymbolIndex().?;44 return elf_file.getSymbolPtr(self.getSymbolIndex().?);
55 return &elf_file.local_symbols.items[sym_index];
56}45}
5746
58pub fn getName(self: Atom, elf_file: *Elf) []const u8 {47pub fn getName(self: Atom, elf_file: *const Elf) []const u8 {
59 const sym = self.getSymbol();48 return elf_file.getSymbolName(self.getSymbolIndex().?);
60 return elf_file.getString(sym.st_name);
61}49}
6250
63pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {51pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
...@@ -72,9 +60,10 @@ pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {...@@ -72,9 +60,10 @@ pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
72/// Returns how much room there is to grow in virtual address space.60/// Returns how much room there is to grow in virtual address space.
73/// File offset relocation happens transparently, so it is not included in61/// File offset relocation happens transparently, so it is not included in
74/// this calculation.62/// this calculation.
75pub fn capacity(self: Atom, elf_file: *Elf) u64 {63pub fn capacity(self: Atom, elf_file: *const Elf) u64 {
76 const self_sym = self.getSymbol(elf_file);64 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);
78 const next_sym = next.getSymbol(elf_file);67 const next_sym = next.getSymbol(elf_file);
79 return next_sym.st_value - self_sym.st_value;68 return next_sym.st_value - self_sym.st_value;
80 } else {69 } else {
...@@ -83,9 +72,10 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {...@@ -83,9 +72,10 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
83 }72 }
84}73}
8574
86pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {75pub fn freeListEligible(self: Atom, elf_file: *const Elf) bool {
87 // No need to keep a free list node for the last block.76 // 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);
89 const self_sym = self.getSymbol(elf_file);79 const self_sym = self.getSymbol(elf_file);
90 const next_sym = next.getSymbol(elf_file);80 const next_sym = next.getSymbol(elf_file);
91 const cap = next_sym.st_value - self_sym.st_value;81 const cap = next_sym.st_value - self_sym.st_value;
...@@ -94,3 +84,17 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {...@@ -94,3 +84,17 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
94 const surplus = cap - ideal_cap;84 const surplus = cap - ideal_cap;
95 return surplus >= Elf.min_text_capacity;85 return surplus >= Elf.min_text_capacity;
96}86}
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 {...@@ -66,7 +66,7 @@ const Section = struct {
6666
67 // TODO is null here necessary, or can we do away with tracking via section67 // TODO is null here necessary, or can we do away with tracking via section
68 // size in incremental context?68 // size in incremental context?
69 last_atom: ?*Atom = null,69 last_atom_index: ?Atom.Index = null,
7070
71 /// A list of atoms that have surplus capacity. This list can have false71 /// A list of atoms that have surplus capacity. This list can have false
72 /// positives, as functions grow and shrink over time, only sometimes being added72 /// positives, as functions grow and shrink over time, only sometimes being added
...@@ -83,7 +83,7 @@ const Section = struct {...@@ -83,7 +83,7 @@ const Section = struct {
83 /// overcapacity can be negative. A simple way to have negative overcapacity is to83 /// overcapacity can be negative. A simple way to have negative overcapacity is to
84 /// allocate a fresh atom, which will have ideal capacity, and then grow it84 /// allocate a fresh atom, which will have ideal capacity, and then grow it
85 /// by 1 byte. It will then have -1 overcapacity.85 /// by 1 byte. It will then have -1 overcapacity.
86 free_list: std.ArrayListUnmanaged(*Atom) = .{},86 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
87};87};
8888
89base: File,89base: File,
...@@ -140,8 +140,8 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{},...@@ -140,8 +140,8 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{},
140globals_free_list: std.ArrayListUnmanaged(u32) = .{},140globals_free_list: std.ArrayListUnmanaged(u32) = .{},
141141
142dyld_stub_binder_index: ?u32 = null,142dyld_stub_binder_index: ?u32 = null,
143dyld_private_atom: ?*Atom = null,143dyld_private_atom_index: ?Atom.Index = null,
144stub_helper_preamble_atom: ?*Atom = null,144stub_helper_preamble_atom_index: ?Atom.Index = null,
145145
146strtab: StringTable(.strtab) = .{},146strtab: StringTable(.strtab) = .{},
147147
...@@ -164,10 +164,10 @@ segment_table_dirty: bool = false,...@@ -164,10 +164,10 @@ segment_table_dirty: bool = false,
164cold_start: bool = true,164cold_start: bool = true,
165165
166/// List of atoms that are either synthetic or map directly to the Zig source program.166/// 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
169/// Table of atoms indexed by the symbol index.169/// 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
172/// Table of unnamed constants associated with a parent `Decl`.172/// Table of unnamed constants associated with a parent `Decl`.
173/// We store them here so that we can free the constants whenever the `Decl`173/// We store them here so that we can free the constants whenever the `Decl`
...@@ -210,11 +210,36 @@ bindings: BindingTable = .{},...@@ -210,11 +210,36 @@ bindings: BindingTable = .{},
210/// this will be a table indexed by index into the list of Atoms.210/// this will be a table indexed by index into the list of Atoms.
211lazy_bindings: BindingTable = .{},211lazy_bindings: BindingTable = .{},
212212
213/// Table of Decls that are currently alive.213/// Table of tracked Decls.
214/// We store them here so that we can properly dispose of any allocated214decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
215/// memory within the atom in the incremental linker.215
216/// TODO consolidate this.216const DeclMetadata = struct {
217decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?u8) = .{},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
219const Entry = struct {244const Entry = struct {
220 target: SymbolWithLoc,245 target: SymbolWithLoc,
...@@ -229,8 +254,8 @@ const Entry = struct {...@@ -229,8 +254,8 @@ const Entry = struct {
229 return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null });254 return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null });
230 }255 }
231256
232 pub fn getAtom(entry: Entry, macho_file: *MachO) ?*Atom {257 pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index {
233 return macho_file.getAtomForSymbol(.{ .sym_index = entry.sym_index, .file = null });258 return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index, .file = null });
234 }259 }
235260
236 pub fn getName(entry: Entry, macho_file: *MachO) []const u8 {261 pub fn getName(entry: Entry, macho_file: *MachO) []const u8 {
...@@ -238,10 +263,10 @@ const Entry = struct {...@@ -238,10 +263,10 @@ const Entry = struct {
238 }263 }
239};264};
240265
241const BindingTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Atom.Binding));266const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
242const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));267const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
243const RebaseTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32));268const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
244const RelocationTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation));269const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
245270
246const PendingUpdate = union(enum) {271const PendingUpdate = union(enum) {
247 resolve_undef: u32,272 resolve_undef: u32,
...@@ -286,10 +311,6 @@ pub const default_pagezero_vmsize: u64 = 0x100000000;...@@ -286,10 +311,6 @@ pub const default_pagezero_vmsize: u64 = 0x100000000;
286/// potential future extensions.311/// potential future extensions.
287pub const default_headerpad_size: u32 = 0x1000;312pub const default_headerpad_size: u32 = 0x1000;
288313
289pub const Export = struct {
290 sym_index: ?u32 = null,
291};
292
293pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {314pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
294 assert(options.target.ofmt == .macho);315 assert(options.target.ofmt == .macho);
295316
...@@ -547,8 +568,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -547,8 +568,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
547568
548 try self.allocateSpecialSymbols();569 try self.allocateSpecialSymbols();
549570
550 for (self.relocs.keys()) |atom| {571 for (self.relocs.keys()) |atom_index| {
551 try atom.resolveRelocations(self);572 try Atom.resolveRelocations(self, atom_index);
552 }573 }
553574
554 if (build_options.enable_logging) {575 if (build_options.enable_logging) {
...@@ -999,18 +1020,19 @@ pub fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs:...@@ -999,18 +1020,19 @@ pub fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs:
999 }1020 }
1000}1021}
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);
1003 const sym = atom.getSymbol(self);1025 const sym = atom.getSymbol(self);
1004 const section = self.sections.get(sym.n_sect - 1);1026 const section = self.sections.get(sym.n_sect - 1);
1005 const file_offset = section.header.offset + sym.n_value - section.header.addr;1027 const file_offset = section.header.offset + sym.n_value - section.header.addr;
1006 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });1028 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
1007 try self.base.file.?.pwriteAll(code, file_offset);1029 try self.base.file.?.pwriteAll(code, file_offset);
1008 try atom.resolveRelocations(self);1030 try Atom.resolveRelocations(self, atom_index);
1009}1031}
10101032
1011fn writePtrWidthAtom(self: *MachO, atom: *Atom) !void {1033fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {
1012 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);1034 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
1013 try self.writeAtom(atom, &buffer);1035 try self.writeAtom(atom_index, &buffer);
1014}1036}
10151037
1016fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {1038fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
...@@ -1026,7 +1048,8 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {...@@ -1026,7 +1048,8 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void {
1026fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {1048fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
1027 for (self.relocs.values()) |*relocs| {1049 for (self.relocs.values()) |*relocs| {
1028 for (relocs.items) |*reloc| {1050 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);
1030 const target_sym = target_atom.getSymbol(self);1053 const target_sym = target_atom.getSymbol(self);
1031 if (target_sym.n_value < addr) continue;1054 if (target_sym.n_value < addr) continue;
1032 reloc.dirty = true;1055 reloc.dirty = true;
...@@ -1053,26 +1076,38 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {...@@ -1053,26 +1076,38 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {
1053 }1076 }
1054}1077}
10551078
1056pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {1079pub fn createAtom(self: *MachO) !Atom.Index {
1057 const gpa = self.base.allocator;1080 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);1097pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1060 atom.* = Atom.empty;1098 const atom_index = try self.createAtom();
1061 try atom.ensureInitialized(self);1099 const atom = self.getAtomPtr(atom_index);
1062 atom.size = @sizeOf(u64);1100 atom.size = @sizeOf(u64);
1063 atom.alignment = @alignOf(u64);1101 atom.alignment = @alignOf(u64);
1064 errdefer gpa.destroy(atom);
1065
1066 try self.managed_atoms.append(gpa, atom);
10671102
1068 const sym = atom.getSymbolPtr(self);1103 const sym = atom.getSymbolPtr(self);
1069 sym.n_type = macho.N_SECT;1104 sym.n_type = macho.N_SECT;
1070 sym.n_sect = self.got_section_index.? + 1;1105 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
1073 log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});1108 log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});
10741109
1075 try atom.addRelocation(self, .{1110 try Atom.addRelocation(self, atom_index, .{
1076 .type = switch (self.base.options.target.cpu.arch) {1111 .type = switch (self.base.options.target.cpu.arch) {
1077 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),1112 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
1078 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),1113 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
...@@ -1087,45 +1122,39 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {...@@ -1087,45 +1122,39 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
10871122
1088 const target_sym = self.getSymbol(target);1123 const target_sym = self.getSymbol(target);
1089 if (target_sym.undf()) {1124 if (target_sym.undf()) {
1090 try atom.addBinding(self, .{1125 try Atom.addBinding(self, atom_index, .{
1091 .target = self.getGlobal(self.getSymbolName(target)).?,1126 .target = self.getGlobal(self.getSymbolName(target)).?,
1092 .offset = 0,1127 .offset = 0,
1093 });1128 });
1094 } else {1129 } else {
1095 try atom.addRebase(self, 0);1130 try Atom.addRebase(self, atom_index, 0);
1096 }1131 }
10971132
1098 return atom;1133 return atom_index;
1099}1134}
11001135
1101pub fn createDyldPrivateAtom(self: *MachO) !void {1136pub fn createDyldPrivateAtom(self: *MachO) !void {
1102 if (self.dyld_stub_binder_index == null) return;1137 if (self.dyld_stub_binder_index == null) return;
1103 if (self.dyld_private_atom != null) return;1138 if (self.dyld_private_atom_index != null) return;
1104
1105 const gpa = self.base.allocator;
11061139
1107 const atom = try gpa.create(Atom);1140 const atom_index = try self.createAtom();
1108 atom.* = Atom.empty;1141 const atom = self.getAtomPtr(atom_index);
1109 try atom.ensureInitialized(self);
1110 atom.size = @sizeOf(u64);1142 atom.size = @sizeOf(u64);
1111 atom.alignment = @alignOf(u64);1143 atom.alignment = @alignOf(u64);
1112 errdefer gpa.destroy(atom);
11131144
1114 const sym = atom.getSymbolPtr(self);1145 const sym = atom.getSymbolPtr(self);
1115 sym.n_type = macho.N_SECT;1146 sym.n_type = macho.N_SECT;
1116 sym.n_sect = self.data_section_index.? + 1;1147 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);1150 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));
1120
1121 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));
1122 log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value});1151 log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value});
1123 try self.writePtrWidthAtom(atom);1152 try self.writePtrWidthAtom(atom_index);
1124}1153}
11251154
1126pub fn createStubHelperPreambleAtom(self: *MachO) !void {1155pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1127 if (self.dyld_stub_binder_index == null) return;1156 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
1130 const gpa = self.base.allocator;1159 const gpa = self.base.allocator;
1131 const arch = self.base.options.target.cpu.arch;1160 const arch = self.base.options.target.cpu.arch;
...@@ -1134,22 +1163,23 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1134,22 +1163,23 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1134 .aarch64 => 6 * @sizeOf(u32),1163 .aarch64 => 6 * @sizeOf(u32),
1135 else => unreachable,1164 else => unreachable,
1136 };1165 };
1137 const atom = try gpa.create(Atom);1166 const atom_index = try self.createAtom();
1138 atom.* = Atom.empty;1167 const atom = self.getAtomPtr(atom_index);
1139 try atom.ensureInitialized(self);
1140 atom.size = size;1168 atom.size = size;
1141 atom.alignment = switch (arch) {1169 atom.alignment = switch (arch) {
1142 .x86_64 => 1,1170 .x86_64 => 1,
1143 .aarch64 => @alignOf(u32),1171 .aarch64 => @alignOf(u32),
1144 else => unreachable,1172 else => unreachable,
1145 };1173 };
1146 errdefer gpa.destroy(atom);
11471174
1148 const sym = atom.getSymbolPtr(self);1175 const sym = atom.getSymbolPtr(self);
1149 sym.n_type = macho.N_SECT;1176 sym.n_type = macho.N_SECT;
1150 sym.n_sect = self.stub_helper_section_index.? + 1;1177 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
1154 const code = try gpa.alloc(u8, size);1184 const code = try gpa.alloc(u8, size);
1155 defer gpa.free(code);1185 defer gpa.free(code);
...@@ -1168,7 +1198,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1168,7 +1198,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1168 code[9] = 0xff;1198 code[9] = 0xff;
1169 code[10] = 0x25;1199 code[10] = 0x25;
11701200
1171 try atom.addRelocations(self, 2, .{ .{1201 try Atom.addRelocations(self, atom_index, 2, .{ .{
1172 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),1202 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
1173 .target = .{ .sym_index = dyld_private_sym_index, .file = null },1203 .target = .{ .sym_index = dyld_private_sym_index, .file = null },
1174 .offset = 3,1204 .offset = 3,
...@@ -1208,7 +1238,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1208,7 +1238,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1208 // br x161238 // br x16
1209 mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32());1239 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, .{ .{
1212 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),1242 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
1213 .target = .{ .sym_index = dyld_private_sym_index, .file = null },1243 .target = .{ .sym_index = dyld_private_sym_index, .file = null },
1214 .offset = 0,1244 .offset = 0,
...@@ -1241,16 +1271,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1241,16 +1271,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
12411271
1242 else => unreachable,1272 else => unreachable,
1243 }1273 }
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);1276 sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment);
1247
1248 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1249 log.debug("allocated stub preamble atom at 0x{x}", .{sym.n_value});1277 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);
1251}1279}
12521280
1253pub fn createStubHelperAtom(self: *MachO) !*Atom {1281pub fn createStubHelperAtom(self: *MachO) !Atom.Index {
1254 const gpa = self.base.allocator;1282 const gpa = self.base.allocator;
1255 const arch = self.base.options.target.cpu.arch;1283 const arch = self.base.options.target.cpu.arch;
1256 const size: u4 = switch (arch) {1284 const size: u4 = switch (arch) {
...@@ -1258,16 +1286,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1258,16 +1286,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
1258 .aarch64 => 3 * @sizeOf(u32),1286 .aarch64 => 3 * @sizeOf(u32),
1259 else => unreachable,1287 else => unreachable,
1260 };1288 };
1261 const atom = try gpa.create(Atom);1289 const atom_index = try self.createAtom();
1262 atom.* = Atom.empty;1290 const atom = self.getAtomPtr(atom_index);
1263 try atom.ensureInitialized(self);
1264 atom.size = size;1291 atom.size = size;
1265 atom.alignment = switch (arch) {1292 atom.alignment = switch (arch) {
1266 .x86_64 => 1,1293 .x86_64 => 1,
1267 .aarch64 => @alignOf(u32),1294 .aarch64 => @alignOf(u32),
1268 else => unreachable,1295 else => unreachable,
1269 };1296 };
1270 errdefer gpa.destroy(atom);
12711297
1272 const sym = atom.getSymbolPtr(self);1298 const sym = atom.getSymbolPtr(self);
1273 sym.n_type = macho.N_SECT;1299 sym.n_type = macho.N_SECT;
...@@ -1277,6 +1303,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1277,6 +1303,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
1277 defer gpa.free(code);1303 defer gpa.free(code);
1278 mem.set(u8, code, 0);1304 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
1280 switch (arch) {1311 switch (arch) {
1281 .x86_64 => {1312 .x86_64 => {
1282 // pushq1313 // pushq
...@@ -1285,9 +1316,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1285,9 +1316,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
1285 // jmpq1316 // jmpq
1286 code[5] = 0xe9;1317 code[5] = 0xe9;
12871318
1288 try atom.addRelocation(self, .{1319 try Atom.addRelocation(self, atom_index, .{
1289 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),1320 .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 },
1291 .offset = 6,1322 .offset = 6,
1292 .addend = 0,1323 .addend = 0,
1293 .pcrel = true,1324 .pcrel = true,
...@@ -1308,9 +1339,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1308,9 +1339,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
1308 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(0).toU32());1339 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(0).toU32());
1309 // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.1340 // 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, .{
1312 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),1343 .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 },
1314 .offset = 4,1345 .offset = 4,
1315 .addend = 0,1346 .addend = 0,
1316 .pcrel = true,1347 .pcrel = true,
...@@ -1320,29 +1351,24 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1320,29 +1351,24 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
1320 else => unreachable,1351 else => unreachable,
1321 }1352 }
13221353
1323 try self.managed_atoms.append(gpa, atom);1354 sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment);
1324
1325 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1326 log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value});1355 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;
1330}1359}
13311360
1332pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom {1361pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !Atom.Index {
1333 const gpa = self.base.allocator;1362 const atom_index = try self.createAtom();
1334 const atom = try gpa.create(Atom);1363 const atom = self.getAtomPtr(atom_index);
1335 atom.* = Atom.empty;
1336 try atom.ensureInitialized(self);
1337 atom.size = @sizeOf(u64);1364 atom.size = @sizeOf(u64);
1338 atom.alignment = @alignOf(u64);1365 atom.alignment = @alignOf(u64);
1339 errdefer gpa.destroy(atom);
13401366
1341 const sym = atom.getSymbolPtr(self);1367 const sym = atom.getSymbolPtr(self);
1342 sym.n_type = macho.N_SECT;1368 sym.n_type = macho.N_SECT;
1343 sym.n_sect = self.la_symbol_ptr_section_index.? + 1;1369 sym.n_sect = self.la_symbol_ptr_section_index.? + 1;
13441370
1345 try atom.addRelocation(self, .{1371 try Atom.addRelocation(self, atom_index, .{
1346 .type = switch (self.base.options.target.cpu.arch) {1372 .type = switch (self.base.options.target.cpu.arch) {
1347 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),1373 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
1348 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),1374 .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...@@ -1354,22 +1380,20 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi
1354 .pcrel = false,1380 .pcrel = false,
1355 .length = 3,1381 .length = 3,
1356 });1382 });
1357 try atom.addRebase(self, 0);1383 try Atom.addRebase(self, atom_index, 0);
1358 try atom.addLazyBinding(self, .{1384 try Atom.addLazyBinding(self, atom_index, .{
1359 .target = self.getGlobal(self.getSymbolName(target)).?,1385 .target = self.getGlobal(self.getSymbolName(target)).?,
1360 .offset = 0,1386 .offset = 0,
1361 });1387 });
13621388
1363 try self.managed_atoms.append(gpa, atom);1389 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));
1364
1365 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));
1366 log.debug("allocated lazy pointer atom at 0x{x} ({s})", .{ sym.n_value, self.getSymbolName(target) });1390 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;
1370}1394}
13711395
1372pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {1396pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1373 const gpa = self.base.allocator;1397 const gpa = self.base.allocator;
1374 const arch = self.base.options.target.cpu.arch;1398 const arch = self.base.options.target.cpu.arch;
1375 const size: u4 = switch (arch) {1399 const size: u4 = switch (arch) {
...@@ -1377,9 +1401,8 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -1377,9 +1401,8 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
1377 .aarch64 => 3 * @sizeOf(u32),1401 .aarch64 => 3 * @sizeOf(u32),
1378 else => unreachable, // unhandled architecture type1402 else => unreachable, // unhandled architecture type
1379 };1403 };
1380 const atom = try gpa.create(Atom);1404 const atom_index = try self.createAtom();
1381 atom.* = Atom.empty;1405 const atom = self.getAtomPtr(atom_index);
1382 try atom.ensureInitialized(self);
1383 atom.size = size;1406 atom.size = size;
1384 atom.alignment = switch (arch) {1407 atom.alignment = switch (arch) {
1385 .x86_64 => 1,1408 .x86_64 => 1,
...@@ -1387,7 +1410,6 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -1387,7 +1410,6 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
1387 else => unreachable, // unhandled architecture type1410 else => unreachable, // unhandled architecture type
13881411
1389 };1412 };
1390 errdefer gpa.destroy(atom);
13911413
1392 const sym = atom.getSymbolPtr(self);1414 const sym = atom.getSymbolPtr(self);
1393 sym.n_type = macho.N_SECT;1415 sym.n_type = macho.N_SECT;
...@@ -1403,7 +1425,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -1403,7 +1425,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
1403 code[0] = 0xff;1425 code[0] = 0xff;
1404 code[1] = 0x25;1426 code[1] = 0x25;
14051427
1406 try atom.addRelocation(self, .{1428 try Atom.addRelocation(self, atom_index, .{
1407 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),1429 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
1408 .target = .{ .sym_index = laptr_sym_index, .file = null },1430 .target = .{ .sym_index = laptr_sym_index, .file = null },
1409 .offset = 2,1431 .offset = 2,
...@@ -1424,7 +1446,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -1424,7 +1446,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
1424 // br x161446 // br x16
1425 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());1447 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, .{
1428 .{1450 .{
1429 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),1451 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
1430 .target = .{ .sym_index = laptr_sym_index, .file = null },1452 .target = .{ .sym_index = laptr_sym_index, .file = null },
...@@ -1446,13 +1468,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -1446,13 +1468,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
1446 else => unreachable,1468 else => unreachable,
1447 }1469 }
14481470
1449 try self.managed_atoms.append(gpa, atom);1471 sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment);
1450
1451 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1452 log.debug("allocated stub atom at 0x{x}", .{sym.n_value});1472 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;
1456}1476}
14571477
1458pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {1478pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {
...@@ -1586,9 +1606,12 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {...@@ -1586,9 +1606,12 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {
1586 if (self.stubs_table.contains(global)) break :blk;1606 if (self.stubs_table.contains(global)) break :blk;
15871607
1588 const stub_index = try self.allocateStubEntry(global);1608 const stub_index = try self.allocateStubEntry(global);
1589 const stub_helper_atom = try self.createStubHelperAtom();1609 const stub_helper_atom_index = try self.createStubHelperAtom();
1590 const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, global);1610 const stub_helper_atom = self.getAtom(stub_helper_atom_index);
1591 const stub_atom = try self.createStubAtom(laptr_atom.getSymbolIndex().?);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);
1592 self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;1615 self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
1593 self.markRelocsDirtyByTarget(global);1616 self.markRelocsDirtyByTarget(global);
1594 }1617 }
...@@ -1686,10 +1709,11 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {...@@ -1686,10 +1709,11 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {
16861709
1687 // Add dyld_stub_binder as the final GOT entry.1710 // Add dyld_stub_binder as the final GOT entry.
1688 const got_index = try self.allocateGotEntry(global);1711 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);
1690 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;1714 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);
1693}1717}
16941718
1695pub fn deinit(self: *MachO) void {1719pub fn deinit(self: *MachO) void {
...@@ -1739,12 +1763,12 @@ pub fn deinit(self: *MachO) void {...@@ -1739,12 +1763,12 @@ pub fn deinit(self: *MachO) void {
1739 }1763 }
1740 self.sections.deinit(gpa);1764 self.sections.deinit(gpa);
17411765
1742 for (self.managed_atoms.items) |atom| {1766 self.atoms.deinit(gpa);
1743 gpa.destroy(atom);
1744 }
1745 self.managed_atoms.deinit(gpa);
17461767
1747 if (self.base.options.module) |_| {1768 if (self.base.options.module) |_| {
1769 for (self.decls.values()) |*m| {
1770 m.exports.deinit(gpa);
1771 }
1748 self.decls.deinit(gpa);1772 self.decls.deinit(gpa);
1749 } else {1773 } else {
1750 assert(self.decls.count() == 0);1774 assert(self.decls.count() == 0);
...@@ -1778,14 +1802,14 @@ pub fn deinit(self: *MachO) void {...@@ -1778,14 +1802,14 @@ pub fn deinit(self: *MachO) void {
1778 self.lazy_bindings.deinit(gpa);1802 self.lazy_bindings.deinit(gpa);
1779}1803}
17801804
1781fn freeAtom(self: *MachO, atom: *Atom) void {1805fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
1782 log.debug("freeAtom {*}", .{atom});
1783
1784 const gpa = self.base.allocator;1806 const gpa = self.base.allocator;
1807 log.debug("freeAtom {d}", .{atom_index});
17851808
1786 // Remove any relocs and base relocs associated with this Atom1809 // 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);
1789 const sect_id = atom.getSymbol(self).n_sect - 1;1813 const sect_id = atom.getSymbol(self).n_sect - 1;
1790 const free_list = &self.sections.items(.free_list)[sect_id];1814 const free_list = &self.sections.items(.free_list)[sect_id];
1791 var already_have_free_list_node = false;1815 var already_have_free_list_node = false;
...@@ -1793,45 +1817,46 @@ fn freeAtom(self: *MachO, atom: *Atom) void {...@@ -1793,45 +1817,46 @@ fn freeAtom(self: *MachO, atom: *Atom) void {
1793 var i: usize = 0;1817 var i: usize = 0;
1794 // TODO turn free_list into a hash map1818 // TODO turn free_list into a hash map
1795 while (i < free_list.items.len) {1819 while (i < free_list.items.len) {
1796 if (free_list.items[i] == atom) {1820 if (free_list.items[i] == atom_index) {
1797 _ = free_list.swapRemove(i);1821 _ = free_list.swapRemove(i);
1798 continue;1822 continue;
1799 }1823 }
1800 if (free_list.items[i] == atom.prev) {1824 if (free_list.items[i] == atom.prev_index) {
1801 already_have_free_list_node = true;1825 already_have_free_list_node = true;
1802 }1826 }
1803 i += 1;1827 i += 1;
1804 }1828 }
1805 }1829 }
18061830
1807 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];1831 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id];
1808 if (maybe_last_atom.*) |last_atom| {1832 if (maybe_last_atom_index.*) |last_atom_index| {
1809 if (last_atom == atom) {1833 if (last_atom_index == atom_index) {
1810 if (atom.prev) |prev| {1834 if (atom.prev_index) |prev_index| {
1811 // TODO shrink the section size here1835 // TODO shrink the section size here
1812 maybe_last_atom.* = prev;1836 maybe_last_atom_index.* = prev_index;
1813 } else {1837 } else {
1814 maybe_last_atom.* = null;1838 maybe_last_atom_index.* = null;
1815 }1839 }
1816 }1840 }
1817 }1841 }
18181842
1819 if (atom.prev) |prev| {1843 if (atom.prev_index) |prev_index| {
1820 prev.next = atom.next;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)) {
1823 // The free list is heuristics, it doesn't have to be perfect, so we can ignore1848 // The free list is heuristics, it doesn't have to be perfect, so we can ignore
1824 // the OOM here.1849 // the OOM here.
1825 free_list.append(gpa, prev) catch {};1850 free_list.append(gpa, prev_index) catch {};
1826 }1851 }
1827 } else {1852 } else {
1828 atom.prev = null;1853 self.getAtomPtr(atom_index).prev_index = null;
1829 }1854 }
18301855
1831 if (atom.next) |next| {1856 if (atom.next_index) |next_index| {
1832 next.prev = atom.prev;1857 self.getAtomPtr(next_index).prev_index = atom.prev_index;
1833 } else {1858 } else {
1834 atom.next = null;1859 self.getAtomPtr(atom_index).next_index = null;
1835 }1860 }
18361861
1837 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.1862 // 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 {...@@ -1859,27 +1884,24 @@ fn freeAtom(self: *MachO, atom: *Atom) void {
1859 self.locals.items[sym_index].n_type = 0;1884 self.locals.items[sym_index].n_type = 0;
1860 _ = self.atom_by_index_table.remove(sym_index);1885 _ = self.atom_by_index_table.remove(sym_index);
1861 log.debug(" adding local symbol index {d} to free list", .{sym_index});1886 log.debug(" adding local symbol index {d} to free list", .{sym_index});
1862 atom.sym_index = 0;1887 self.getAtomPtr(atom_index).sym_index = 0;
1863
1864 if (self.d_sym) |*d_sym| {
1865 d_sym.dwarf.freeAtom(&atom.dbg_info_atom);
1866 }
1867}1888}
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 {
1870 _ = self;1891 _ = self;
1871 _ = atom;1892 _ = atom_index;
1872 _ = new_block_size;1893 _ = new_block_size;
1873 // TODO check the new capacity, and if it crosses the size threshold into a big enough1894 // TODO check the new capacity, and if it crosses the size threshold into a big enough
1874 // capacity, insert a free list node for it.1895 // capacity, insert a free list node for it.
1875}1896}
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);
1878 const sym = atom.getSymbol(self);1900 const sym = atom.getSymbol(self);
1879 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;1901 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;
1880 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);1902 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
1881 if (!need_realloc) return sym.n_value;1903 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);
1883}1905}
18841906
1885pub fn allocateSymbol(self: *MachO) !u32 {1907pub fn allocateSymbol(self: *MachO) !u32 {
...@@ -1986,15 +2008,12 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -1986,15 +2008,12 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
19862008
1987 const decl_index = func.owner_decl;2009 const decl_index = func.owner_decl;
1988 const decl = module.declPtr(decl_index);2010 const decl = module.declPtr(decl_index);
1989 const atom = &decl.link.macho;2011
1990 try atom.ensureInitialized(self);2012 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
1991 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);2013 self.freeUnnamedConsts(decl_index);
1992 if (gop.found_existing) {2014 Atom.freeRelocations(self, atom_index);
1993 self.freeUnnamedConsts(decl_index);2015
1994 self.freeRelocationsForAtom(atom);2016 const atom = self.getAtom(atom_index);
1995 } else {
1996 gop.value_ptr.* = null;
1997 }
19982017
1999 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2018 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2000 defer code_buffer.deinit();2019 defer code_buffer.deinit();
...@@ -2024,13 +2043,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -2024,13 +2043,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
2024 const addr = try self.updateDeclCode(decl_index, code);2043 const addr = try self.updateDeclCode(decl_index, code);
20252044
2026 if (decl_state) |*ds| {2045 if (decl_state) |*ds| {
2027 try self.d_sym.?.dwarf.commitDeclState(2046 try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds);
2028 module,
2029 decl_index,
2030 addr,
2031 decl.link.macho.size,
2032 ds,
2033 );
2034 }2047 }
20352048
2036 // Since we updated the vaddr and the size, each corresponding export symbol also2049 // 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...@@ -2065,14 +2078,10 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
20652078
2066 log.debug("allocating symbol indexes for {?s}", .{name});2079 log.debug("allocating symbol indexes for {?s}", .{name});
20672080
2068 const atom = try gpa.create(Atom);2081 const atom_index = try self.createAtom();
2069 errdefer gpa.destroy(atom);
2070 atom.* = Atom.empty;
2071 try atom.ensureInitialized(self);
2072 try self.managed_atoms.append(gpa, atom);
20732082
2074 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{2083 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().?,
2076 });2085 });
2077 const code = switch (res) {2086 const code = switch (res) {
2078 .ok => code_buffer.items,2087 .ok => code_buffer.items,
...@@ -2085,24 +2094,25 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -2085,24 +2094,25 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
2085 };2094 };
20862095
2087 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);2096 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
2097 const atom = self.getAtomPtr(atom_index);
2088 atom.size = code.len;2098 atom.size = code.len;
2089 atom.alignment = required_alignment;2099 atom.alignment = required_alignment;
2090 // TODO: work out logic for disambiguating functions from function pointers2100 // 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);
2092 const sect_id = self.data_const_section_index.?;2102 const sect_id = self.data_const_section_index.?;
2093 const symbol = atom.getSymbolPtr(self);2103 const symbol = atom.getSymbolPtr(self);
2094 symbol.n_strx = name_str_index;2104 symbol.n_strx = name_str_index;
2095 symbol.n_type = macho.N_SECT;2105 symbol.n_type = macho.N_SECT;
2096 symbol.n_sect = sect_id + 1;2106 symbol.n_sect = sect_id + 1;
2097 symbol.n_value = try self.allocateAtom(atom, code.len, required_alignment);2107 symbol.n_value = try self.allocateAtom(atom_index, code.len, required_alignment);
2098 errdefer self.freeAtom(atom);2108 errdefer self.freeAtom(atom_index);
20992109
2100 try unnamed_consts.append(gpa, atom);2110 try unnamed_consts.append(gpa, atom_index);
21012111
2102 log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value });2112 log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value });
2103 log.debug(" (required alignment 0x{x})", .{required_alignment});2113 log.debug(" (required alignment 0x{x})", .{required_alignment});
21042114
2105 try self.writeAtom(atom, code);2115 try self.writeAtom(atom_index, code);
21062116
2107 return atom.getSymbolIndex().?;2117 return atom.getSymbolIndex().?;
2108}2118}
...@@ -2129,14 +2139,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2129,14 +2139,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2129 }2139 }
2130 }2140 }
21312141
2132 const atom = &decl.link.macho;2142 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2133 try atom.ensureInitialized(self);2143 Atom.freeRelocations(self, atom_index);
2134 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);2144 const atom = self.getAtom(atom_index);
2135 if (gop.found_existing) {
2136 self.freeRelocationsForAtom(atom);
2137 } else {
2138 gop.value_ptr.* = null;
2139 }
21402145
2141 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2146 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2142 defer code_buffer.deinit();2147 defer code_buffer.deinit();
...@@ -2155,14 +2160,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2155,14 +2160,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2155 }, &code_buffer, .{2160 }, &code_buffer, .{
2156 .dwarf = ds,2161 .dwarf = ds,
2157 }, .{2162 }, .{
2158 .parent_atom_index = decl.link.macho.getSymbolIndex().?,2163 .parent_atom_index = atom.getSymbolIndex().?,
2159 })2164 })
2160 else2165 else
2161 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{2166 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2162 .ty = decl.ty,2167 .ty = decl.ty,
2163 .val = decl_val,2168 .val = decl_val,
2164 }, &code_buffer, .none, .{2169 }, &code_buffer, .none, .{
2165 .parent_atom_index = decl.link.macho.getSymbolIndex().?,2170 .parent_atom_index = atom.getSymbolIndex().?,
2166 });2171 });
21672172
2168 const code = switch (res) {2173 const code = switch (res) {
...@@ -2176,13 +2181,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2176,13 +2181,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2176 const addr = try self.updateDeclCode(decl_index, code);2181 const addr = try self.updateDeclCode(decl_index, code);
21772182
2178 if (decl_state) |*ds| {2183 if (decl_state) |*ds| {
2179 try self.d_sym.?.dwarf.commitDeclState(2184 try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds);
2180 module,
2181 decl_index,
2182 addr,
2183 decl.link.macho.size,
2184 ds,
2185 );
2186 }2185 }
21872186
2188 // Since we updated the vaddr and the size, each corresponding export symbol also2187 // 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)...@@ -2190,7 +2189,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2190 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2189 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2191}2190}
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);
2194 const ty = decl.ty;2206 const ty = decl.ty;
2195 const val = decl.val;2207 const val = decl.val;
2196 const zig_ty = ty.zigTypeTag();2208 const zig_ty = ty.zigTypeTag();
...@@ -2341,13 +2353,11 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)...@@ -2341,13 +2353,11 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
2341 const sym_name = try decl.getFullyQualifiedName(mod);2353 const sym_name = try decl.getFullyQualifiedName(mod);
2342 defer self.base.allocator.free(sym_name);2354 defer self.base.allocator.free(sym_name);
23432355
2344 const atom = &decl.link.macho;2356 const decl_metadata = self.decls.get(decl_index).?;
2345 const sym_index = atom.getSymbolIndex().?; // Atom was not initialized2357 const atom_index = decl_metadata.atom;
2346 const decl_ptr = self.decls.getPtr(decl_index).?;2358 const atom = self.getAtom(atom_index);
2347 if (decl_ptr.* == null) {2359 const sym_index = atom.getSymbolIndex().?;
2348 decl_ptr.* = self.getDeclOutputSection(decl);2360 const sect_id = decl_metadata.section;
2349 }
2350 const sect_id = decl_ptr.*.?;
2351 const code_len = code.len;2361 const code_len = code.len;
23522362
2353 if (atom.size != 0) {2363 if (atom.size != 0) {
...@@ -2357,11 +2367,11 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)...@@ -2357,11 +2367,11 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
2357 sym.n_sect = sect_id + 1;2367 sym.n_sect = sect_id + 1;
2358 sym.n_desc = 0;2368 sym.n_desc = 0;
23592369
2360 const capacity = decl.link.macho.capacity(self);2370 const capacity = atom.capacity(self);
2361 const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment);2371 const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment);
23622372
2363 if (need_realloc) {2373 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);
2365 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, sym.n_value, vaddr });2375 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, sym.n_value, vaddr });
2366 log.debug(" (required alignment 0x{x})", .{required_alignment});2376 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)...@@ -2369,19 +2379,19 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
2369 sym.n_value = vaddr;2379 sym.n_value = vaddr;
2370 log.debug(" (updating GOT entry)", .{});2380 log.debug(" (updating GOT entry)", .{});
2371 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };2381 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).?;
2373 self.markRelocsDirtyByTarget(got_target);2383 self.markRelocsDirtyByTarget(got_target);
2374 try self.writePtrWidthAtom(got_atom);2384 try self.writePtrWidthAtom(got_atom_index);
2375 }2385 }
2376 } else if (code_len < atom.size) {2386 } else if (code_len < atom.size) {
2377 self.shrinkAtom(atom, code_len);2387 self.shrinkAtom(atom_index, code_len);
2378 } else if (atom.next == null) {2388 } else if (atom.next_index == null) {
2379 const header = &self.sections.items(.header)[sect_id];2389 const header = &self.sections.items(.header)[sect_id];
2380 const segment = self.getSegment(sect_id);2390 const segment = self.getSegment(sect_id);
2381 const needed_size = (sym.n_value + code_len) - segment.vmaddr;2391 const needed_size = (sym.n_value + code_len) - segment.vmaddr;
2382 header.size = needed_size;2392 header.size = needed_size;
2383 }2393 }
2384 atom.size = code_len;2394 self.getAtomPtr(atom_index).size = code_len;
2385 } else {2395 } else {
2386 const name_str_index = try self.strtab.insert(gpa, sym_name);2396 const name_str_index = try self.strtab.insert(gpa, sym_name);
2387 const sym = atom.getSymbolPtr(self);2397 const sym = atom.getSymbolPtr(self);
...@@ -2390,32 +2400,32 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)...@@ -2390,32 +2400,32 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
2390 sym.n_sect = sect_id + 1;2400 sym.n_sect = sect_id + 1;
2391 sym.n_desc = 0;2401 sym.n_desc = 0;
23922402
2393 const vaddr = try self.allocateAtom(atom, code_len, required_alignment);2403 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
2394 errdefer self.freeAtom(atom);2404 errdefer self.freeAtom(atom_index);
23952405
2396 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, vaddr });2406 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, vaddr });
2397 log.debug(" (required alignment 0x{x})", .{required_alignment});2407 log.debug(" (required alignment 0x{x})", .{required_alignment});
23982408
2399 atom.size = code_len;2409 self.getAtomPtr(atom_index).size = code_len;
2400 sym.n_value = vaddr;2410 sym.n_value = vaddr;
24012411
2402 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };2412 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2403 const got_index = try self.allocateGotEntry(got_target);2413 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);
2405 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;2416 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
2406 try self.writePtrWidthAtom(got_atom);2417 try self.writePtrWidthAtom(got_atom_index);
2407 }2418 }
24082419
2409 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());2420 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
2410 try self.writeAtom(atom, code);2421 try self.writeAtom(atom_index, code);
24112422
2412 return atom.getSymbol(self).n_value;2423 return atom.getSymbol(self).n_value;
2413}2424}
24142425
2415pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {2426pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void {
2416 _ = module;
2417 if (self.d_sym) |*d_sym| {2427 if (self.d_sym) |*d_sym| {
2418 try d_sym.dwarf.updateDeclLineNumber(decl);2428 try d_sym.dwarf.updateDeclLineNumber(module, decl_index);
2419 }2429 }
2420}2430}
24212431
...@@ -2432,22 +2442,17 @@ pub fn updateDeclExports(...@@ -2432,22 +2442,17 @@ pub fn updateDeclExports(
2432 if (self.llvm_object) |llvm_object|2442 if (self.llvm_object) |llvm_object|
2433 return llvm_object.updateDeclExports(module, decl_index, exports);2443 return llvm_object.updateDeclExports(module, decl_index, exports);
2434 }2444 }
2445
2435 const tracy = trace(@src());2446 const tracy = trace(@src());
2436 defer tracy.end();2447 defer tracy.end();
24372448
2438 const gpa = self.base.allocator;2449 const gpa = self.base.allocator;
24392450
2440 const decl = module.declPtr(decl_index);2451 const decl = module.declPtr(decl_index);
2441 const atom = &decl.link.macho;2452 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
24422453 const atom = self.getAtom(atom_index);
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
2450 const decl_sym = atom.getSymbol(self);2454 const decl_sym = atom.getSymbol(self);
2455 const decl_metadata = self.decls.getPtr(decl_index).?;
24512456
2452 for (exports) |exp| {2457 for (exports) |exp| {
2453 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name});2458 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name});
...@@ -2485,9 +2490,9 @@ pub fn updateDeclExports(...@@ -2485,9 +2490,9 @@ pub fn updateDeclExports(
2485 continue;2490 continue;
2486 }2491 }
24872492
2488 const sym_index = exp.link.macho.sym_index orelse blk: {2493 const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: {
2489 const sym_index = try self.allocateSymbol();2494 const sym_index = try self.allocateSymbol();
2490 exp.link.macho.sym_index = sym_index;2495 try decl_metadata.exports.append(gpa, sym_index);
2491 break :blk sym_index;2496 break :blk sym_index;
2492 };2497 };
2493 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };2498 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
...@@ -2535,16 +2540,18 @@ pub fn updateDeclExports(...@@ -2535,16 +2540,18 @@ pub fn updateDeclExports(
2535 }2540 }
2536}2541}
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 {
2539 if (self.llvm_object) |_| return;2544 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
2542 const gpa = self.base.allocator;2547 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 };
2545 const sym = self.getSymbolPtr(sym_loc);2553 const sym = self.getSymbolPtr(sym_loc);
2546 const sym_name = self.getSymbolName(sym_loc);2554 log.debug("deleting export '{s}'", .{exp_name});
2547 log.debug("deleting export '{s}'", .{sym_name});
2548 assert(sym.sect() and sym.ext());2555 assert(sym.sect() and sym.ext());
2549 sym.* = .{2556 sym.* = .{
2550 .n_strx = 0,2557 .n_strx = 0,
...@@ -2553,9 +2560,9 @@ pub fn deleteExport(self: *MachO, exp: Export) void {...@@ -2553,9 +2560,9 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
2553 .n_desc = 0,2560 .n_desc = 0,
2554 .n_value = 0,2561 .n_value = 0,
2555 };2562 };
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| {
2559 defer gpa.free(entry.key);2566 defer gpa.free(entry.key);
2560 self.globals_free_list.append(gpa, entry.value) catch {};2567 self.globals_free_list.append(gpa, entry.value) catch {};
2561 self.globals.items[entry.value] = .{2568 self.globals.items[entry.value] = .{
...@@ -2563,17 +2570,8 @@ pub fn deleteExport(self: *MachO, exp: Export) void {...@@ -2563,17 +2570,8 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
2563 .file = null,2570 .file = null,
2564 };2571 };
2565 }2572 }
2566}
25672573
2568fn freeRelocationsForAtom(self: *MachO, atom: *Atom) void {2574 sym_index.* = 0;
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);
2577}2575}
25782576
2579fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {2577fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {
...@@ -2594,29 +2592,25 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {...@@ -2594,29 +2592,25 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {
25942592
2595 log.debug("freeDecl {*}", .{decl});2593 log.debug("freeDecl {*}", .{decl});
25962594
2597 if (self.decls.fetchSwapRemove(decl_index)) |kv| {2595 if (self.decls.fetchSwapRemove(decl_index)) |const_kv| {
2598 if (kv.value) |_| {2596 var kv = const_kv;
2599 self.freeAtom(&decl.link.macho);2597 self.freeAtom(kv.value.atom);
2600 self.freeUnnamedConsts(decl_index);2598 self.freeUnnamedConsts(decl_index);
2601 }2599 kv.value.exports.deinit(self.base.allocator);
2602 }2600 }
26032601
2604 if (self.d_sym) |*d_sym| {2602 if (self.d_sym) |*d_sym| {
2605 d_sym.dwarf.freeDecl(decl);2603 d_sym.dwarf.freeDecl(decl_index);
2606 }2604 }
2607}2605}
26082606
2609pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 {2607pub 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
2613 assert(self.llvm_object == null);2608 assert(self.llvm_object == null);
26142609
2615 try decl.link.macho.ensureInitialized(self);2610 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
2616 const sym_index = decl.link.macho.getSymbolIndex().?;2611 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
26172612 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
2618 const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;2613 try Atom.addRelocation(self, atom_index, .{
2619 try atom.addRelocation(self, .{
2620 .type = switch (self.base.options.target.cpu.arch) {2614 .type = switch (self.base.options.target.cpu.arch) {
2621 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),2615 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
2622 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),2616 .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...@@ -2628,7 +2622,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
2628 .pcrel = false,2622 .pcrel = false,
2629 .length = 3,2623 .length = 3,
2630 });2624 });
2631 try atom.addRebase(self, @intCast(u32, reloc_info.offset));2625 try Atom.addRebase(self, atom_index, @intCast(u32, reloc_info.offset));
26322626
2633 return 0;2627 return 0;
2634}2628}
...@@ -2860,34 +2854,36 @@ fn moveSectionInVirtualMemory(self: *MachO, sect_id: u8, needed_size: u64) !void...@@ -2860,34 +2854,36 @@ fn moveSectionInVirtualMemory(self: *MachO, sect_id: u8, needed_size: u64) !void
2860 // TODO: enforce order by increasing VM addresses in self.sections container.2854 // TODO: enforce order by increasing VM addresses in self.sections container.
2861 for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| {2855 for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| {
2862 const index = @intCast(u8, sect_id + 1 + next_sect_id);2856 const index = @intCast(u8, sect_id + 1 + next_sect_id);
2863 const maybe_last_atom = &self.sections.items(.last_atom)[index];
2864 const next_segment = self.getSegmentPtr(index);2857 const next_segment = self.getSegmentPtr(index);
2865 next_header.addr += diff;2858 next_header.addr += diff;
2866 next_segment.vmaddr += diff;2859 next_segment.vmaddr += diff;
28672860
2868 if (maybe_last_atom.*) |last_atom| {2861 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[index];
2869 var atom = last_atom;2862 if (maybe_last_atom_index.*) |last_atom_index| {
2863 var atom_index = last_atom_index;
2870 while (true) {2864 while (true) {
2865 const atom = self.getAtom(atom_index);
2871 const sym = atom.getSymbolPtr(self);2866 const sym = atom.getSymbolPtr(self);
2872 sym.n_value += diff;2867 sym.n_value += diff;
28732868
2874 if (atom.prev) |prev| {2869 if (atom.prev_index) |prev_index| {
2875 atom = prev;2870 atom_index = prev_index;
2876 } else break;2871 } else break;
2877 }2872 }
2878 }2873 }
2879 }2874 }
2880}2875}
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 {
2883 const tracy = trace(@src());2878 const tracy = trace(@src());
2884 defer tracy.end();2879 defer tracy.end();
28852880
2881 const atom = self.getAtom(atom_index);
2886 const sect_id = atom.getSymbol(self).n_sect - 1;2882 const sect_id = atom.getSymbol(self).n_sect - 1;
2887 const segment = self.getSegmentPtr(sect_id);2883 const segment = self.getSegmentPtr(sect_id);
2888 const header = &self.sections.items(.header)[sect_id];2884 const header = &self.sections.items(.header)[sect_id];
2889 const free_list = &self.sections.items(.free_list)[sect_id];2885 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];
2891 const requires_padding = blk: {2887 const requires_padding = blk: {
2892 if (!header.isCode()) break :blk false;2888 if (!header.isCode()) break :blk false;
2893 if (header.isSymbolStubs()) break :blk false;2889 if (header.isSymbolStubs()) break :blk false;
...@@ -2901,7 +2897,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !...@@ -2901,7 +2897,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
2901 // It would be simpler to do it inside the for loop below, but that would cause a2897 // It would be simpler to do it inside the for loop below, but that would cause a
2902 // problem if an error was returned later in the function. So this action2898 // problem if an error was returned later in the function. So this action
2903 // is actually carried out at the end of the function, when errors are no longer possible.2899 // 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;
2905 var free_list_removal: ?usize = null;2901 var free_list_removal: ?usize = null;
29062902
2907 // First we look for an appropriately sized free list node.2903 // 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) !...@@ -2909,7 +2905,8 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
2909 var vaddr = blk: {2905 var vaddr = blk: {
2910 var i: usize = 0;2906 var i: usize = 0;
2911 while (i < free_list.items.len) {2907 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);
2913 // We now have a pointer to a live atom that has too much capacity.2910 // We now have a pointer to a live atom that has too much capacity.
2914 // Is it enough that we could fit this new atom?2911 // Is it enough that we could fit this new atom?
2915 const sym = big_atom.getSymbol(self);2912 const sym = big_atom.getSymbol(self);
...@@ -2937,30 +2934,35 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !...@@ -2937,30 +2934,35 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
2937 const keep_free_list_node = remaining_capacity >= min_text_capacity;2934 const keep_free_list_node = remaining_capacity >= min_text_capacity;
29382935
2939 // Set up the metadata to be updated, after errors are no longer possible.2936 // Set up the metadata to be updated, after errors are no longer possible.
2940 atom_placement = big_atom;2937 atom_placement = big_atom_index;
2941 if (!keep_free_list_node) {2938 if (!keep_free_list_node) {
2942 free_list_removal = i;2939 free_list_removal = i;
2943 }2940 }
2944 break :blk new_start_vaddr;2941 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);
2946 const last_symbol = last.getSymbol(self);2944 const last_symbol = last.getSymbol(self);
2947 const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size;2945 const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size;
2948 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;2946 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
2949 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);2947 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
2950 atom_placement = last;2948 atom_placement = last_index;
2951 break :blk new_start_vaddr;2949 break :blk new_start_vaddr;
2952 } else {2950 } else {
2953 break :blk mem.alignForwardGeneric(u64, segment.vmaddr, alignment);2951 break :blk mem.alignForwardGeneric(u64, segment.vmaddr, alignment);
2954 }2952 }
2955 };2953 };
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;
2958 if (expand_section) {2959 if (expand_section) {
2959 const sect_capacity = self.allocatedSize(header.offset);2960 const sect_capacity = self.allocatedSize(header.offset);
2960 const needed_size = (vaddr + new_atom_size) - segment.vmaddr;2961 const needed_size = (vaddr + new_atom_size) - segment.vmaddr;
2961 if (needed_size > sect_capacity) {2962 if (needed_size > sect_capacity) {
2962 const new_offset = self.findFreeSpace(needed_size, self.page_size);2963 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);
2964 const sym = last_atom.getSymbol(self);2966 const sym = last_atom.getSymbol(self);
2965 break :blk (sym.n_value + last_atom.size) - segment.vmaddr;2967 break :blk (sym.n_value + last_atom.size) - segment.vmaddr;
2966 } else 0;2968 } else 0;
...@@ -2992,7 +2994,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !...@@ -2992,7 +2994,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
2992 header.size = needed_size;2994 header.size = needed_size;
2993 segment.filesize = mem.alignForwardGeneric(u64, needed_size, self.page_size);2995 segment.filesize = mem.alignForwardGeneric(u64, needed_size, self.page_size);
2994 segment.vmsize = mem.alignForwardGeneric(u64, needed_size, self.page_size);2996 segment.vmsize = mem.alignForwardGeneric(u64, needed_size, self.page_size);
2995 maybe_last_atom.* = atom;2997 maybe_last_atom_index.* = atom_index;
29962998
2997 self.segment_table_dirty = true;2999 self.segment_table_dirty = true;
2998 }3000 }
...@@ -3001,21 +3003,31 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !...@@ -3001,21 +3003,31 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
3001 if (header.@"align" < align_pow) {3003 if (header.@"align" < align_pow) {
3002 header.@"align" = align_pow;3004 header.@"align" = align_pow;
3003 }3005 }
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| {3012 if (atom.prev_index) |prev_index| {
3006 prev.next = atom.next;3013 const prev = self.getAtomPtr(prev_index);
3014 prev.next_index = atom.next_index;
3007 }3015 }
3008 if (atom.next) |next| {3016 if (atom.next_index) |next_index| {
3009 next.prev = atom.prev;3017 const next = self.getAtomPtr(next_index);
3018 next.prev_index = atom.prev_index;
3010 }3019 }
30113020
3012 if (atom_placement) |big_atom| {3021 if (atom_placement) |big_atom_index| {
3013 atom.prev = big_atom;3022 const big_atom = self.getAtomPtr(big_atom_index);
3014 atom.next = big_atom.next;3023 const atom_ptr = self.getAtomPtr(atom_index);
3015 big_atom.next = atom;3024 atom_ptr.prev_index = big_atom_index;
3025 atom_ptr.next_index = big_atom.next_index;
3026 big_atom.next_index = atom_index;
3016 } else {3027 } else {
3017 atom.prev = null;3028 const atom_ptr = self.getAtomPtr(atom_index);
3018 atom.next = null;3029 atom_ptr.prev_index = null;
3030 atom_ptr.next_index = null;
3019 }3031 }
3020 if (free_list_removal) |i| {3032 if (free_list_removal) |i| {
3021 _ = free_list.swapRemove(i);3033 _ = free_list.swapRemove(i);
...@@ -3155,7 +3167,8 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {...@@ -3155,7 +3167,8 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {
3155 const gpa = self.base.allocator;3167 const gpa = self.base.allocator;
3156 const slice = self.sections.slice();3168 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);
3159 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });3172 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });
31603173
3161 const sym = atom.getSymbol(self);3174 const sym = atom.getSymbol(self);
...@@ -3184,7 +3197,8 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {...@@ -3184,7 +3197,8 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {
3184 const gpa = self.base.allocator;3197 const gpa = self.base.allocator;
3185 const slice = self.sections.slice();3198 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);
3188 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });3202 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });
31893203
3190 const sym = atom.getSymbol(self);3204 const sym = atom.getSymbol(self);
...@@ -3359,7 +3373,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void...@@ -3359,7 +3373,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void
3359 if (lazy_bind.size() == 0) return;3373 if (lazy_bind.size() == 0) return;
33603374
3361 const stub_helper_section_index = self.stub_helper_section_index.?;3375 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
3364 const section = self.sections.get(stub_helper_section_index);3378 const section = self.sections.get(stub_helper_section_index);
33653379
...@@ -3369,10 +3383,11 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void...@@ -3369,10 +3383,11 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void
3369 else => unreachable,3383 else => unreachable,
3370 };3384 };
3371 const header = section.header;3385 const header = section.header;
3372 var atom = section.last_atom.?;3386 var atom_index = section.last_atom_index.?;
33733387
3374 var index: usize = lazy_bind.offsets.items.len;3388 var index: usize = lazy_bind.offsets.items.len;
3375 while (index > 0) : (index -= 1) {3389 while (index > 0) : (index -= 1) {
3390 const atom = self.getAtom(atom_index);
3376 const sym = atom.getSymbol(self);3391 const sym = atom.getSymbol(self);
3377 const file_offset = header.offset + sym.n_value - header.addr + stub_offset;3392 const file_offset = header.offset + sym.n_value - header.addr + stub_offset;
3378 const bind_offset = lazy_bind.offsets.items[index - 1];3393 const bind_offset = lazy_bind.offsets.items[index - 1];
...@@ -3385,7 +3400,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void...@@ -3385,7 +3400,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void
33853400
3386 try self.base.file.?.pwriteAll(mem.asBytes(&bind_offset), file_offset);3401 try self.base.file.?.pwriteAll(mem.asBytes(&bind_offset), file_offset);
33873402
3388 atom = atom.prev.?;3403 atom_index = atom.prev_index.?;
3389 }3404 }
3390}3405}
33913406
...@@ -3828,25 +3843,35 @@ pub fn getOrPutGlobalPtr(self: *MachO, name: []const u8) !GetOrPutGlobalPtrResul...@@ -3828,25 +3843,35 @@ pub fn getOrPutGlobalPtr(self: *MachO, name: []const u8) !GetOrPutGlobalPtrResul
3828 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };3843 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
3829}3844}
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
3831/// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor.3856/// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor.
3832/// Returns null on failure.3857/// 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 {
3834 assert(sym_with_loc.file == null);3859 assert(sym_with_loc.file == null);
3835 return self.atom_by_index_table.get(sym_with_loc.sym_index);3860 return self.atom_by_index_table.get(sym_with_loc.sym_index);
3836}3861}
38373862
3838/// Returns GOT atom that references `sym_with_loc` if one exists.3863/// Returns GOT atom that references `sym_with_loc` if one exists.
3839/// Returns null otherwise.3864/// Returns null otherwise.
3840pub fn getGotAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {3865pub fn getGotAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
3841 const got_index = self.got_entries_table.get(sym_with_loc) orelse return null;3866 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);
3843}3868}
38443869
3845/// Returns stubs atom that references `sym_with_loc` if one exists.3870/// Returns stubs atom that references `sym_with_loc` if one exists.
3846/// Returns null otherwise.3871/// Returns null otherwise.
3847pub fn getStubsAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {3872pub fn getStubsAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
3848 const stubs_index = self.stubs_table.get(sym_with_loc) orelse return null;3873 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);
3850}3875}
38513876
3852/// Returns symbol location corresponding to the set entrypoint.3877/// Returns symbol location corresponding to the set entrypoint.
...@@ -4232,26 +4257,31 @@ pub fn logAtoms(self: *MachO) void {...@@ -4232,26 +4257,31 @@ pub fn logAtoms(self: *MachO) void {
4232 log.debug("atoms:", .{});4257 log.debug("atoms:", .{});
42334258
4234 const slice = self.sections.slice();4259 const slice = self.sections.slice();
4235 for (slice.items(.last_atom)) |last, i| {4260 for (slice.items(.last_atom_index)) |last_atom_index, i| {
4236 var atom = last orelse continue;4261 var atom_index = last_atom_index orelse continue;
4237 const header = slice.items(.header)[i];4262 const header = slice.items(.header)[i];
42384263
4239 while (atom.prev) |prev| {4264 while (true) {
4240 atom = prev;4265 const atom = self.getAtom(atom_index);
4266 if (atom.prev_index) |prev_index| {
4267 atom_index = prev_index;
4268 } else break;
4241 }4269 }
42424270
4243 log.debug("{s},{s}", .{ header.segName(), header.sectName() });4271 log.debug("{s},{s}", .{ header.segName(), header.sectName() });
42444272
4245 while (true) {4273 while (true) {
4246 self.logAtom(atom);4274 self.logAtom(atom_index);
4247 if (atom.next) |next| {4275 const atom = self.getAtom(atom_index);
4248 atom = next;4276 if (atom.next_index) |next_index| {
4277 atom_index = next_index;
4249 } else break;4278 } else break;
4250 }4279 }
4251 }4280 }
4252}4281}
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);
4255 const sym = atom.getSymbol(self);4285 const sym = atom.getSymbol(self);
4256 const sym_name = atom.getName(self);4286 const sym_name = atom.getName(self);
4257 log.debug(" ATOM(%{?d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{4287 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;...@@ -13,7 +13,6 @@ const trace = @import("../../tracy.zig").trace;
1313
14const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
15const Arch = std.Target.Cpu.Arch;15const Arch = std.Target.Cpu.Arch;
16const Dwarf = @import("../Dwarf.zig");
17const MachO = @import("../MachO.zig");16const MachO = @import("../MachO.zig");
18const Relocation = @import("Relocation.zig");17const Relocation = @import("Relocation.zig");
19const SymbolWithLoc = MachO.SymbolWithLoc;18const SymbolWithLoc = MachO.SymbolWithLoc;
...@@ -39,10 +38,11 @@ size: u64,...@@ -39,10 +38,11 @@ size: u64,
39alignment: u32,38alignment: u32,
4039
41/// Points to the previous and next neighbours40/// Points to the previous and next neighbours
42next: ?*Atom,41/// TODO use the same trick as with symbols: reserve index 0 as null atom
43prev: ?*Atom,42next_index: ?Index,
43prev_index: ?Index,
4444
45dbg_info_atom: Dwarf.Atom,45pub const Index = u32;
4646
47pub const Binding = struct {47pub const Binding = struct {
48 target: SymbolWithLoc,48 target: SymbolWithLoc,
...@@ -54,22 +54,6 @@ pub const SymbolAtOffset = struct {...@@ -54,22 +54,6 @@ pub const SymbolAtOffset = struct {
54 offset: u64,54 offset: u64,
55};55};
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
73pub fn getSymbolIndex(self: Atom) ?u32 {57pub fn getSymbolIndex(self: Atom) ?u32 {
74 if (self.sym_index == 0) return null;58 if (self.sym_index == 0) return null;
75 return self.sym_index;59 return self.sym_index;
...@@ -108,7 +92,8 @@ pub fn getName(self: Atom, macho_file: *MachO) []const u8 {...@@ -108,7 +92,8 @@ pub fn getName(self: Atom, macho_file: *MachO) []const u8 {
108/// this calculation.92/// this calculation.
109pub fn capacity(self: Atom, macho_file: *MachO) u64 {93pub fn capacity(self: Atom, macho_file: *MachO) u64 {
110 const self_sym = self.getSymbol(macho_file);94 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);
112 const next_sym = next.getSymbol(macho_file);97 const next_sym = next.getSymbol(macho_file);
113 return next_sym.n_value - self_sym.n_value;98 return next_sym.n_value - self_sym.n_value;
114 } else {99 } else {
...@@ -120,7 +105,8 @@ pub fn capacity(self: Atom, macho_file: *MachO) u64 {...@@ -120,7 +105,8 @@ pub fn capacity(self: Atom, macho_file: *MachO) u64 {
120105
121pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {106pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
122 // No need to keep a free list node for the last atom.107 // 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);
124 const self_sym = self.getSymbol(macho_file);110 const self_sym = self.getSymbol(macho_file);
125 const next_sym = next.getSymbol(macho_file);111 const next_sym = next.getSymbol(macho_file);
126 const cap = next_sym.n_value - self_sym.n_value;112 const cap = next_sym.n_value - self_sym.n_value;
...@@ -130,19 +116,19 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {...@@ -130,19 +116,19 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
130 return surplus >= MachO.min_text_capacity;116 return surplus >= MachO.min_text_capacity;
131}117}
132118
133pub fn addRelocation(self: *Atom, macho_file: *MachO, reloc: Relocation) !void {119pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) !void {
134 return self.addRelocations(macho_file, 1, .{reloc});120 return addRelocations(macho_file, atom_index, 1, .{reloc});
135}121}
136122
137pub fn addRelocations(123pub fn addRelocations(
138 self: *Atom,
139 macho_file: *MachO,124 macho_file: *MachO,
125 atom_index: Index,
140 comptime count: comptime_int,126 comptime count: comptime_int,
141 relocs: [count]Relocation,127 relocs: [count]Relocation,
142) !void {128) !void {
143 const gpa = macho_file.base.allocator;129 const gpa = macho_file.base.allocator;
144 const target = macho_file.base.options.target;130 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);
146 if (!gop.found_existing) {132 if (!gop.found_existing) {
147 gop.value_ptr.* = .{};133 gop.value_ptr.* = .{};
148 }134 }
...@@ -156,56 +142,72 @@ pub fn addRelocations(...@@ -156,56 +142,72 @@ pub fn addRelocations(
156 }142 }
157}143}
158144
159pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void {145pub fn addRebase(macho_file: *MachO, atom_index: Index, offset: u32) !void {
160 const gpa = macho_file.base.allocator;146 const gpa = macho_file.base.allocator;
161 log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, self.getSymbolIndex() });147 const atom = macho_file.getAtom(atom_index);
162 const gop = try macho_file.rebases.getOrPut(gpa, self);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);
163 if (!gop.found_existing) {150 if (!gop.found_existing) {
164 gop.value_ptr.* = .{};151 gop.value_ptr.* = .{};
165 }152 }
166 try gop.value_ptr.append(gpa, offset);153 try gop.value_ptr.append(gpa, offset);
167}154}
168155
169pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {156pub fn addBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void {
170 const gpa = macho_file.base.allocator;157 const gpa = macho_file.base.allocator;
158 const atom = macho_file.getAtom(atom_index);
171 log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{?d})", .{159 log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{?d})", .{
172 macho_file.getSymbolName(binding.target),160 macho_file.getSymbolName(binding.target),
173 binding.offset,161 binding.offset,
174 self.getSymbolIndex(),162 atom.getSymbolIndex(),
175 });163 });
176 const gop = try macho_file.bindings.getOrPut(gpa, self);164 const gop = try macho_file.bindings.getOrPut(gpa, atom_index);
177 if (!gop.found_existing) {165 if (!gop.found_existing) {
178 gop.value_ptr.* = .{};166 gop.value_ptr.* = .{};
179 }167 }
180 try gop.value_ptr.append(gpa, binding);168 try gop.value_ptr.append(gpa, binding);
181}169}
182170
183pub fn addLazyBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {171pub fn addLazyBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void {
184 const gpa = macho_file.base.allocator;172 const gpa = macho_file.base.allocator;
173 const atom = macho_file.getAtom(atom_index);
185 log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{?d})", .{174 log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{?d})", .{
186 macho_file.getSymbolName(binding.target),175 macho_file.getSymbolName(binding.target),
187 binding.offset,176 binding.offset,
188 self.getSymbolIndex(),177 atom.getSymbolIndex(),
189 });178 });
190 const gop = try macho_file.lazy_bindings.getOrPut(gpa, self);179 const gop = try macho_file.lazy_bindings.getOrPut(gpa, atom_index);
191 if (!gop.found_existing) {180 if (!gop.found_existing) {
192 gop.value_ptr.* = .{};181 gop.value_ptr.* = .{};
193 }182 }
194 try gop.value_ptr.append(gpa, binding);183 try gop.value_ptr.append(gpa, binding);
195}184}
196185
197pub fn resolveRelocations(self: *Atom, macho_file: *MachO) !void {186pub fn resolveRelocations(macho_file: *MachO, atom_index: Index) !void {
198 const relocs = macho_file.relocs.get(self) orelse return;187 const atom = macho_file.getAtom(atom_index);
199 const source_sym = self.getSymbol(macho_file);188 const relocs = macho_file.relocs.get(atom_index) orelse return;
189 const source_sym = atom.getSymbol(macho_file);
200 const source_section = macho_file.sections.get(source_sym.n_sect - 1).header;190 const source_section = macho_file.sections.get(source_sym.n_sect - 1).header;
201 const file_offset = source_section.offset + source_sym.n_value - source_section.addr;191 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
205 for (relocs.items) |*reloc| {195 for (relocs.items) |*reloc| {
206 if (!reloc.dirty) continue;196 if (!reloc.dirty) continue;
207197
208 try reloc.resolve(self, macho_file, file_offset);198 try reloc.resolve(macho_file, atom_index, file_offset);
209 reloc.dirty = false;199 reloc.dirty = false;
210 }200 }
211}201}
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 {...@@ -82,11 +82,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols) !void {
82 }82 }
8383
84 if (self.debug_str_section_index == null) {84 if (self.debug_str_section_index == null) {
85 assert(self.dwarf.strtab.items.len == 0);85 assert(self.dwarf.strtab.buffer.items.len == 0);
86 try self.dwarf.strtab.append(self.allocator, 0);86 try self.dwarf.strtab.buffer.append(self.allocator, 0);
87 self.debug_str_section_index = try self.allocateSection(87 self.debug_str_section_index = try self.allocateSection(
88 "__debug_str",88 "__debug_str",
89 @intCast(u32, self.dwarf.strtab.items.len),89 @intCast(u32, self.dwarf.strtab.buffer.items.len),
90 0,90 0,
91 );91 );
92 self.debug_string_table_dirty = true;92 self.debug_string_table_dirty = true;
...@@ -291,10 +291,10 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -291,10 +291,10 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
291291
292 {292 {
293 const sect_index = self.debug_str_section_index.?;293 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) {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.items.len);295 const needed_size = @intCast(u32, self.dwarf.strtab.buffer.items.len);
296 try self.growSection(sect_index, needed_size, false);296 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);
298 self.debug_string_table_dirty = false;298 self.debug_string_table_dirty = false;
299 }299 }
300 }300 }
src/link/MachO/Relocation.zig+9-7
...@@ -29,33 +29,35 @@ pub fn fmtType(self: Relocation, target: std.Target) []const u8 {...@@ -29,33 +29,35 @@ pub fn fmtType(self: Relocation, target: std.Target) []const u8 {
29 }29 }
30}30}
3131
32pub fn getTargetAtom(self: Relocation, macho_file: *MachO) ?*Atom {32pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
33 switch (macho_file.base.options.target.cpu.arch) {33 switch (macho_file.base.options.target.cpu.arch) {
34 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.type)) {34 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.type)) {
35 .ARM64_RELOC_GOT_LOAD_PAGE21,35 .ARM64_RELOC_GOT_LOAD_PAGE21,
36 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,36 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
37 .ARM64_RELOC_POINTER_TO_GOT,37 .ARM64_RELOC_POINTER_TO_GOT,
38 => return macho_file.getGotAtomForSymbol(self.target),38 => return macho_file.getGotAtomIndexForSymbol(self.target),
39 else => {},39 else => {},
40 },40 },
41 .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, self.type)) {41 .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, self.type)) {
42 .X86_64_RELOC_GOT,42 .X86_64_RELOC_GOT,
43 .X86_64_RELOC_GOT_LOAD,43 .X86_64_RELOC_GOT_LOAD,
44 => return macho_file.getGotAtomForSymbol(self.target),44 => return macho_file.getGotAtomIndexForSymbol(self.target),
45 else => {},45 else => {},
46 },46 },
47 else => unreachable,47 else => unreachable,
48 }48 }
49 if (macho_file.getStubsAtomForSymbol(self.target)) |stubs_atom| return stubs_atom;49 if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom;
50 return macho_file.getAtomForSymbol(self.target);50 return macho_file.getAtomIndexForSymbol(self.target);
51}51}
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 {
54 const arch = macho_file.base.options.target.cpu.arch;54 const arch = macho_file.base.options.target.cpu.arch;
55 const atom = macho_file.getAtom(atom_index);
55 const source_sym = atom.getSymbol(macho_file);56 const source_sym = atom.getSymbol(macho_file);
56 const source_addr = source_sym.n_value + self.offset;57 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);
59 const target_addr = @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend;61 const target_addr = @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend;
6062
61 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{63 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
src/link/Plan9.zig+149-83
...@@ -21,14 +21,7 @@ const Allocator = std.mem.Allocator;...@@ -21,14 +21,7 @@ const Allocator = std.mem.Allocator;
21const log = std.log.scoped(.link);21const log = std.log.scoped(.link);
22const assert = std.debug.assert;22const assert = std.debug.assert;
2323
24const FnDeclOutput = struct {24pub const base_tag = .plan9;
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};
3225
33base: link.File,26base: link.File,
34sixtyfour_bit: bool,27sixtyfour_bit: bool,
...@@ -101,6 +94,9 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},...@@ -101,6 +94,9 @@ got_index_free_list: std.ArrayListUnmanaged(usize) = .{},
10194
102syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},95syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},
10396
97decl_blocks: std.ArrayListUnmanaged(DeclBlock) = .{},
98decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
99
104const Reloc = struct {100const Reloc = struct {
105 target: Module.Decl.Index,101 target: Module.Decl.Index,
106 offset: u64,102 offset: u64,
...@@ -115,6 +111,42 @@ const Bases = struct {...@@ -115,6 +111,42 @@ const Bases = struct {
115111
116const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 }));112const 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
118fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 {150fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 {
119 return addr + switch (t) {151 return addr + switch (t) {
120 .T, .t, .l, .L => self.bases.text,152 .T, .t, .l, .L => self.bases.text,
...@@ -127,22 +159,6 @@ fn getSymAddr(self: Plan9, s: aout.Sym) u64 {...@@ -127,22 +159,6 @@ fn getSymAddr(self: Plan9, s: aout.Sym) u64 {
127 return self.getAddr(s.value, s.type);159 return self.getAddr(s.value, s.type);
128}160}
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
146pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {162pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
147 return switch (arch) {163 return switch (arch) {
148 .x86_64 => .{164 .x86_64 => .{
...@@ -164,8 +180,6 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {...@@ -164,8 +180,6 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
164 };180 };
165}181}
166182
167pub const PtrWidth = enum { p32, p64 };
168
169pub fn createEmpty(gpa: Allocator, options: link.Options) !*Plan9 {183pub fn createEmpty(gpa: Allocator, options: link.Options) !*Plan9 {
170 if (options.use_llvm)184 if (options.use_llvm)
171 return error.LLVMBackendDoesNotSupportPlan9;185 return error.LLVMBackendDoesNotSupportPlan9;
...@@ -271,7 +285,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv...@@ -271,7 +285,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
271 const decl = module.declPtr(decl_index);285 const decl = module.declPtr(decl_index);
272 self.freeUnnamedConsts(decl_index);286 self.freeUnnamedConsts(decl_index);
273287
274 try self.seeDecl(decl_index);288 _ = try self.seeDecl(decl_index);
275 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });289 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });
276290
277 var code_buffer = std.ArrayList(u8).init(self.base.allocator);291 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...@@ -313,11 +327,11 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
313 .end_line = end_line,327 .end_line = end_line,
314 };328 };
315 try self.putFn(decl_index, out);329 try self.putFn(decl_index, out);
316 return self.updateFinish(decl);330 return self.updateFinish(decl_index);
317}331}
318332
319pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {333pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {
320 try self.seeDecl(decl_index);334 _ = try self.seeDecl(decl_index);
321 var code_buffer = std.ArrayList(u8).init(self.base.allocator);335 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
322 defer code_buffer.deinit();336 defer code_buffer.deinit();
323337
...@@ -387,7 +401,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index)...@@ -387,7 +401,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index)
387 }401 }
388 }402 }
389403
390 try self.seeDecl(decl_index);404 _ = try self.seeDecl(decl_index);
391405
392 log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index });406 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)...@@ -414,28 +428,31 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index)
414 if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| {428 if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| {
415 self.base.allocator.free(old_entry.value);429 self.base.allocator.free(old_entry.value);
416 }430 }
417 return self.updateFinish(decl);431 return self.updateFinish(decl_index);
418}432}
419/// called at the end of update{Decl,Func}433/// 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);
421 const is_fn = (decl.ty.zigTypeTag() == .Fn);436 const is_fn = (decl.ty.zigTypeTag() == .Fn);
422 log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name });437 log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name });
423 const sym_t: aout.Sym.Type = if (is_fn) .t else .d;438 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);
424 // write the internal linker metadata441 // write the internal linker metadata
425 decl.link.plan9.type = sym_t;442 decl_block.type = sym_t;
426 // write the symbol443 // write the symbol
427 // we already have the got index444 // we already have the got index
428 const sym: aout.Sym = .{445 const sym: aout.Sym = .{
429 .value = undefined, // the value of stuff gets filled in in flushModule446 .value = undefined, // the value of stuff gets filled in in flushModule
430 .type = decl.link.plan9.type,447 .type = decl_block.type,
431 .name = mem.span(decl.name),448 .name = mem.span(decl.name),
432 };449 };
433450
434 if (decl.link.plan9.sym_index) |s| {451 if (decl_block.sym_index) |s| {
435 self.syms.items[s] = sym;452 self.syms.items[s] = sym;
436 } else {453 } else {
437 const s = try self.allocateSymbolIndex();454 const s = try self.allocateSymbolIndex();
438 decl.link.plan9.sym_index = s;455 decl_block.sym_index = s;
439 self.syms.items[s] = sym;456 self.syms.items[s] = sym;
440 }457 }
441}458}
...@@ -550,6 +567,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -550,6 +567,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
550 while (it.next()) |entry| {567 while (it.next()) |entry| {
551 const decl_index = entry.key_ptr.*;568 const decl_index = entry.key_ptr.*;
552 const decl = mod.declPtr(decl_index);569 const decl = mod.declPtr(decl_index);
570 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);
553 const out = entry.value_ptr.*;571 const out = entry.value_ptr.*;
554 log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line + 1, out.end_line });572 log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line + 1, out.end_line });
555 {573 {
...@@ -568,16 +586,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -568,16 +586,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
568 iovecs_i += 1;586 iovecs_i += 1;
569 const off = self.getAddr(text_i, .t);587 const off = self.getAddr(text_i, .t);
570 text_i += out.code.len;588 text_i += out.code.len;
571 decl.link.plan9.offset = off;589 decl_block.offset = off;
572 if (!self.sixtyfour_bit) {590 if (!self.sixtyfour_bit) {
573 mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off));591 mem.writeIntNative(u32, got_table[decl_block.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());592 mem.writeInt(u32, got_table[decl_block.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
575 } else {593 } 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());
577 }595 }
578 self.syms.items[decl.link.plan9.sym_index.?].value = off;596 self.syms.items[decl_block.sym_index.?].value = off;
579 if (mod.decl_exports.get(decl_index)) |exports| {597 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);
581 }599 }
582 }600 }
583 }601 }
...@@ -598,6 +616,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -598,6 +616,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
598 while (it.next()) |entry| {616 while (it.next()) |entry| {
599 const decl_index = entry.key_ptr.*;617 const decl_index = entry.key_ptr.*;
600 const decl = mod.declPtr(decl_index);618 const decl = mod.declPtr(decl_index);
619 const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index);
601 const code = entry.value_ptr.*;620 const code = entry.value_ptr.*;
602 log.debug("write data decl {*} ({s})", .{ decl, decl.name });621 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...@@ -606,15 +625,15 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
606 iovecs_i += 1;625 iovecs_i += 1;
607 const off = self.getAddr(data_i, .d);626 const off = self.getAddr(data_i, .d);
608 data_i += code.len;627 data_i += code.len;
609 decl.link.plan9.offset = off;628 decl_block.offset = off;
610 if (!self.sixtyfour_bit) {629 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());
612 } else {631 } 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());
614 }633 }
615 self.syms.items[decl.link.plan9.sym_index.?].value = off;634 self.syms.items[decl_block.sym_index.?].value = off;
616 if (mod.decl_exports.get(decl_index)) |exports| {635 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);
618 }637 }
619 }638 }
620 // write the unnamed constants after the other data decls639 // 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...@@ -676,7 +695,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
676 for (kv.value_ptr.items) |reloc| {695 for (kv.value_ptr.items) |reloc| {
677 const target_decl_index = reloc.target;696 const target_decl_index = reloc.target;
678 const target_decl = mod.declPtr(target_decl_index);697 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
681 const offset = reloc.offset;701 const offset = reloc.offset;
682 const addend = reloc.addend;702 const addend = reloc.addend;
...@@ -709,28 +729,36 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -709,28 +729,36 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
709fn addDeclExports(729fn addDeclExports(
710 self: *Plan9,730 self: *Plan9,
711 module: *Module,731 module: *Module,
712 decl: *Module.Decl,732 decl_index: Module.Decl.Index,
713 exports: []const *Module.Export,733 exports: []const *Module.Export,
714) !void {734) !void {
735 const metadata = self.decls.getPtr(decl_index).?;
736 const decl_block = self.getDeclBlock(metadata.index);
737
715 for (exports) |exp| {738 for (exports) |exp| {
716 // plan9 does not support custom sections739 // plan9 does not support custom sections
717 if (exp.options.section) |section_name| {740 if (exp.options.section) |section_name| {
718 if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) {741 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 ));
720 break;748 break;
721 }749 }
722 }750 }
723 const sym = .{751 const sym = .{
724 .value = decl.link.plan9.offset.?,752 .value = decl_block.offset.?,
725 .type = decl.link.plan9.type.toGlobal(),753 .type = decl_block.type.toGlobal(),
726 .name = exp.options.name,754 .name = exp.options.name,
727 };755 };
728756
729 if (exp.link.plan9) |i| {757 if (metadata.getExport(self, exp.options.name)) |i| {
730 self.syms.items[i] = sym;758 self.syms.items[i] = sym;
731 } else {759 } else {
732 try self.syms.append(self.base.allocator, sym);760 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);
734 }762 }
735 }763 }
736}764}
...@@ -760,13 +788,18 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {...@@ -760,13 +788,18 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {
760 self.base.allocator.free(removed_entry.value);788 self.base.allocator.free(removed_entry.value);
761 }789 }
762 }790 }
763 if (decl.link.plan9.got_index) |i| {791 if (self.decls.fetchRemove(decl_index)) |const_kv| {
764 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length792 var kv = const_kv;
765 self.got_index_free_list.append(self.base.allocator, i) catch {};793 const decl_block = self.getDeclBlock(kv.value.index);
766 }794 if (decl_block.got_index) |i| {
767 if (decl.link.plan9.sym_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
768 self.syms_index_free_list.append(self.base.allocator, i) catch {};796 self.got_index_free_list.append(self.base.allocator, i) catch {};
769 self.syms.items[i] = aout.Sym.undefined_symbol;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);
770 }803 }
771 self.freeUnnamedConsts(decl_index);804 self.freeUnnamedConsts(decl_index);
772 {805 {
...@@ -786,12 +819,30 @@ fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void {...@@ -786,12 +819,30 @@ fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void {
786 unnamed_consts.clearAndFree(self.base.allocator);819 unnamed_consts.clearAndFree(self.base.allocator);
787}820}
788821
789pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void {822fn createDeclBlock(self: *Plan9) !DeclBlock.Index {
790 const mod = self.base.options.module.?;823 const gpa = self.base.allocator;
791 const decl = mod.declPtr(decl_index);824 const index = @intCast(DeclBlock.Index, self.decl_blocks.items.len);
792 if (decl.link.plan9.got_index == null) {825 const decl_block = try self.decl_blocks.addOne(gpa);
793 decl.link.plan9.got_index = self.allocateGotIndex();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 };
794 }844 }
845 return gop.value_ptr.index;
795}846}
796847
797pub fn updateDeclExports(848pub fn updateDeclExports(
...@@ -800,7 +851,7 @@ pub fn updateDeclExports(...@@ -800,7 +851,7 @@ pub fn updateDeclExports(
800 decl_index: Module.Decl.Index,851 decl_index: Module.Decl.Index,
801 exports: []const *Module.Export,852 exports: []const *Module.Export,
802) !void {853) !void {
803 try self.seeDecl(decl_index);854 _ = try self.seeDecl(decl_index);
804 // we do all the things in flush855 // we do all the things in flush
805 _ = module;856 _ = module;
806 _ = exports;857 _ = exports;
...@@ -842,10 +893,17 @@ pub fn deinit(self: *Plan9) void {...@@ -842,10 +893,17 @@ pub fn deinit(self: *Plan9) void {
842 self.syms_index_free_list.deinit(gpa);893 self.syms_index_free_list.deinit(gpa);
843 self.file_segments.deinit(gpa);894 self.file_segments.deinit(gpa);
844 self.path_arena.deinit();895 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 }
845}905}
846906
847pub const Export = ?usize;
848pub const base_tag = .plan9;
849pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {907pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {
850 if (options.use_llvm)908 if (options.use_llvm)
851 return error.LLVMBackendDoesNotSupportPlan9;909 return error.LLVMBackendDoesNotSupportPlan9;
...@@ -911,20 +969,19 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -911,20 +969,19 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
911 }969 }
912 }970 }
913971
914 const mod = self.base.options.module.?;
915
916 // write the data symbols972 // write the data symbols
917 {973 {
918 var it = self.data_decl_table.iterator();974 var it = self.data_decl_table.iterator();
919 while (it.next()) |entry| {975 while (it.next()) |entry| {
920 const decl_index = entry.key_ptr.*;976 const decl_index = entry.key_ptr.*;
921 const decl = mod.declPtr(decl_index);977 const decl_metadata = self.decls.get(decl_index).?;
922 const sym = self.syms.items[decl.link.plan9.sym_index.?];978 const decl_block = self.getDeclBlock(decl_metadata.index);
979 const sym = self.syms.items[decl_block.sym_index.?];
923 try self.writeSym(writer, sym);980 try self.writeSym(writer, sym);
924 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {981 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
925 for (exports.items) |e| {982 for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| {
926 try self.writeSym(writer, self.syms.items[e.link.plan9.?]);983 try self.writeSym(writer, self.syms.items[exp_i]);
927 }984 };
928 }985 }
929 }986 }
930 }987 }
...@@ -943,16 +1000,17 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -943,16 +1000,17 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
943 var submap_it = symidx_and_submap.functions.iterator();1000 var submap_it = symidx_and_submap.functions.iterator();
944 while (submap_it.next()) |entry| {1001 while (submap_it.next()) |entry| {
945 const decl_index = entry.key_ptr.*;1002 const decl_index = entry.key_ptr.*;
946 const decl = mod.declPtr(decl_index);1003 const decl_metadata = self.decls.get(decl_index).?;
947 const sym = self.syms.items[decl.link.plan9.sym_index.?];1004 const decl_block = self.getDeclBlock(decl_metadata.index);
1005 const sym = self.syms.items[decl_block.sym_index.?];
948 try self.writeSym(writer, sym);1006 try self.writeSym(writer, sym);
949 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {1007 if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| {
950 for (exports.items) |e| {1008 for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| {
951 const s = self.syms.items[e.link.plan9.?];1009 const s = self.syms.items[exp_i];
952 if (mem.eql(u8, s.name, "_start"))1010 if (mem.eql(u8, s.name, "_start"))
953 self.entry_val = s.value;1011 self.entry_val = s.value;
954 try self.writeSym(writer, s);1012 try self.writeSym(writer, s);
955 }1013 };
956 }1014 }
957 }1015 }
958 }1016 }
...@@ -960,10 +1018,10 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -960,10 +1018,10 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
960}1018}
9611019
962/// Must be called only after a successful call to `updateDecl`.1020/// 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 {
964 _ = self;1022 _ = self;
965 _ = mod;1023 _ = mod;
966 _ = decl;1024 _ = decl_index;
967}1025}
9681026
969pub fn getDeclVAddr(1027pub fn getDeclVAddr(
...@@ -1004,3 +1062,11 @@ pub fn getDeclVAddr(...@@ -1004,3 +1062,11 @@ pub fn getDeclVAddr(
1004 });1062 });
1005 return undefined;1063 return undefined;
1006}1064}
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");...@@ -42,13 +42,6 @@ const SpvModule = @import("../codegen/spirv/Module.zig");
42const spec = @import("../codegen/spirv/spec.zig");42const spec = @import("../codegen/spirv/spec.zig");
43const IdResult = spec.IdResult;43const 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
52base: link.File,45base: link.File,
5346
54/// This linker backend does not try to incrementally link output SPIR-V code.47/// 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...@@ -209,16 +202,19 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
209 // so that we can access them before processing them.202 // so that we can access them before processing them.
210 // TODO: We're allocating an ID unconditionally now, are there203 // TODO: We're allocating an ID unconditionally now, are there
211 // declarations which don't generate a result?204 // 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
213 for (self.decl_table.keys()) |decl_index| {209 for (self.decl_table.keys()) |decl_index| {
214 const decl = module.declPtr(decl_index);210 const decl = module.declPtr(decl_index);
215 if (decl.has_tv) {211 if (decl.has_tv) {
216 decl.fn_link.spirv.id = spv.allocId();212 ids.putAssumeCapacityNoClobber(decl_index, spv.allocId());
217 }213 }
218 }214 }
219215
220 // Now, actually generate the code for all declarations.216 // 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);
222 defer decl_gen.deinit();218 defer decl_gen.deinit();
223219
224 var it = self.decl_table.iterator();220 var it = self.decl_table.iterator();
...@@ -231,7 +227,7 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No...@@ -231,7 +227,7 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
231 const liveness = entry.value_ptr.liveness;227 const liveness = entry.value_ptr.liveness;
232228
233 // Note, if `decl` is not a function, air/liveness may be undefined.229 // 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| {
235 try module.failed_decls.put(module.gpa, decl_index, msg);231 try module.failed_decls.put(module.gpa, decl_index, msg);
236 return; // TODO: Attempt to generate more decls?232 return; // TODO: Attempt to generate more decls?
237 }233 }
src/link/Wasm.zig+281-258
...@@ -9,7 +9,7 @@ const fs = std.fs;...@@ -9,7 +9,7 @@ const fs = std.fs;
9const leb = std.leb;9const leb = std.leb;
10const log = std.log.scoped(.link);10const log = std.log.scoped(.link);
1111
12const Atom = @import("Wasm/Atom.zig");12pub const Atom = @import("Wasm/Atom.zig");
13const Dwarf = @import("Dwarf.zig");13const Dwarf = @import("Dwarf.zig");
14const Module = @import("../Module.zig");14const Module = @import("../Module.zig");
15const Compilation = @import("../Compilation.zig");15const Compilation = @import("../Compilation.zig");
...@@ -31,10 +31,7 @@ const Object = @import("Wasm/Object.zig");...@@ -31,10 +31,7 @@ const Object = @import("Wasm/Object.zig");
31const Archive = @import("Wasm/Archive.zig");31const Archive = @import("Wasm/Archive.zig");
32const types = @import("Wasm/types.zig");32const types = @import("Wasm/types.zig");
3333
34pub const base_tag = link.File.Tag.wasm;34pub const base_tag: link.File.Tag = .wasm;
35
36/// deprecated: Use `@import("Wasm/Atom.zig");`
37pub const DeclBlock = Atom;
3835
39base: link.File,36base: link.File,
40/// Output name of the file37/// Output name of the file
...@@ -47,18 +44,16 @@ llvm_object: ?*LlvmObject = null,...@@ -47,18 +44,16 @@ llvm_object: ?*LlvmObject = null,
47/// TODO: Allow setting this through a flag?44/// TODO: Allow setting this through a flag?
48host_name: []const u8 = "env",45host_name: []const u8 = "env",
49/// List of all `Decl` that are currently alive.46/// List of all `Decl` that are currently alive.
50/// This is ment for bookkeeping so we can safely cleanup all codegen memory47/// Each index maps to the corresponding `Atom.Index`.
51/// when calling `deinit`48decls: std.AutoHashMapUnmanaged(Module.Decl.Index, Atom.Index) = .{},
52decls: std.AutoHashMapUnmanaged(Module.Decl.Index, void) = .{},
53/// List of all symbols generated by Zig code.49/// List of all symbols generated by Zig code.
54symbols: std.ArrayListUnmanaged(Symbol) = .{},50symbols: std.ArrayListUnmanaged(Symbol) = .{},
55/// List of symbol indexes which are free to be used.51/// List of symbol indexes which are free to be used.
56symbols_free_list: std.ArrayListUnmanaged(u32) = .{},52symbols_free_list: std.ArrayListUnmanaged(u32) = .{},
57/// Maps atoms to their segment index53/// Maps atoms to their segment index
58atoms: std.AutoHashMapUnmanaged(u32, *Atom) = .{},54atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
59/// Atoms managed and created by the linker. This contains atoms55/// List of all atoms.
60/// from object files, and not Atoms generated by a Decl.56managed_atoms: std.ArrayListUnmanaged(Atom) = .{},
61managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
62/// Represents the index into `segments` where the 'code' section57/// Represents the index into `segments` where the 'code' section
63/// lives.58/// lives.
64code_section_index: ?u32 = null,59code_section_index: ?u32 = null,
...@@ -148,7 +143,7 @@ undefs: std.StringArrayHashMapUnmanaged(SymbolLoc) = .{},...@@ -148,7 +143,7 @@ undefs: std.StringArrayHashMapUnmanaged(SymbolLoc) = .{},
148/// Maps a symbol's location to an atom. This can be used to find meta143/// Maps a symbol's location to an atom. This can be used to find meta
149/// data of a symbol, such as its size, or its offset to perform a relocation.144/// data of a symbol, such as its size, or its offset to perform a relocation.
150/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.145/// 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) = .{},
152/// Maps a symbol's location to its export name, which may differ from the decl's name147/// Maps a symbol's location to its export name, which may differ from the decl's name
153/// which does the exporting.148/// which does the exporting.
154/// Note: The value represents the offset into the string table, rather than the actual string.149/// Note: The value represents the offset into the string table, rather than the actual string.
...@@ -165,14 +160,14 @@ error_table_symbol: ?u32 = null,...@@ -165,14 +160,14 @@ error_table_symbol: ?u32 = null,
165// unit contains Zig code. The lifetime of these atoms are extended160// unit contains Zig code. The lifetime of these atoms are extended
166// until the end of the compiler's lifetime. Meaning they're not freed161// until the end of the compiler's lifetime. Meaning they're not freed
167// during `flush()` in incremental-mode.162// during `flush()` in incremental-mode.
168debug_info_atom: ?*Atom = null,163debug_info_atom: ?Atom.Index = null,
169debug_line_atom: ?*Atom = null,164debug_line_atom: ?Atom.Index = null,
170debug_loc_atom: ?*Atom = null,165debug_loc_atom: ?Atom.Index = null,
171debug_ranges_atom: ?*Atom = null,166debug_ranges_atom: ?Atom.Index = null,
172debug_abbrev_atom: ?*Atom = null,167debug_abbrev_atom: ?Atom.Index = null,
173debug_str_atom: ?*Atom = null,168debug_str_atom: ?Atom.Index = null,
174debug_pubnames_atom: ?*Atom = null,169debug_pubnames_atom: ?Atom.Index = null,
175debug_pubtypes_atom: ?*Atom = null,170debug_pubtypes_atom: ?Atom.Index = null,
176171
177pub const Segment = struct {172pub const Segment = struct {
178 alignment: u32,173 alignment: u32,
...@@ -183,13 +178,9 @@ pub const Segment = struct {...@@ -183,13 +178,9 @@ pub const Segment = struct {
183pub const FnData = struct {178pub const FnData = struct {
184 /// Reference to the wasm type that represents this function.179 /// Reference to the wasm type that represents this function.
185 type_index: u32,180 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
190 pub const empty: FnData = .{182 pub const empty: FnData = .{
191 .type_index = undefined,183 .type_index = undefined,
192 .src_fn = Dwarf.SrcFn.empty,
193 };184 };
194};185};
195186
...@@ -434,10 +425,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -434,10 +425,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
434 // at the end during `initializeCallCtorsFunction`.425 // at the end during `initializeCallCtorsFunction`.
435 }426 }
436427
437 if (!options.strip and options.module != null) {428 // if (!options.strip and options.module != null) {
438 wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);429 // wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);
439 try wasm_bin.initDebugSections();430 // try wasm_bin.initDebugSections();
440 }431 // }
441432
442 return wasm_bin;433 return wasm_bin;
443}434}
...@@ -478,6 +469,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol...@@ -478,6 +469,7 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol
478 try wasm.globals.put(wasm.base.allocator, name_offset, loc);469 try wasm.globals.put(wasm.base.allocator, name_offset, loc);
479 return loc;470 return loc;
480}471}
472
481/// Initializes symbols and atoms for the debug sections473/// Initializes symbols and atoms for the debug sections
482/// Initialization is only done when compiling Zig code.474/// Initialization is only done when compiling Zig code.
483/// When Zig is invoked as a linker instead, the atoms475/// When Zig is invoked as a linker instead, the atoms
...@@ -520,6 +512,36 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {...@@ -520,6 +512,36 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
520 return true;512 return true;
521}513}
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
523/// Parses an archive file and will then parse each object file545/// Parses an archive file and will then parse each object file
524/// that was found in the archive file.546/// that was found in the archive file.
525/// Returns false when the file is not an archive file.547/// Returns false when the file is not an archive file.
...@@ -861,15 +883,16 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -861,15 +883,16 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
861 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);883 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
862 _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations.884 _ = 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);886 // TODO: Can we use `createAtom` here while also re-using the symbol
865 errdefer wasm.base.allocator.destroy(atom);887 // from `createSyntheticSymbol`.
866 try wasm.managed_atoms.append(wasm.base.allocator, atom);888 const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
889 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
867 atom.* = Atom.empty;890 atom.* = Atom.empty;
868 atom.sym_index = loc.index;891 atom.sym_index = loc.index;
869 atom.alignment = 1;892 atom.alignment = 1;
870893
871 try wasm.parseAtom(atom, .{ .data = .synthetic });894 try wasm.parseAtom(atom_index, .{ .data = .synthetic });
872 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);895 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
873 }896 }
874897
875 if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| {898 if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| {
...@@ -877,15 +900,14 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -877,15 +900,14 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
877 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);900 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
878 _ = wasm.resolved_symbols.swapRemove(loc);901 _ = wasm.resolved_symbols.swapRemove(loc);
879902
880 const atom = try wasm.base.allocator.create(Atom);903 const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
881 errdefer wasm.base.allocator.destroy(atom);904 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
882 try wasm.managed_atoms.append(wasm.base.allocator, atom);
883 atom.* = Atom.empty;905 atom.* = Atom.empty;
884 atom.sym_index = loc.index;906 atom.sym_index = loc.index;
885 atom.alignment = 1;907 atom.alignment = 1;
886908
887 try wasm.parseAtom(atom, .{ .data = .synthetic });909 try wasm.parseAtom(atom_index, .{ .data = .synthetic });
888 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);910 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
889 }911 }
890}912}
891913
...@@ -924,16 +946,6 @@ pub fn deinit(wasm: *Wasm) void {...@@ -924,16 +946,6 @@ pub fn deinit(wasm: *Wasm) void {
924 if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);946 if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);
925 }947 }
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
937 for (wasm.func_types.items) |*func_type| {949 for (wasm.func_types.items) |*func_type| {
938 func_type.deinit(gpa);950 func_type.deinit(gpa);
939 }951 }
...@@ -958,9 +970,8 @@ pub fn deinit(wasm: *Wasm) void {...@@ -958,9 +970,8 @@ pub fn deinit(wasm: *Wasm) void {
958 wasm.symbol_atom.deinit(gpa);970 wasm.symbol_atom.deinit(gpa);
959 wasm.export_names.deinit(gpa);971 wasm.export_names.deinit(gpa);
960 wasm.atoms.deinit(gpa);972 wasm.atoms.deinit(gpa);
961 for (wasm.managed_atoms.items) |managed_atom| {973 for (wasm.managed_atoms.items) |*managed_atom| {
962 managed_atom.deinit(gpa);974 managed_atom.deinit(wasm);
963 gpa.destroy(managed_atom);
964 }975 }
965 wasm.managed_atoms.deinit(gpa);976 wasm.managed_atoms.deinit(gpa);
966 wasm.segments.deinit(gpa);977 wasm.segments.deinit(gpa);
...@@ -1018,18 +1029,24 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes...@@ -1018,18 +1029,24 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
10181029
1019 const decl_index = func.owner_decl;1030 const decl_index = func.owner_decl;
1020 const decl = mod.declPtr(decl_index);1031 const decl = mod.declPtr(decl_index);
1021 const atom = &decl.link.wasm;1032 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1022 try atom.ensureInitialized(wasm);1033 const atom = wasm.getAtomPtr(atom_index);
1023 const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);1034 atom.clear();
1024 if (gop.found_existing) {
1025 atom.clear();
1026 } else gop.value_ptr.* = {};
10271035
1028 var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;1036 // 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();1037 // defer if (decl_state) |*ds| ds.deinit();
10301038
1031 var code_writer = std.ArrayList(u8).init(wasm.base.allocator);1039 var code_writer = std.ArrayList(u8).init(wasm.base.allocator);
1032 defer code_writer.deinit();1040 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 // );
1033 const result = try codegen.generateFunction(1050 const result = try codegen.generateFunction(
1034 &wasm.base,1051 &wasm.base,
1035 decl.srcLoc(),1052 decl.srcLoc(),
...@@ -1037,7 +1054,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes...@@ -1037,7 +1054,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
1037 air,1054 air,
1038 liveness,1055 liveness,
1039 &code_writer,1056 &code_writer,
1040 if (decl_state) |*ds| .{ .dwarf = ds } else .none,1057 .none,
1041 );1058 );
10421059
1043 const code = switch (result) {1060 const code = switch (result) {
...@@ -1049,19 +1066,19 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes...@@ -1049,19 +1066,19 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
1049 },1066 },
1050 };1067 };
10511068
1052 if (wasm.dwarf) |*dwarf| {1069 // if (wasm.dwarf) |*dwarf| {
1053 try dwarf.commitDeclState(1070 // try dwarf.commitDeclState(
1054 mod,1071 // mod,
1055 decl_index,1072 // decl_index,
1056 // Actual value will be written after relocation.1073 // // Actual value will be written after relocation.
1057 // For Wasm, this is the offset relative to the code section1074 // // For Wasm, this is the offset relative to the code section
1058 // which isn't known until flush().1075 // // which isn't known until flush().
1059 0,1076 // 0,
1060 code.len,1077 // code.len,
1061 &decl_state.?,1078 // &decl_state.?,
1062 );1079 // );
1063 }1080 // }
1064 return wasm.finishUpdateDecl(decl, code);1081 return wasm.finishUpdateDecl(decl_index, code);
1065}1082}
10661083
1067// Generate code for the Decl, storing it in memory to be later written to1084// 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...@@ -1084,17 +1101,14 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
1084 return;1101 return;
1085 }1102 }
10861103
1087 const atom = &decl.link.wasm;1104 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1088 try atom.ensureInitialized(wasm);1105 const atom = wasm.getAtomPtr(atom_index);
1089 const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);1106 atom.clear();
1090 if (gop.found_existing) {
1091 atom.clear();
1092 } else gop.value_ptr.* = {};
10931107
1094 if (decl.isExtern()) {1108 if (decl.isExtern()) {
1095 const variable = decl.getVariable().?;1109 const variable = decl.getVariable().?;
1096 const name = mem.sliceTo(decl.name, 0);1110 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);
1098 }1112 }
1099 const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;1113 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...@@ -1107,7 +1121,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
1107 .{ .ty = decl.ty, .val = val },1121 .{ .ty = decl.ty, .val = val },
1108 &code_writer,1122 &code_writer,
1109 .none,1123 .none,
1110 .{ .parent_atom_index = decl.link.wasm.sym_index },1124 .{ .parent_atom_index = atom.sym_index },
1111 );1125 );
11121126
1113 const code = switch (res) {1127 const code = switch (res) {
...@@ -1119,26 +1133,29 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi...@@ -1119,26 +1133,29 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
1119 },1133 },
1120 };1134 };
11211135
1122 return wasm.finishUpdateDecl(decl, code);1136 return wasm.finishUpdateDecl(decl_index, code);
1123}1137}
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 {
1126 if (wasm.llvm_object) |_| return;1140 if (wasm.llvm_object) |_| return;
1127 if (wasm.dwarf) |*dw| {1141 if (wasm.dwarf) |*dw| {
1128 const tracy = trace(@src());1142 const tracy = trace(@src());
1129 defer tracy.end();1143 defer tracy.end();
11301144
1145 const decl = mod.declPtr(decl_index);
1131 const decl_name = try decl.getFullyQualifiedName(mod);1146 const decl_name = try decl.getFullyQualifiedName(mod);
1132 defer wasm.base.allocator.free(decl_name);1147 defer wasm.base.allocator.free(decl_name);
11331148
1134 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });1149 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
1135 try dw.updateDeclLineNumber(decl);1150 try dw.updateDeclLineNumber(mod, decl_index);
1136 }1151 }
1137}1152}
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 {
1140 const mod = wasm.base.options.module.?;1155 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);
1142 const symbol = &wasm.symbols.items[atom.sym_index];1159 const symbol = &wasm.symbols.items[atom.sym_index];
1143 const full_name = try decl.getFullyQualifiedName(mod);1160 const full_name = try decl.getFullyQualifiedName(mod);
1144 defer wasm.base.allocator.free(full_name);1161 defer wasm.base.allocator.free(full_name);
...@@ -1204,48 +1221,51 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1204,48 +1221,51 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1204 const decl = mod.declPtr(decl_index);1221 const decl = mod.declPtr(decl_index);
12051222
1206 // Create and initialize a new local symbol and atom1223 // 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);
1208 const fqdn = try decl.getFullyQualifiedName(mod);1229 const fqdn = try decl.getFullyQualifiedName(mod);
1209 defer wasm.base.allocator.free(fqdn);1230 defer wasm.base.allocator.free(fqdn);
1210 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index });1231 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index });
1211 defer wasm.base.allocator.free(name);1232 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
1226 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);1233 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
1227 defer value_bytes.deinit();1234 defer value_bytes.deinit();
12281235
1229 const result = try codegen.generateSymbol(1236 const code = code: {
1230 &wasm.base,1237 const atom = wasm.getAtomPtr(atom_index);
1231 decl.srcLoc(),1238 atom.alignment = tv.ty.abiAlignment(wasm.base.options.target);
1232 tv,1239 wasm.symbols.items[atom.sym_index] = .{
1233 &value_bytes,1240 .name = try wasm.string_table.put(wasm.base.allocator, name),
1234 .none,1241 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1235 .{1242 .tag = .data,
1236 .parent_atom_index = atom.sym_index,1243 .index = undefined,
1237 .addend = null,1244 };
1238 },1245 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});
1239 );1246
1240 const code = switch (result) {1247 const result = try codegen.generateSymbol(
1241 .ok => value_bytes.items,1248 &wasm.base,
1242 .fail => |em| {1249 decl.srcLoc(),
1243 decl.analysis = .codegen_failure;1250 tv,
1244 try mod.failed_decls.put(mod.gpa, decl_index, em);1251 &value_bytes,
1245 return error.AnalysisFail;1252 .none,
1246 },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 };
1247 };1266 };
12481267
1268 const atom = wasm.getAtomPtr(atom_index);
1249 atom.size = @intCast(u32, code.len);1269 atom.size = @intCast(u32, code.len);
1250 try atom.code.appendSlice(wasm.base.allocator, code);1270 try atom.code.appendSlice(wasm.base.allocator, code);
1251 return atom.sym_index;1271 return atom.sym_index;
...@@ -1293,10 +1313,13 @@ pub fn getDeclVAddr(...@@ -1293,10 +1313,13 @@ pub fn getDeclVAddr(
1293) !u64 {1313) !u64 {
1294 const mod = wasm.base.options.module.?;1314 const mod = wasm.base.options.module.?;
1295 const decl = mod.declPtr(decl_index);1315 const decl = mod.declPtr(decl_index);
1296 try decl.link.wasm.ensureInitialized(wasm);1316
1297 const target_symbol_index = decl.link.wasm.sym_index;1317 const target_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1318 const target_symbol_index = wasm.getAtom(target_atom_index).sym_index;
1319
1298 assert(reloc_info.parent_atom_index != 0);1320 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);
1300 const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;1323 const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;
1301 if (decl.ty.zigTypeTag() == .Fn) {1324 if (decl.ty.zigTypeTag() == .Fn) {
1302 assert(reloc_info.addend == 0); // addend not allowed for function relocations1325 assert(reloc_info.addend == 0); // addend not allowed for function relocations
...@@ -1324,9 +1347,10 @@ pub fn getDeclVAddr(...@@ -1324,9 +1347,10 @@ pub fn getDeclVAddr(
1324 return target_symbol_index;1347 return target_symbol_index;
1325}1348}
13261349
1327pub fn deleteExport(wasm: *Wasm, exp: Export) void {1350pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {
1328 if (wasm.llvm_object) |_| return;1351 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;
1330 const loc: SymbolLoc = .{ .file = null, .index = sym_index };1354 const loc: SymbolLoc = .{ .file = null, .index = sym_index };
1331 const symbol = loc.getSymbol(wasm);1355 const symbol = loc.getSymbol(wasm);
1332 const symbol_name = wasm.string_table.get(symbol.name);1356 const symbol_name = wasm.string_table.get(symbol.name);
...@@ -1352,7 +1376,8 @@ pub fn updateDeclExports(...@@ -1352,7 +1376,8 @@ pub fn updateDeclExports(
1352 }1376 }
13531377
1354 const decl = mod.declPtr(decl_index);1378 const decl = mod.declPtr(decl_index);
1355 if (decl.link.wasm.getSymbolIndex() == null) return; // unititialized1379 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1380 const atom = wasm.getAtom(atom_index);
13561381
1357 for (exports) |exp| {1382 for (exports) |exp| {
1358 if (exp.options.section) |section| {1383 if (exp.options.section) |section| {
...@@ -1367,7 +1392,7 @@ pub fn updateDeclExports(...@@ -1367,7 +1392,7 @@ pub fn updateDeclExports(
13671392
1368 const export_name = try wasm.string_table.put(wasm.base.allocator, exp.options.name);1393 const export_name = try wasm.string_table.put(wasm.base.allocator, exp.options.name);
1369 if (wasm.globals.getPtr(export_name)) |existing_loc| {1394 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;
1371 const existing_sym: Symbol = existing_loc.getSymbol(wasm).*;1396 const existing_sym: Symbol = existing_loc.getSymbol(wasm).*;
13721397
1373 const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak;1398 const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak;
...@@ -1388,15 +1413,16 @@ pub fn updateDeclExports(...@@ -1388,15 +1413,16 @@ pub fn updateDeclExports(
1388 } else if (exp_is_weak) {1413 } else if (exp_is_weak) {
1389 continue; // to-be-exported symbol is weak, so we keep the existing symbol1414 continue; // to-be-exported symbol is weak, so we keep the existing symbol
1390 } else {1415 } 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;
1392 existing_loc.file = null;1418 existing_loc.file = null;
1393 exp.link.wasm.sym_index = existing_loc.index;1419 // exp.link.wasm.sym_index = existing_loc.index;
1394 }1420 }
1395 }1421 }
13961422
1397 const exported_decl = mod.declPtr(exp.exported_decl);1423 const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl);
1398 const sym_index = exported_decl.link.wasm.sym_index;1424 const exported_atom = wasm.getAtom(exported_atom_index);
1399 const sym_loc = exported_decl.link.wasm.symbolLoc();1425 const sym_loc = exported_atom.symbolLoc();
1400 const symbol = sym_loc.getSymbol(wasm);1426 const symbol = sym_loc.getSymbol(wasm);
1401 switch (exp.options.linkage) {1427 switch (exp.options.linkage) {
1402 .Internal => {1428 .Internal => {
...@@ -1432,7 +1458,6 @@ pub fn updateDeclExports(...@@ -1432,7 +1458,6 @@ pub fn updateDeclExports(
1432 // if the symbol was previously undefined, remove it as an import1458 // if the symbol was previously undefined, remove it as an import
1433 _ = wasm.imports.remove(sym_loc);1459 _ = wasm.imports.remove(sym_loc);
1434 _ = wasm.undefs.swapRemove(exp.options.name);1460 _ = wasm.undefs.swapRemove(exp.options.name);
1435 exp.link.wasm.sym_index = sym_index;
1436 }1461 }
1437}1462}
14381463
...@@ -1442,11 +1467,13 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {...@@ -1442,11 +1467,13 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
1442 }1467 }
1443 const mod = wasm.base.options.module.?;1468 const mod = wasm.base.options.module.?;
1444 const decl = mod.declPtr(decl_index);1469 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);
1446 wasm.symbols_free_list.append(wasm.base.allocator, atom.sym_index) catch {};1472 wasm.symbols_free_list.append(wasm.base.allocator, atom.sym_index) catch {};
1447 _ = wasm.decls.remove(decl_index);1473 _ = wasm.decls.remove(decl_index);
1448 wasm.symbols.items[atom.sym_index].tag = .dead;1474 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);
1450 const local_symbol = &wasm.symbols.items[local_atom.sym_index];1477 const local_symbol = &wasm.symbols.items[local_atom.sym_index];
1451 local_symbol.tag = .dead; // also for any local symbol1478 local_symbol.tag = .dead; // also for any local symbol
1452 wasm.symbols_free_list.append(wasm.base.allocator, local_atom.sym_index) catch {};1479 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 {...@@ -1460,12 +1487,20 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
1460 _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc());1487 _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc());
1461 _ = wasm.symbol_atom.remove(atom.symbolLoc());1488 _ = wasm.symbol_atom.remove(atom.symbolLoc());
14621489
1463 if (wasm.dwarf) |*dwarf| {1490 // if (wasm.dwarf) |*dwarf| {
1464 dwarf.freeDecl(decl);1491 // dwarf.freeDecl(decl_index);
1465 dwarf.freeAtom(&atom.dbg_info_atom);1492 // }
1466 }
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 }
1469}1504}
14701505
1471/// Appends a new entry to the indirect function table1506/// Appends a new entry to the indirect function table
...@@ -1587,7 +1622,8 @@ const Kind = union(enum) {...@@ -1587,7 +1622,8 @@ const Kind = union(enum) {
1587};1622};
15881623
1589/// Parses an Atom and inserts its metadata into the corresponding sections.1624/// 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);
1591 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);1627 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
1592 const final_index: u32 = switch (kind) {1628 const final_index: u32 = switch (kind) {
1593 .function => |fn_data| result: {1629 .function => |fn_data| result: {
...@@ -1662,18 +1698,20 @@ fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void {...@@ -1662,18 +1698,20 @@ fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void {
1662 const segment: *Segment = &wasm.segments.items[final_index];1698 const segment: *Segment = &wasm.segments.items[final_index];
1663 segment.alignment = std.math.max(segment.alignment, atom.alignment);1699 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);
1666}1702}
16671703
1668/// From a given index, append the given `Atom` at the back of the linked list.1704/// From a given index, append the given `Atom` at the back of the linked list.
1669/// Simply inserts it into the map of atoms when it doesn't exist yet.1705/// Simply inserts it into the map of atoms when it doesn't exist yet.
1670pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom: *Atom) !void {1706pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {
1671 if (wasm.atoms.getPtr(index)) |last| {1707 const atom = wasm.getAtomPtr(atom_index);
1672 last.*.next = atom;1708 if (wasm.atoms.getPtr(index)) |last_index_ptr| {
1673 atom.prev = last.*;1709 const last = wasm.getAtomPtr(last_index_ptr.*);
1674 last.* = atom;1710 last.*.next = atom_index;
1711 atom.prev = last_index_ptr.*;
1712 last_index_ptr.* = atom_index;
1675 } else {1713 } else {
1676 try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom);1714 try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom_index);
1677 }1715 }
1678}1716}
16791717
...@@ -1683,16 +1721,17 @@ fn allocateDebugAtoms(wasm: *Wasm) !void {...@@ -1683,16 +1721,17 @@ fn allocateDebugAtoms(wasm: *Wasm) !void {
1683 if (wasm.dwarf == null) return;1721 if (wasm.dwarf == null) return;
16841722
1685 const allocAtom = struct {1723 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 {
1687 const index = maybe_index.* orelse idx: {1725 const index = maybe_index.* orelse idx: {
1688 const index = @intCast(u32, bin.segments.items.len);1726 const index = @intCast(u32, bin.segments.items.len);
1689 try bin.appendDummySegment();1727 try bin.appendDummySegment();
1690 maybe_index.* = index;1728 maybe_index.* = index;
1691 break :idx index;1729 break :idx index;
1692 };1730 };
1731 const atom = bin.getAtomPtr(atom_index);
1693 atom.size = @intCast(u32, atom.code.items.len);1732 atom.size = @intCast(u32, atom.code.items.len);
1694 bin.symbols.items[atom.sym_index].index = index;1733 bin.symbols.items[atom.sym_index].index = index;
1695 try bin.appendAtomAtIndex(index, atom);1734 try bin.appendAtomAtIndex(index, atom_index);
1696 }1735 }
1697 }.f;1736 }.f;
16981737
...@@ -1714,15 +1753,16 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -1714,15 +1753,16 @@ fn allocateAtoms(wasm: *Wasm) !void {
1714 var it = wasm.atoms.iterator();1753 var it = wasm.atoms.iterator();
1715 while (it.next()) |entry| {1754 while (it.next()) |entry| {
1716 const segment = &wasm.segments.items[entry.key_ptr.*];1755 const segment = &wasm.segments.items[entry.key_ptr.*];
1717 var atom: *Atom = entry.value_ptr.*.getFirst();1756 var atom_index = entry.value_ptr.*;
1718 var offset: u32 = 0;1757 var offset: u32 = 0;
1719 while (true) {1758 while (true) {
1759 const atom = wasm.getAtomPtr(atom_index);
1720 const symbol_loc = atom.symbolLoc();1760 const symbol_loc = atom.symbolLoc();
1721 if (wasm.code_section_index) |index| {1761 if (wasm.code_section_index) |index| {
1722 if (index == entry.key_ptr.*) {1762 if (index == entry.key_ptr.*) {
1723 if (!wasm.resolved_symbols.contains(symbol_loc)) {1763 if (!wasm.resolved_symbols.contains(symbol_loc)) {
1724 // only allocate resolved function body's.1764 // only allocate resolved function body's.
1725 atom = atom.next orelse break;1765 atom_index = atom.prev orelse break;
1726 continue;1766 continue;
1727 }1767 }
1728 }1768 }
...@@ -1736,8 +1776,7 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -1736,8 +1776,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
1736 atom.size,1776 atom.size,
1737 });1777 });
1738 offset += atom.size;1778 offset += atom.size;
1739 try wasm.symbol_atom.put(wasm.base.allocator, symbol_loc, atom); // Update atom pointers1779 atom_index = atom.prev orelse break;
1740 atom = atom.next orelse break;
1741 }1780 }
1742 segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);1781 segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);
1743 }1782 }
...@@ -1871,8 +1910,8 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {...@@ -1871,8 +1910,8 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
1871 symbol.index = func_index;1910 symbol.index = func_index;
18721911
1873 // create the atom that will be output into the final binary1912 // create the atom that will be output into the final binary
1874 const atom = try wasm.base.allocator.create(Atom);1913 const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
1875 errdefer wasm.base.allocator.destroy(atom);1914 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
1876 atom.* = .{1915 atom.* = .{
1877 .size = @intCast(u32, function_body.items.len),1916 .size = @intCast(u32, function_body.items.len),
1878 .offset = 0,1917 .offset = 0,
...@@ -1882,15 +1921,14 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {...@@ -1882,15 +1921,14 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
1882 .next = null,1921 .next = null,
1883 .prev = null,1922 .prev = null,
1884 .code = function_body.moveToUnmanaged(),1923 .code = function_body.moveToUnmanaged(),
1885 .dbg_info_atom = undefined,
1886 };1924 };
1887 try wasm.managed_atoms.append(wasm.base.allocator, atom);1925 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);
1888 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom);1926 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
1889 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
18901927
1891 // `allocateAtoms` has already been called, set the atom's offset manually.1928 // `allocateAtoms` has already been called, set the atom's offset manually.
1892 // This is fine to do manually as we insert the atom at the very end.1929 // 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;
1894}1932}
18951933
1896fn setupImports(wasm: *Wasm) !void {1934fn setupImports(wasm: *Wasm) !void {
...@@ -2093,7 +2131,8 @@ fn setupExports(wasm: *Wasm) !void {...@@ -2093,7 +2131,8 @@ fn setupExports(wasm: *Wasm) !void {
2093 break :blk try wasm.string_table.put(wasm.base.allocator, sym_name);2131 break :blk try wasm.string_table.put(wasm.base.allocator, sym_name);
2094 };2132 };
2095 const exp: types.Export = if (symbol.tag == .data) exp: {2133 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);
2097 const va = atom.getVA(wasm, symbol);2136 const va = atom.getVA(wasm, symbol);
2098 const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len);2137 const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len);
2099 try wasm.wasm_globals.append(wasm.base.allocator, .{2138 try wasm.wasm_globals.append(wasm.base.allocator, .{
...@@ -2198,7 +2237,8 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2198,7 +2237,8 @@ fn setupMemory(wasm: *Wasm) !void {
2198 const segment_index = wasm.data_segments.get(".synthetic").?;2237 const segment_index = wasm.data_segments.get(".synthetic").?;
2199 const segment = &wasm.segments.items[segment_index];2238 const segment = &wasm.segments.items[segment_index];
2200 segment.offset = 0; // for simplicity we store the entire VA into atom's offset.2239 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);
2202 atom.offset = @intCast(u32, mem.alignForwardGeneric(u64, memory_ptr, heap_alignment));2242 atom.offset = @intCast(u32, mem.alignForwardGeneric(u64, memory_ptr, heap_alignment));
2203 }2243 }
22042244
...@@ -2231,7 +2271,8 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2231,7 +2271,8 @@ fn setupMemory(wasm: *Wasm) !void {
2231 const segment_index = wasm.data_segments.get(".synthetic").?;2271 const segment_index = wasm.data_segments.get(".synthetic").?;
2232 const segment = &wasm.segments.items[segment_index];2272 const segment = &wasm.segments.items[segment_index];
2233 segment.offset = 0;2273 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);
2235 atom.offset = @intCast(u32, memory_ptr);2276 atom.offset = @intCast(u32, memory_ptr);
2236 }2277 }
22372278
...@@ -2357,15 +2398,14 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {...@@ -2357,15 +2398,14 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
2357 // and then return said symbol's index. The final table will be populated2398 // and then return said symbol's index. The final table will be populated
2358 // during `flush` when we know all possible error names.2399 // during `flush` when we know all possible error names.
23592400
2360 // As sym_index '0' is reserved, we use it for our stack pointer symbol2401 const atom_index = try wasm.createAtom();
2361 const symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: {2402 const atom = wasm.getAtomPtr(atom_index);
2362 const index = @intCast(u32, wasm.symbols.items.len);2403 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
2363 _ = try wasm.symbols.addOne(wasm.base.allocator);2404 atom.alignment = slice_ty.abiAlignment(wasm.base.options.target);
2364 break :blk index;2405 const sym_index = atom.sym_index;
2365 };
23662406
2367 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table");2407 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];
2369 symbol.* = .{2409 symbol.* = .{
2370 .name = sym_name,2410 .name = sym_name,
2371 .tag = .data,2411 .tag = .data,
...@@ -2374,20 +2414,11 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {...@@ -2374,20 +2414,11 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
2374 };2414 };
2375 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);2415 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);2419 log.debug("Error name table was created with symbol index: ({d})", .{sym_index});
2380 atom.* = Atom.empty;2420 wasm.error_table_symbol = sym_index;
2381 atom.sym_index = symbol_index;2421 return sym_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;
2391}2422}
23922423
2393/// Populates the error name table, when `error_table_symbol` is not null.2424/// Populates the error name table, when `error_table_symbol` is not null.
...@@ -2396,22 +2427,17 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {...@@ -2396,22 +2427,17 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
2396/// The table is what is being pointed to within the runtime bodies that are generated.2427/// The table is what is being pointed to within the runtime bodies that are generated.
2397fn populateErrorNameTable(wasm: *Wasm) !void {2428fn populateErrorNameTable(wasm: *Wasm) !void {
2398 const symbol_index = wasm.error_table_symbol orelse return;2429 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
2400 // Rather than creating a symbol for each individual error name,2433 // Rather than creating a symbol for each individual error name,
2401 // we create a symbol for the entire region of error names. We then calculate2434 // we create a symbol for the entire region of error names. We then calculate
2402 // the pointers into the list using addends which are appended to the relocation.2435 // the pointers into the list using addends which are appended to the relocation.
2403 const names_atom = try wasm.base.allocator.create(Atom);2436 const names_atom_index = try wasm.createAtom();
2404 names_atom.* = Atom.empty;2437 const names_atom = wasm.getAtomPtr(names_atom_index);
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;
2412 names_atom.alignment = 1;2438 names_atom.alignment = 1;
2413 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names");2439 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];
2415 names_symbol.* = .{2441 names_symbol.* = .{
2416 .name = sym_name,2442 .name = sym_name,
2417 .tag = .data,2443 .tag = .data,
...@@ -2435,7 +2461,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {...@@ -2435,7 +2461,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
2435 try atom.code.writer(wasm.base.allocator).writeIntLittle(u32, len - 1);2461 try atom.code.writer(wasm.base.allocator).writeIntLittle(u32, len - 1);
2436 // create relocation to the error name2462 // create relocation to the error name
2437 try atom.relocs.append(wasm.base.allocator, .{2463 try atom.relocs.append(wasm.base.allocator, .{
2438 .index = names_symbol_index,2464 .index = names_atom.sym_index,
2439 .relocation_type = .R_WASM_MEMORY_ADDR_I32,2465 .relocation_type = .R_WASM_MEMORY_ADDR_I32,
2440 .offset = offset,2466 .offset = offset,
2441 .addend = @intCast(i32, addend),2467 .addend = @intCast(i32, addend),
...@@ -2454,61 +2480,53 @@ fn populateErrorNameTable(wasm: *Wasm) !void {...@@ -2454,61 +2480,53 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
24542480
2455 const name_loc = names_atom.symbolLoc();2481 const name_loc = names_atom.symbolLoc();
2456 try wasm.resolved_symbols.put(wasm.base.allocator, name_loc, {});2482 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
2459 // link the atoms with the rest of the binary so they can be allocated2485 // link the atoms with the rest of the binary so they can be allocated
2460 // and relocations will be performed.2486 // and relocations will be performed.
2461 try wasm.parseAtom(atom, .{ .data = .read_only });2487 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2462 try wasm.parseAtom(names_atom, .{ .data = .read_only });2488 try wasm.parseAtom(names_atom_index, .{ .data = .read_only });
2463}2489}
24642490
2465/// From a given index variable, creates a new debug section.2491/// From a given index variable, creates a new debug section.
2466/// This initializes the index, appends a new segment,2492/// This initializes the index, appends a new segment,
2467/// and finally, creates a managed `Atom`.2493/// 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 {
2469 const new_index = @intCast(u32, wasm.segments.items.len);2495 const new_index = @intCast(u32, wasm.segments.items.len);
2470 index.* = new_index;2496 index.* = new_index;
2471 try wasm.appendDummySegment();2497 try wasm.appendDummySegment();
24722498
2473 const sym_index = wasm.symbols_free_list.popOrNull() orelse idx: {2499 const atom_index = try wasm.createAtom();
2474 const tmp_index = @intCast(u32, wasm.symbols.items.len);2500 const atom = wasm.getAtomPtr(atom_index);
2475 _ = try wasm.symbols.addOne(wasm.base.allocator);2501 wasm.symbols.items[atom.sym_index] = .{
2476 break :idx tmp_index;
2477 };
2478 wasm.symbols.items[sym_index] = .{
2479 .tag = .section,2502 .tag = .section,
2480 .name = try wasm.string_table.put(wasm.base.allocator, name),2503 .name = try wasm.string_table.put(wasm.base.allocator, name),
2481 .index = 0,2504 .index = 0,
2482 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),2505 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
2483 };2506 };
24842507
2485 const atom = try wasm.base.allocator.create(Atom);
2486 atom.* = Atom.empty;
2487 atom.alignment = 1; // debug sections are always 1-byte-aligned2508 atom.alignment = 1; // debug sections are always 1-byte-aligned
2488 atom.sym_index = sym_index;2509 return atom_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;
2492}2510}
24932511
2494fn resetState(wasm: *Wasm) void {2512fn resetState(wasm: *Wasm) void {
2495 for (wasm.segment_info.values()) |segment_info| {2513 for (wasm.segment_info.values()) |segment_info| {
2496 wasm.base.allocator.free(segment_info.name);2514 wasm.base.allocator.free(segment_info.name);
2497 }2515 }
2498 if (wasm.base.options.module) |mod| {2516
2499 var decl_it = wasm.decls.keyIterator();2517 var atom_it = wasm.decls.valueIterator();
2500 while (decl_it.next()) |decl_index_ptr| {2518 while (atom_it.next()) |atom_index| {
2501 const decl = mod.declPtr(decl_index_ptr.*);2519 const atom = wasm.getAtomPtr(atom_index.*);
2502 const atom = &decl.link.wasm;2520 atom.next = null;
2503 atom.next = null;2521 atom.prev = null;
2504 atom.prev = null;2522
25052523 for (atom.locals.items) |local_atom_index| {
2506 for (atom.locals.items) |*local_atom| {2524 const local_atom = wasm.getAtomPtr(local_atom_index);
2507 local_atom.next = null;2525 local_atom.next = null;
2508 local_atom.prev = null;2526 local_atom.prev = null;
2509 }
2510 }2527 }
2511 }2528 }
2529
2512 wasm.functions.clearRetainingCapacity();2530 wasm.functions.clearRetainingCapacity();
2513 wasm.exports.clearRetainingCapacity();2531 wasm.exports.clearRetainingCapacity();
2514 wasm.segments.clearRetainingCapacity();2532 wasm.segments.clearRetainingCapacity();
...@@ -2805,28 +2823,29 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2805,28 +2823,29 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2805 try wasm.setupStart();2823 try wasm.setupStart();
2806 try wasm.setupImports();2824 try wasm.setupImports();
2807 if (wasm.base.options.module) |mod| {2825 if (wasm.base.options.module) |mod| {
2808 var decl_it = wasm.decls.keyIterator();2826 var decl_it = wasm.decls.iterator();
2809 while (decl_it.next()) |decl_index_ptr| {2827 while (decl_it.next()) |entry| {
2810 const decl = mod.declPtr(decl_index_ptr.*);2828 const decl = mod.declPtr(entry.key_ptr.*);
2811 if (decl.isExtern()) continue;2829 if (decl.isExtern()) continue;
2812 const atom = &decl.*.link.wasm;2830 const atom_index = entry.value_ptr.*;
2813 if (decl.ty.zigTypeTag() == .Fn) {2831 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.? });
2815 } else if (decl.getVariable()) |variable| {2833 } else if (decl.getVariable()) |variable| {
2816 if (!variable.is_mutable) {2834 if (!variable.is_mutable) {
2817 try wasm.parseAtom(atom, .{ .data = .read_only });2835 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2818 } else if (variable.init.isUndefDeep()) {2836 } else if (variable.init.isUndefDeep()) {
2819 try wasm.parseAtom(atom, .{ .data = .uninitialized });2837 try wasm.parseAtom(atom_index, .{ .data = .uninitialized });
2820 } else {2838 } else {
2821 try wasm.parseAtom(atom, .{ .data = .initialized });2839 try wasm.parseAtom(atom_index, .{ .data = .initialized });
2822 }2840 }
2823 } else {2841 } else {
2824 try wasm.parseAtom(atom, .{ .data = .read_only });2842 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2825 }2843 }
28262844
2827 // also parse atoms for a decl's locals2845 // also parse atoms for a decl's locals
2828 for (atom.locals.items) |*local_atom| {2846 const atom = wasm.getAtomPtr(atom_index);
2829 try wasm.parseAtom(local_atom, .{ .data = .read_only });2847 for (atom.locals.items) |local_atom_index| {
2848 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
2830 }2849 }
2831 }2850 }
28322851
...@@ -3071,20 +3090,22 @@ fn writeToFile(...@@ -3071,20 +3090,22 @@ fn writeToFile(
3071 var code_section_size: u32 = 0;3090 var code_section_size: u32 = 0;
3072 if (wasm.code_section_index) |code_index| {3091 if (wasm.code_section_index) |code_index| {
3073 const header_offset = try reserveVecSectionHeader(&binary_bytes);3092 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
3076 // The code section must be sorted in line with the function order.3095 // The code section must be sorted in line with the function order.
3077 var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count());3096 var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count());
3078 defer sorted_atoms.deinit();3097 defer sorted_atoms.deinit();
30793098
3080 while (true) {3099 while (true) {
3100 var atom = wasm.getAtomPtr(atom_index);
3081 if (wasm.resolved_symbols.contains(atom.symbolLoc())) {3101 if (wasm.resolved_symbols.contains(atom.symbolLoc())) {
3082 if (!is_obj) {3102 if (!is_obj) {
3083 atom.resolveRelocs(wasm);3103 atom.resolveRelocs(wasm);
3084 }3104 }
3085 sorted_atoms.appendAssumeCapacity(atom);3105 sorted_atoms.appendAssumeCapacity(atom);
3086 }3106 }
3087 atom = atom.next orelse break;3107 // atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
3108 atom_index = atom.prev orelse break;
3088 }3109 }
30893110
3090 const atom_sort_fn = struct {3111 const atom_sort_fn = struct {
...@@ -3124,11 +3145,11 @@ fn writeToFile(...@@ -3124,11 +3145,11 @@ fn writeToFile(
3124 // do not output 'bss' section unless we import memory and therefore3145 // do not output 'bss' section unless we import memory and therefore
3125 // want to guarantee the data is zero initialized3146 // want to guarantee the data is zero initialized
3126 if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;3147 if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;
3127 const atom_index = entry.value_ptr.*;3148 const segment_index = entry.value_ptr.*;
3128 const segment = wasm.segments.items[atom_index];3149 const segment = wasm.segments.items[segment_index];
3129 if (segment.size == 0) continue; // do not emit empty segments3150 if (segment.size == 0) continue; // do not emit empty segments
3130 segment_count += 1;3151 segment_count += 1;
3131 var atom: *Atom = wasm.atoms.getPtr(atom_index).?.*.getFirst();3152 var atom_index = wasm.atoms.get(segment_index).?;
31323153
3133 // flag and index to memory section (currently, there can only be 1 memory section in wasm)3154 // flag and index to memory section (currently, there can only be 1 memory section in wasm)
3134 try leb.writeULEB128(binary_writer, @as(u32, 0));3155 try leb.writeULEB128(binary_writer, @as(u32, 0));
...@@ -3139,6 +3160,7 @@ fn writeToFile(...@@ -3139,6 +3160,7 @@ fn writeToFile(
3139 // fill in the offset table and the data segments3160 // fill in the offset table and the data segments
3140 var current_offset: u32 = 0;3161 var current_offset: u32 = 0;
3141 while (true) {3162 while (true) {
3163 const atom = wasm.getAtomPtr(atom_index);
3142 if (!is_obj) {3164 if (!is_obj) {
3143 atom.resolveRelocs(wasm);3165 atom.resolveRelocs(wasm);
3144 }3166 }
...@@ -3154,8 +3176,8 @@ fn writeToFile(...@@ -3154,8 +3176,8 @@ fn writeToFile(
3154 try binary_writer.writeAll(atom.code.items);3176 try binary_writer.writeAll(atom.code.items);
31553177
3156 current_offset += atom.size;3178 current_offset += atom.size;
3157 if (atom.next) |next| {3179 if (atom.prev) |prev| {
3158 atom = next;3180 atom_index = prev;
3159 } else {3181 } else {
3160 // also pad with zeroes when last atom to ensure3182 // also pad with zeroes when last atom to ensure
3161 // segments are aligned.3183 // segments are aligned.
...@@ -3197,15 +3219,15 @@ fn writeToFile(...@@ -3197,15 +3219,15 @@ fn writeToFile(
3197 }3219 }
31983220
3199 if (!wasm.base.options.strip) {3221 if (!wasm.base.options.strip) {
3200 if (wasm.dwarf) |*dwarf| {3222 // if (wasm.dwarf) |*dwarf| {
3201 const mod = wasm.base.options.module.?;3223 // const mod = wasm.base.options.module.?;
3202 try dwarf.writeDbgAbbrev();3224 // try dwarf.writeDbgAbbrev();
3203 // for debug info and ranges, the address is always 0,3225 // // for debug info and ranges, the address is always 0,
3204 // as locations are always offsets relative to 'code' section.3226 // // as locations are always offsets relative to 'code' section.
3205 try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);3227 // try dwarf.writeDbgInfoHeader(mod, 0, code_section_size);
3206 try dwarf.writeDbgAranges(0, code_section_size);3228 // try dwarf.writeDbgAranges(0, code_section_size);
3207 try dwarf.writeDbgLineHeader();3229 // try dwarf.writeDbgLineHeader();
3208 }3230 // }
32093231
3210 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);3232 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);
3211 defer debug_bytes.deinit();3233 defer debug_bytes.deinit();
...@@ -3228,11 +3250,11 @@ fn writeToFile(...@@ -3228,11 +3250,11 @@ fn writeToFile(
32283250
3229 for (debug_sections) |item| {3251 for (debug_sections) |item| {
3230 if (item.index) |index| {3252 if (item.index) |index| {
3231 var atom = wasm.atoms.get(index).?.getFirst();3253 var atom = wasm.getAtomPtr(wasm.atoms.get(index).?);
3232 while (true) {3254 while (true) {
3233 atom.resolveRelocs(wasm);3255 atom.resolveRelocs(wasm);
3234 try debug_bytes.appendSlice(atom.code.items);3256 try debug_bytes.appendSlice(atom.code.items);
3235 atom = atom.next orelse break;3257 atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
3236 }3258 }
3237 try emitDebugSection(&binary_bytes, debug_bytes.items, item.name);3259 try emitDebugSection(&binary_bytes, debug_bytes.items, item.name);
3238 debug_bytes.clearRetainingCapacity();3260 debug_bytes.clearRetainingCapacity();
...@@ -3964,7 +3986,8 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:...@@ -3964,7 +3986,8 @@ fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table:
39643986
3965 if (symbol.isDefined()) {3987 if (symbol.isDefined()) {
3966 try leb.writeULEB128(writer, symbol.index);3988 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);
3968 try leb.writeULEB128(writer, @as(u32, atom.offset));3991 try leb.writeULEB128(writer, @as(u32, atom.offset));
3969 try leb.writeULEB128(writer, @as(u32, atom.size));3992 try leb.writeULEB128(writer, @as(u32, atom.size));
3970 }3993 }
...@@ -4042,7 +4065,7 @@ fn emitCodeRelocations(...@@ -4042,7 +4065,7 @@ fn emitCodeRelocations(
4042 const reloc_start = binary_bytes.items.len;4065 const reloc_start = binary_bytes.items.len;
40434066
4044 var count: u32 = 0;4067 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).?);
4046 // for each atom, we calculate the uleb size and append that4069 // for each atom, we calculate the uleb size and append that
4047 var size_offset: u32 = 5; // account for code section size leb1284070 var size_offset: u32 = 5; // account for code section size leb128
4048 while (true) {4071 while (true) {
...@@ -4060,7 +4083,7 @@ fn emitCodeRelocations(...@@ -4060,7 +4083,7 @@ fn emitCodeRelocations(
4060 }4083 }
4061 log.debug("Emit relocation: {}", .{relocation});4084 log.debug("Emit relocation: {}", .{relocation});
4062 }4085 }
4063 atom = atom.next orelse break;4086 atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
4064 }4087 }
4065 if (count == 0) return;4088 if (count == 0) return;
4066 var buf: [5]u8 = undefined;4089 var buf: [5]u8 = undefined;
...@@ -4091,7 +4114,7 @@ fn emitDataRelocations(...@@ -4091,7 +4114,7 @@ fn emitDataRelocations(
4091 // for each atom, we calculate the uleb size and append that4114 // for each atom, we calculate the uleb size and append that
4092 var size_offset: u32 = 5; // account for code section size leb1284115 var size_offset: u32 = 5; // account for code section size leb128
4093 for (wasm.data_segments.values()) |segment_index| {4116 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).?);
4095 while (true) {4118 while (true) {
4096 size_offset += getULEB128Size(atom.size);4119 size_offset += getULEB128Size(atom.size);
4097 for (atom.relocs.items) |relocation| {4120 for (atom.relocs.items) |relocation| {
...@@ -4110,7 +4133,7 @@ fn emitDataRelocations(...@@ -4110,7 +4133,7 @@ fn emitDataRelocations(
4110 }4133 }
4111 log.debug("Emit relocation: {}", .{relocation});4134 log.debug("Emit relocation: {}", .{relocation});
4112 }4135 }
4113 atom = atom.next orelse break;4136 atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;
4114 }4137 }
4115 }4138 }
4116 if (count == 0) return;4139 if (count == 0) return;
src/link/Wasm/Atom.zig+19-28
...@@ -4,7 +4,6 @@ const std = @import("std");...@@ -4,7 +4,6 @@ const std = @import("std");
4const types = @import("types.zig");4const types = @import("types.zig");
5const Wasm = @import("../Wasm.zig");5const Wasm = @import("../Wasm.zig");
6const Symbol = @import("Symbol.zig");6const Symbol = @import("Symbol.zig");
7const Dwarf = @import("../Dwarf.zig");
87
9const leb = std.leb;8const leb = std.leb;
10const log = std.log.scoped(.link);9const log = std.log.scoped(.link);
...@@ -30,17 +29,17 @@ file: ?u16,...@@ -30,17 +29,17 @@ file: ?u16,
3029
31/// Next atom in relation to this atom.30/// Next atom in relation to this atom.
32/// When null, this atom is the last atom31/// When null, this atom is the last atom
33next: ?*Atom,32next: ?Atom.Index,
34/// Previous atom in relation to this atom.33/// Previous atom in relation to this atom.
35/// is null when this atom is the first in its order34/// is null when this atom is the first in its order
36prev: ?*Atom,35prev: ?Atom.Index,
3736
38/// Contains atoms local to a decl, all managed by this `Atom`.37/// Contains atoms local to a decl, all managed by this `Atom`.
39/// When the parent atom is being freed, it will also do so for all local atoms.38/// 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.41/// Alias to an unsigned 32-bit integer
43dbg_info_atom: Dwarf.Atom,42pub const Index = u32;
4443
45/// Represents a default empty wasm `Atom`44/// Represents a default empty wasm `Atom`
46pub const empty: Atom = .{45pub const empty: Atom = .{
...@@ -51,18 +50,15 @@ pub const empty: Atom = .{...@@ -51,18 +50,15 @@ pub const empty: Atom = .{
51 .prev = null,50 .prev = null,
52 .size = 0,51 .size = 0,
53 .sym_index = 0,52 .sym_index = 0,
54 .dbg_info_atom = undefined,
55};53};
5654
57/// Frees all resources owned by this `Atom`.55/// 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;
59 atom.relocs.deinit(gpa);58 atom.relocs.deinit(gpa);
60 atom.code.deinit(gpa);59 atom.code.deinit(gpa);
61
62 for (atom.locals.items) |*local| {
63 local.deinit(gpa);
64 }
65 atom.locals.deinit(gpa);60 atom.locals.deinit(gpa);
61 atom.* = undefined;
66}62}
6763
68/// Sets the length of relocations and code to '0',64/// 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...@@ -83,24 +79,11 @@ pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptio
83 });79 });
84}80}
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
93/// Returns the location of the symbol that represents this `Atom`82/// Returns the location of the symbol that represents this `Atom`
94pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {83pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
95 return .{ .file = atom.file, .index = atom.sym_index };84 return .{ .file = atom.file, .index = atom.sym_index };
96}85}
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
104pub fn getSymbolIndex(atom: Atom) ?u32 {87pub fn getSymbolIndex(atom: Atom) ?u32 {
105 if (atom.sym_index == 0) return null;88 if (atom.sym_index == 0) return null;
106 return atom.sym_index;89 return atom.sym_index;
...@@ -203,20 +186,28 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa...@@ -203,20 +186,28 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
203 if (symbol.isUndefined()) {186 if (symbol.isUndefined()) {
204 return 0;187 return 0;
205 }188 }
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);
207 const va = @intCast(i32, target_atom.getVA(wasm_bin, symbol));196 const va = @intCast(i32, target_atom.getVA(wasm_bin, symbol));
208 return @intCast(u32, va + relocation.addend);197 return @intCast(u32, va + relocation.addend);
209 },198 },
210 .R_WASM_EVENT_INDEX_LEB => return symbol.index,199 .R_WASM_EVENT_INDEX_LEB => return symbol.index,
211 .R_WASM_SECTION_OFFSET_I32 => {200 .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);
213 const rel_value = @intCast(i32, target_atom.offset) + relocation.addend;203 const rel_value = @intCast(i32, target_atom.offset) + relocation.addend;
214 return @intCast(u32, rel_value);204 return @intCast(u32, rel_value);
215 },205 },
216 .R_WASM_FUNCTION_OFFSET_I32 => {206 .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 {
218 return @bitCast(u32, @as(i32, -1));208 return @bitCast(u32, @as(i32, -1));
219 };209 };
210 const target_atom = wasm_bin.getAtom(target_atom_index);
220 const offset: u32 = 11 + Wasm.getULEB128Size(target_atom.size); // Header (11 bytes fixed-size) + body size (leb-encoded)211 const offset: u32 = 11 + Wasm.getULEB128Size(target_atom.size); // Header (11 bytes fixed-size) + body size (leb-encoded)
221 const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend;212 const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend;
222 return @intCast(u32, rel_value);213 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...@@ -901,14 +901,9 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
901 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.901 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
902 };902 };
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);
905 atom.* = Atom.empty;906 atom.* = Atom.empty;
906 errdefer {
907 atom.deinit(gpa);
908 gpa.destroy(atom);
909 }
910
911 try wasm_bin.managed_atoms.append(gpa, atom);
912 atom.file = object_index;907 atom.file = object_index;
913 atom.size = relocatable_data.size;908 atom.size = relocatable_data.size;
914 atom.alignment = relocatable_data.getAlignment(object);909 atom.alignment = relocatable_data.getAlignment(object);
...@@ -938,12 +933,12 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b...@@ -938,12 +933,12 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
938 .index = relocatable_data.getIndex(),933 .index = relocatable_data.getIndex(),
939 })) |symbols| {934 })) |symbols| {
940 atom.sym_index = symbols.pop();935 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
943 // symbols referencing the same atom will be added as alias938 // symbols referencing the same atom will be added as alias
944 // or as 'parent' when they are global.939 // or as 'parent' when they are global.
945 while (symbols.popOrNull()) |idx| {940 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);
947 const alias_symbol = object.symtable[idx];942 const alias_symbol = object.symtable[idx];
948 if (alias_symbol.isGlobal()) {943 if (alias_symbol.isGlobal()) {
949 atom.sym_index = idx;944 atom.sym_index = idx;
...@@ -956,7 +951,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b...@@ -956,7 +951,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
956 segment.alignment = std.math.max(segment.alignment, atom.alignment);951 segment.alignment = std.math.max(segment.alignment, atom.alignment);
957 }952 }
958953
959 try wasm_bin.appendAtomAtIndex(final_index, atom);954 try wasm_bin.appendAtomAtIndex(final_index, atom_index);
960 log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index });955 log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index });
961 }956 }
962}957}
test/link/wasm/export-data/build.zig+2-2
...@@ -25,8 +25,8 @@ pub fn build(b: *std.Build) void {...@@ -25,8 +25,8 @@ pub fn build(b: *std.Build) void {
25 check_lib.checkNext("type i32");25 check_lib.checkNext("type i32");
26 check_lib.checkNext("mutable false");26 check_lib.checkNext("mutable false");
27 check_lib.checkNext("i32.const {bar_address}");27 check_lib.checkNext("i32.const {bar_address}");
28 check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 0 } });28 check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 4 } });
29 check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 4 } });29 check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 0 } });
3030
31 check_lib.checkStart("Section export");31 check_lib.checkStart("Section export");
32 check_lib.checkNext("entries 3");32 check_lib.checkNext("entries 3");