authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-01-28 22:33:56+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-28 22:33:56+01:00
log5a67ae506a381aa0494b4b066a8c54ba7ed9fc31
treec262a934444ee566af839d3a002b97e21690baa0
parent4c116841840bfa7f0068bef23984dd832da8a54d
parenta8987291390d80ad9e2bb45ba225313a108eed0b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14472 from ziglang/alloc-decls

self-hosted: remove allocateDeclIndexes from the linker API

18 files changed, 688 insertions(+), 777 deletions(-)

src/Module.zig-20
...@@ -4585,7 +4585,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4585,7 +4585,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4585 // We don't fully codegen the decl until later, but we do need to reserve a global4585 // We don't fully codegen the decl until later, but we do need to reserve a global
4586 // offset table index for it. This allows us to codegen decls out of dependency4586 // offset table index for it. This allows us to codegen decls out of dependency
4587 // order, increasing how many computations can be done in parallel.4587 // order, increasing how many computations can be done in parallel.
4588 try mod.comp.bin_file.allocateDeclIndexes(decl_index);
4589 try mod.comp.work_queue.writeItem(.{ .codegen_func = func });4588 try mod.comp.work_queue.writeItem(.{ .codegen_func = func });
4590 if (type_changed and mod.emit_h != null) {4589 if (type_changed and mod.emit_h != null) {
4591 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });4590 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
...@@ -4697,7 +4696,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4697,7 +4696,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4697 // codegen backend wants full access to the Decl Type.4696 // codegen backend wants full access to the Decl Type.
4698 try sema.resolveTypeFully(decl.ty);4697 try sema.resolveTypeFully(decl.ty);
46994698
4700 try mod.comp.bin_file.allocateDeclIndexes(decl_index);
4701 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });4699 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
47024700
4703 if (type_changed and mod.emit_h != null) {4701 if (type_changed and mod.emit_h != null) {
...@@ -5315,23 +5313,6 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void {...@@ -5315,23 +5313,6 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void {
5315 const decl = mod.declPtr(decl_index);5313 const decl = mod.declPtr(decl_index);
5316 log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name });5314 log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name });
53175315
5318 // TODO: remove `allocateDeclIndexes` and make the API that the linker backends
5319 // are required to notice the first time `updateDecl` happens and keep track
5320 // of it themselves. However they can rely on getting a `freeDecl` call if any
5321 // `updateDecl` or `updateFunc` calls happen. This will allow us to avoid any call
5322 // into the linker backend here, since the linker backend will never have been told
5323 // about the Decl in the first place.
5324 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we
5325 // must call `freeDecl` in the linker backend now.
5326 switch (mod.comp.bin_file.tag) {
5327 .c => {}, // this linker backend has already migrated to the new API
5328 else => if (decl.has_tv) {
5329 if (decl.ty.isFnOrHasRuntimeBits()) {
5330 mod.comp.bin_file.freeDecl(decl_index);
5331 }
5332 },
5333 }
5334
5335 assert(!mod.declIsRoot(decl_index));5316 assert(!mod.declIsRoot(decl_index));
5336 assert(decl.src_namespace.anon_decls.swapRemove(decl_index));5317 assert(decl.src_namespace.anon_decls.swapRemove(decl_index));
53375318
...@@ -5816,7 +5797,6 @@ pub fn initNewAnonDecl(...@@ -5816,7 +5797,6 @@ pub fn initNewAnonDecl(
5816 // the Decl will be garbage collected by the `codegen_decl` task instead of sent5797 // the Decl will be garbage collected by the `codegen_decl` task instead of sent
5817 // to the linker.5798 // to the linker.
5818 if (typed_value.ty.isFnOrHasRuntimeBits()) {5799 if (typed_value.ty.isFnOrHasRuntimeBits()) {
5819 try mod.comp.bin_file.allocateDeclIndexes(new_decl_index);
5820 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl_index });5800 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl_index });
5821 }5801 }
5822}5802}
src/Sema.zig-1
...@@ -7510,7 +7510,6 @@ fn resolveGenericInstantiationType(...@@ -7510,7 +7510,6 @@ fn resolveGenericInstantiationType(
7510 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field7510 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field
7511 // will be populated, ensuring it will have `analyzeBody` called with the ZIR7511 // will be populated, ensuring it will have `analyzeBody` called with the ZIR
7512 // parameters mapped appropriately.7512 // parameters mapped appropriately.
7513 try mod.comp.bin_file.allocateDeclIndexes(new_decl_index);
7514 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });7513 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
7515 return new_func;7514 return new_func;
7516}7515}
src/arch/aarch64/CodeGen.zig+61-109
...@@ -3999,8 +3999,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3999,8 +3999,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3999 const mod = self.bin_file.options.module.?;3999 const mod = self.bin_file.options.module.?;
4000 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);4000 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
4001 const atom_index = switch (self.bin_file.tag) {4001 const atom_index = switch (self.bin_file.tag) {
4002 .macho => owner_decl.link.macho.sym_index,4002 .macho => owner_decl.link.macho.getSymbolIndex().?,
4003 .coff => owner_decl.link.coff.sym_index,4003 .coff => owner_decl.link.coff.getSymbolIndex().?,
4004 else => unreachable, // unsupported target format4004 else => unreachable, // unsupported target format
4005 };4005 };
4006 _ = try self.addInst(.{4006 _ = try self.addInst(.{
...@@ -4302,90 +4302,66 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4302,90 +4302,66 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4302 // on linking.4302 // on linking.
4303 const mod = self.bin_file.options.module.?;4303 const mod = self.bin_file.options.module.?;
4304 if (self.air.value(callee)) |func_value| {4304 if (self.air.value(callee)) |func_value| {
4305 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4305 if (func_value.castTag(.function)) |func_payload| {
4306 if (func_value.castTag(.function)) |func_payload| {4306 const func = func_payload.data;
4307 const func = func_payload.data;4307 const fn_owner_decl = mod.declPtr(func.owner_decl);
4308 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4309 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4310 const fn_owner_decl = mod.declPtr(func.owner_decl);
4311 const got_addr = blk: {
4312 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4313 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
4314 };
43154308
4309 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4310 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4311 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4316 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });4312 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
43174313 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4318 _ = try self.addInst(.{4314 try fn_owner_decl.link.macho.ensureInitialized(macho_file);
4319 .tag = .blr,4315 try self.genSetReg(Type.initTag(.u64), .x30, .{
4320 .data = .{ .reg = .x30 },4316 .linker_load = .{
4317 .type = .got,
4318 .sym_index = fn_owner_decl.link.macho.getSymbolIndex().?,
4319 },
4321 });4320 });
4322 } else if (func_value.castTag(.extern_fn)) |_| {4321 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4323 return self.fail("TODO implement calling extern functions", .{});4322 try fn_owner_decl.link.coff.ensureInitialized(coff_file);
4324 } else {
4325 return self.fail("TODO implement calling bitcasted functions", .{});
4326 }
4327 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4328 if (func_value.castTag(.function)) |func_payload| {
4329 const func = func_payload.data;
4330 const fn_owner_decl = mod.declPtr(func.owner_decl);
4331 try self.genSetReg(Type.initTag(.u64), .x30, .{4323 try self.genSetReg(Type.initTag(.u64), .x30, .{
4332 .linker_load = .{4324 .linker_load = .{
4333 .type = .got,4325 .type = .got,
4334 .sym_index = fn_owner_decl.link.macho.sym_index,4326 .sym_index = fn_owner_decl.link.coff.getSymbolIndex().?,
4335 },4327 },
4336 });4328 });
4337 // blr x304329 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4338 _ = try self.addInst(.{4330 try p9.seeDecl(func.owner_decl);
4339 .tag = .blr,4331 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4340 .data = .{ .reg = .x30 },4332 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4333 const got_addr = p9.bases.data;
4334 const got_index = fn_owner_decl.link.plan9.got_index.?;
4335 const fn_got_addr = got_addr + got_index * ptr_bytes;
4336 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr });
4337 } else unreachable;
4338
4339 _ = try self.addInst(.{
4340 .tag = .blr,
4341 .data = .{ .reg = .x30 },
4342 });
4343 } else if (func_value.castTag(.extern_fn)) |func_payload| {
4344 const extern_fn = func_payload.data;
4345 const decl_name = mod.declPtr(extern_fn.owner_decl).name;
4346 if (extern_fn.lib_name) |lib_name| {
4347 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
4348 decl_name,
4349 lib_name,
4341 });4350 });
4342 } else if (func_value.castTag(.extern_fn)) |func_payload| {4351 }
4343 const extern_fn = func_payload.data;
4344 const decl_name = mod.declPtr(extern_fn.owner_decl).name;
4345 if (extern_fn.lib_name) |lib_name| {
4346 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
4347 decl_name,
4348 lib_name,
4349 });
4350 }
4351 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
43524352
4353 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4354 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4353 _ = try self.addInst(.{4355 _ = try self.addInst(.{
4354 .tag = .call_extern,4356 .tag = .call_extern,
4355 .data = .{4357 .data = .{
4356 .relocation = .{4358 .relocation = .{
4357 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,4359 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?,
4358 .sym_index = sym_index,4360 .sym_index = sym_index,
4359 },4361 },
4360 },4362 },
4361 });4363 });
4362 } else {4364 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4363 return self.fail("TODO implement calling bitcasted functions", .{});
4364 }
4365 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4366 if (func_value.castTag(.function)) |func_payload| {
4367 const func = func_payload.data;
4368 const fn_owner_decl = mod.declPtr(func.owner_decl);
4369 try self.genSetReg(Type.initTag(.u64), .x30, .{
4370 .linker_load = .{
4371 .type = .got,
4372 .sym_index = fn_owner_decl.link.coff.sym_index,
4373 },
4374 });
4375 // blr x30
4376 _ = try self.addInst(.{
4377 .tag = .blr,
4378 .data = .{ .reg = .x30 },
4379 });
4380 } else if (func_value.castTag(.extern_fn)) |func_payload| {
4381 const extern_fn = func_payload.data;
4382 const decl_name = mod.declPtr(extern_fn.owner_decl).name;
4383 if (extern_fn.lib_name) |lib_name| {
4384 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
4385 decl_name,
4386 lib_name,
4387 });
4388 }
4389 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));4365 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4390 try self.genSetReg(Type.initTag(.u64), .x30, .{4366 try self.genSetReg(Type.initTag(.u64), .x30, .{
4391 .linker_load = .{4367 .linker_load = .{
...@@ -4393,35 +4369,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4393,35 +4369,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4393 .sym_index = sym_index,4369 .sym_index = sym_index,
4394 },4370 },
4395 });4371 });
4396 // blr x30
4397 _ = try self.addInst(.{4372 _ = try self.addInst(.{
4398 .tag = .blr,4373 .tag = .blr,
4399 .data = .{ .reg = .x30 },4374 .data = .{ .reg = .x30 },
4400 });4375 });
4401 } else {4376 } else {
4402 return self.fail("TODO implement calling bitcasted functions", .{});
4403 }
4404 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4405 if (func_value.castTag(.function)) |func_payload| {
4406 try p9.seeDecl(func_payload.data.owner_decl);
4407 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4408 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4409 const got_addr = p9.bases.data;
4410 const got_index = mod.declPtr(func_payload.data.owner_decl).link.plan9.got_index.?;
4411 const fn_got_addr = got_addr + got_index * ptr_bytes;
4412
4413 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr });
4414
4415 _ = try self.addInst(.{
4416 .tag = .blr,
4417 .data = .{ .reg = .x30 },
4418 });
4419 } else if (func_value.castTag(.extern_fn)) |_| {
4420 return self.fail("TODO implement calling extern functions", .{});4377 return self.fail("TODO implement calling extern functions", .{});
4421 } else {
4422 return self.fail("TODO implement calling bitcasted functions", .{});
4423 }4378 }
4424 } else unreachable;4379 } else {
4380 return self.fail("TODO implement calling bitcasted functions", .{});
4381 }
4425 } else {4382 } else {
4426 assert(ty.zigTypeTag() == .Pointer);4383 assert(ty.zigTypeTag() == .Pointer);
4427 const mcv = try self.resolveInst(callee);4384 const mcv = try self.resolveInst(callee);
...@@ -5537,8 +5494,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -5537,8 +5494,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
5537 const mod = self.bin_file.options.module.?;5494 const mod = self.bin_file.options.module.?;
5538 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);5495 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5539 const atom_index = switch (self.bin_file.tag) {5496 const atom_index = switch (self.bin_file.tag) {
5540 .macho => owner_decl.link.macho.sym_index,5497 .macho => owner_decl.link.macho.getSymbolIndex().?,
5541 .coff => owner_decl.link.coff.sym_index,5498 .coff => owner_decl.link.coff.getSymbolIndex().?,
5542 else => unreachable, // unsupported target format5499 else => unreachable, // unsupported target format
5543 };5500 };
5544 _ = try self.addInst(.{5501 _ = try self.addInst(.{
...@@ -5651,8 +5608,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5651,8 +5608,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5651 const mod = self.bin_file.options.module.?;5608 const mod = self.bin_file.options.module.?;
5652 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);5609 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5653 const atom_index = switch (self.bin_file.tag) {5610 const atom_index = switch (self.bin_file.tag) {
5654 .macho => owner_decl.link.macho.sym_index,5611 .macho => owner_decl.link.macho.getSymbolIndex().?,
5655 .coff => owner_decl.link.coff.sym_index,5612 .coff => owner_decl.link.coff.getSymbolIndex().?,
5656 else => unreachable, // unsupported target format5613 else => unreachable, // unsupported target format
5657 };5614 };
5658 _ = try self.addInst(.{5615 _ = try self.addInst(.{
...@@ -5845,8 +5802,8 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -5845,8 +5802,8 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
5845 const mod = self.bin_file.options.module.?;5802 const mod = self.bin_file.options.module.?;
5846 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);5803 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5847 const atom_index = switch (self.bin_file.tag) {5804 const atom_index = switch (self.bin_file.tag) {
5848 .macho => owner_decl.link.macho.sym_index,5805 .macho => owner_decl.link.macho.getSymbolIndex().?,
5849 .coff => owner_decl.link.coff.sym_index,5806 .coff => owner_decl.link.coff.getSymbolIndex().?,
5850 else => unreachable, // unsupported target format5807 else => unreachable, // unsupported target format
5851 };5808 };
5852 _ = try self.addInst(.{5809 _ = try self.addInst(.{
...@@ -6165,24 +6122,19 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6165,24 +6122,19 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6165 mod.markDeclAlive(decl);6122 mod.markDeclAlive(decl);
61666123
6167 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6124 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6168 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];6125 try decl.link.elf.ensureInitialized(elf_file);
6169 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;6126 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6170 return MCValue{ .memory = got_addr };6127 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6171 } else if (self.bin_file.cast(link.File.MachO)) |_| {6128 try decl.link.macho.ensureInitialized(macho_file);
6172 // Because MachO is PIE-always-on, we defer memory address resolution until
6173 // the linker has enough info to perform relocations.
6174 assert(decl.link.macho.sym_index != 0);
6175 return MCValue{ .linker_load = .{6129 return MCValue{ .linker_load = .{
6176 .type = .got,6130 .type = .got,
6177 .sym_index = decl.link.macho.sym_index,6131 .sym_index = decl.link.macho.getSymbolIndex().?,
6178 } };6132 } };
6179 } else if (self.bin_file.cast(link.File.Coff)) |_| {6133 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6180 // Because COFF is PIE-always-on, we defer memory address resolution until6134 try decl.link.coff.ensureInitialized(coff_file);
6181 // the linker has enough info to perform relocations.
6182 assert(decl.link.coff.sym_index != 0);
6183 return MCValue{ .linker_load = .{6135 return MCValue{ .linker_load = .{
6184 .type = .got,6136 .type = .got,
6185 .sym_index = decl.link.coff.sym_index,6137 .sym_index = decl.link.coff.getSymbolIndex().?,
6186 } };6138 } };
6187 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {6139 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6188 try p9.seeDecl(decl_index);6140 try p9.seeDecl(decl_index);
src/arch/arm/CodeGen.zig+50-53
...@@ -4253,59 +4253,57 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4253,59 +4253,57 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
42534253
4254 // Due to incremental compilation, how function calls are generated depends4254 // Due to incremental compilation, how function calls are generated depends
4255 // on linking.4255 // on linking.
4256 switch (self.bin_file.tag) {4256 if (self.air.value(callee)) |func_value| {
4257 .elf => {4257 if (func_value.castTag(.function)) |func_payload| {
4258 if (self.air.value(callee)) |func_value| {4258 const func = func_payload.data;
4259 if (func_value.castTag(.function)) |func_payload| {4259 const mod = self.bin_file.options.module.?;
4260 const func = func_payload.data;4260 const fn_owner_decl = mod.declPtr(func.owner_decl);
4261 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4261
4262 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4262 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4263 const mod = self.bin_file.options.module.?;4263 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4264 const fn_owner_decl = mod.declPtr(func.owner_decl);4264 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4265 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {4265 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
4266 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];4266 } else if (self.bin_file.cast(link.File.MachO)) |_| {
4267 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);4267 unreachable; // unsupported architecture for MachO
4268 } else unreachable;
4269 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
4270 } else if (func_value.castTag(.extern_fn)) |_| {
4271 return self.fail("TODO implement calling extern functions", .{});
4272 } else {
4273 return self.fail("TODO implement calling bitcasted functions", .{});
4274 }
4275 } else {4268 } else {
4276 assert(ty.zigTypeTag() == .Pointer);4269 return self.fail("TODO implement call on {s} for {s}", .{
4277 const mcv = try self.resolveInst(callee);4270 @tagName(self.bin_file.tag),
42784271 @tagName(self.target.cpu.arch),
4279 try self.genSetReg(Type.initTag(.usize), .lr, mcv);
4280 }
4281
4282 // TODO: add Instruction.supportedOn
4283 // function for ARM
4284 if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
4285 _ = try self.addInst(.{
4286 .tag = .blx,
4287 .data = .{ .reg = .lr },
4288 });4272 });
4289 } else {
4290 return self.fail("TODO fix blx emulation for ARM <v5", .{});
4291 // _ = try self.addInst(.{
4292 // .tag = .mov,
4293 // .data = .{ .rr_op = .{
4294 // .rd = .lr,
4295 // .rn = .r0,
4296 // .op = Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none),
4297 // } },
4298 // });
4299 // _ = try self.addInst(.{
4300 // .tag = .bx,
4301 // .data = .{ .reg = .lr },
4302 // });
4303 }4273 }
4304 },4274 } else if (func_value.castTag(.extern_fn)) |_| {
4305 .macho => unreachable, // unsupported architecture for MachO4275 return self.fail("TODO implement calling extern functions", .{});
4306 .coff => return self.fail("TODO implement call in COFF for {}", .{self.target.cpu.arch}),4276 } else {
4307 .plan9 => return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch}),4277 return self.fail("TODO implement calling bitcasted functions", .{});
4308 else => unreachable,4278 }
4279 } else {
4280 assert(ty.zigTypeTag() == .Pointer);
4281 const mcv = try self.resolveInst(callee);
4282
4283 try self.genSetReg(Type.initTag(.usize), .lr, mcv);
4284 }
4285
4286 // TODO: add Instruction.supportedOn
4287 // function for ARM
4288 if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
4289 _ = try self.addInst(.{
4290 .tag = .blx,
4291 .data = .{ .reg = .lr },
4292 });
4293 } else {
4294 return self.fail("TODO fix blx emulation for ARM <v5", .{});
4295 // _ = try self.addInst(.{
4296 // .tag = .mov,
4297 // .data = .{ .rr_op = .{
4298 // .rd = .lr,
4299 // .rn = .r0,
4300 // .op = Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none),
4301 // } },
4302 // });
4303 // _ = try self.addInst(.{
4304 // .tag = .bx,
4305 // .data = .{ .reg = .lr },
4306 // });
4309 }4307 }
43104308
4311 const result: MCValue = result: {4309 const result: MCValue = result: {
...@@ -6086,9 +6084,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6086,9 +6084,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6086 mod.markDeclAlive(decl);6084 mod.markDeclAlive(decl);
60876085
6088 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6086 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6089 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];6087 try decl.link.elf.ensureInitialized(elf_file);
6090 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;6088 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6091 return MCValue{ .memory = got_addr };
6092 } else if (self.bin_file.cast(link.File.MachO)) |_| {6089 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6093 unreachable; // unsupported architecture for MachO6090 unreachable; // unsupported architecture for MachO
6094 } else if (self.bin_file.cast(link.File.Coff)) |_| {6091 } else if (self.bin_file.cast(link.File.Coff)) |_| {
src/arch/riscv64/CodeGen.zig+4-9
...@@ -1722,14 +1722,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1722,14 +1722,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1722 if (func_value.castTag(.function)) |func_payload| {1722 if (func_value.castTag(.function)) |func_payload| {
1723 const func = func_payload.data;1723 const func = func_payload.data;
17241724
1725 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1726 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1727 const mod = self.bin_file.options.module.?;1725 const mod = self.bin_file.options.module.?;
1728 const fn_owner_decl = mod.declPtr(func.owner_decl);1726 const fn_owner_decl = mod.declPtr(func.owner_decl);
1729 const got_addr = blk: {1727 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
1730 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];1728 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
1731 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
1732 };
17331729
1734 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });1730 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
1735 _ = try self.addInst(.{1731 _ = try self.addInst(.{
...@@ -2557,9 +2553,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -2557,9 +2553,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
2557 const decl = mod.declPtr(decl_index);2553 const decl = mod.declPtr(decl_index);
2558 mod.markDeclAlive(decl);2554 mod.markDeclAlive(decl);
2559 if (self.bin_file.cast(link.File.Elf)) |elf_file| {2555 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2560 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];2556 try decl.link.elf.ensureInitialized(elf_file);
2561 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;2557 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
2562 return MCValue{ .memory = got_addr };
2563 } else if (self.bin_file.cast(link.File.MachO)) |_| {2558 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2564 // TODO I'm hacking my way through here by repurposing .memory for storing2559 // TODO I'm hacking my way through here by repurposing .memory for storing
2565 // index to the GOT target symbol index.2560 // index to the GOT target symbol index.
src/arch/sparc64/CodeGen.zig+6-11
...@@ -1216,12 +1216,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1216,12 +1216,11 @@ 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 ptr_bits = self.target.cpu.arch.ptrBitWidth();1219 const mod = self.bin_file.options.module.?;
1220 const ptr_bytes: u64 = @divExact(ptr_bits, 8);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: {1221 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1222 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];1222 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
1223 const mod = self.bin_file.options.module.?;1223 break :blk @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
1224 break :blk @intCast(u32, got.p_vaddr + mod.declPtr(func.owner_decl).link.elf.offset_table_index * ptr_bytes);
1225 } else unreachable;1224 } else unreachable;
12261225
1227 try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr });1226 try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr });
...@@ -4193,9 +4192,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -4193,9 +4192,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
4193}4192}
41944193
4195fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue {4194fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue {
4196 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4197 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4198
4199 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?4195 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
4200 if (tv.ty.zigTypeTag() == .Pointer) blk: {4196 if (tv.ty.zigTypeTag() == .Pointer) blk: {
4201 if (tv.ty.castPtrToFn()) |_| break :blk;4197 if (tv.ty.castPtrToFn()) |_| break :blk;
...@@ -4209,9 +4205,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -4209,9 +4205,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
42094205
4210 mod.markDeclAlive(decl);4206 mod.markDeclAlive(decl);
4211 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4207 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4212 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];4208 try decl.link.elf.ensureInitialized(elf_file);
4213 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;4209 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
4214 return MCValue{ .memory = got_addr };
4215 } else {4210 } else {
4216 return self.fail("TODO codegen non-ELF const Decl pointer", .{});4211 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
4217 }4212 }
src/arch/wasm/CodeGen.zig+10-3
...@@ -2120,22 +2120,28 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -2120,22 +2120,28 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2120 const module = func.bin_file.base.options.module.?;2120 const module = func.bin_file.base.options.module.?;
21212121
2122 if (func_val.castTag(.function)) |function| {2122 if (func_val.castTag(.function)) |function| {
2123 break :blk module.declPtr(function.data.owner_decl);2123 const decl = module.declPtr(function.data.owner_decl);
2124 try decl.link.wasm.ensureInitialized(func.bin_file);
2125 break :blk decl;
2124 } else if (func_val.castTag(.extern_fn)) |extern_fn| {2126 } else if (func_val.castTag(.extern_fn)) |extern_fn| {
2125 const ext_decl = module.declPtr(extern_fn.data.owner_decl);2127 const ext_decl = module.declPtr(extern_fn.data.owner_decl);
2126 const ext_info = ext_decl.ty.fnInfo();2128 const ext_info = ext_decl.ty.fnInfo();
2127 var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target);2129 var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target);
2128 defer func_type.deinit(func.gpa);2130 defer func_type.deinit(func.gpa);
2131 const atom = &ext_decl.link.wasm;
2132 try atom.ensureInitialized(func.bin_file);
2129 ext_decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type);2133 ext_decl.fn_link.wasm.type_index = try func.bin_file.putOrGetFuncType(func_type);
2130 try func.bin_file.addOrUpdateImport(2134 try func.bin_file.addOrUpdateImport(
2131 mem.sliceTo(ext_decl.name, 0),2135 mem.sliceTo(ext_decl.name, 0),
2132 ext_decl.link.wasm.sym_index,2136 atom.getSymbolIndex().?,
2133 ext_decl.getExternFn().?.lib_name,2137 ext_decl.getExternFn().?.lib_name,
2134 ext_decl.fn_link.wasm.type_index,2138 ext_decl.fn_link.wasm.type_index,
2135 );2139 );
2136 break :blk ext_decl;2140 break :blk ext_decl;
2137 } else if (func_val.castTag(.decl_ref)) |decl_ref| {2141 } else if (func_val.castTag(.decl_ref)) |decl_ref| {
2138 break :blk module.declPtr(decl_ref.data);2142 const decl = module.declPtr(decl_ref.data);
2143 try decl.link.wasm.ensureInitialized(func.bin_file);
2144 break :blk decl;
2139 }2145 }
2140 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()});
2141 };2147 };
...@@ -2752,6 +2758,7 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind...@@ -2752,6 +2758,7 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind
2752 }2758 }
27532759
2754 module.markDeclAlive(decl);2760 module.markDeclAlive(decl);
2761 try decl.link.wasm.ensureInitialized(func.bin_file);
27552762
2756 const target_sym_index = decl.link.wasm.sym_index;2763 const target_sym_index = decl.link.wasm.sym_index;
2757 if (decl.ty.zigTypeTag() == .Fn) {2764 if (decl.ty.zigTypeTag() == .Fn) {
src/arch/x86_64/CodeGen.zig+69-132
...@@ -2671,9 +2671,9 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue...@@ -2671,9 +2671,9 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2671 const mod = self.bin_file.options.module.?;2671 const mod = self.bin_file.options.module.?;
2672 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);2672 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
2673 const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag)2673 const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag)
2674 fn_owner_decl.link.macho.sym_index2674 fn_owner_decl.link.macho.getSymbolIndex().?
2675 else2675 else
2676 fn_owner_decl.link.coff.sym_index;2676 fn_owner_decl.link.coff.getSymbolIndex().?;
2677 const flags: u2 = switch (load_struct.type) {2677 const flags: u2 = switch (load_struct.type) {
2678 .got => 0b00,2678 .got => 0b00,
2679 .direct => 0b01,2679 .direct => 0b01,
...@@ -3992,49 +3992,26 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -3992,49 +3992,26 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
3992 // Due to incremental compilation, how function calls are generated depends3992 // Due to incremental compilation, how function calls are generated depends
3993 // on linking.3993 // on linking.
3994 const mod = self.bin_file.options.module.?;3994 const mod = self.bin_file.options.module.?;
3995 if (self.bin_file.cast(link.File.Elf)) |elf_file| {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);
3999 const ptr_bits = self.target.cpu.arch.ptrBitWidth();3999
4000 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4000 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4001 const fn_owner_decl = mod.declPtr(func.owner_decl);4001 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4002 const got_addr = blk: {4002 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4003 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4004 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
4005 };
4006 _ = try self.addInst(.{4003 _ = try self.addInst(.{
4007 .tag = .call,4004 .tag = .call,
4008 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),4005 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4009 .data = .{ .imm = @truncate(u32, got_addr) },4006 .data = .{ .imm = got_addr },
4010 });4007 });
4011 } else if (func_value.castTag(.extern_fn)) |_| {4008 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4012 return self.fail("TODO implement calling extern functions", .{});4009 try fn_owner_decl.link.coff.ensureInitialized(coff_file);
4013 } else {4010 const sym_index = fn_owner_decl.link.coff.getSymbolIndex().?;
4014 return self.fail("TODO implement calling bitcasted functions", .{});
4015 }
4016 } else {
4017 assert(ty.zigTypeTag() == .Pointer);
4018 const mcv = try self.resolveInst(callee);
4019 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4020 _ = try self.addInst(.{
4021 .tag = .call,
4022 .ops = Mir.Inst.Ops.encode(.{
4023 .reg1 = .rax,
4024 .flags = 0b01,
4025 }),
4026 .data = undefined,
4027 });
4028 }
4029 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4030 if (self.air.value(callee)) |func_value| {
4031 if (func_value.castTag(.function)) |func_payload| {
4032 const func = func_payload.data;
4033 const fn_owner_decl = mod.declPtr(func.owner_decl);
4034 try self.genSetReg(Type.initTag(.usize), .rax, .{4011 try self.genSetReg(Type.initTag(.usize), .rax, .{
4035 .linker_load = .{4012 .linker_load = .{
4036 .type = .got,4013 .type = .got,
4037 .sym_index = fn_owner_decl.link.coff.sym_index,4014 .sym_index = sym_index,
4038 },4015 },
4039 });4016 });
4040 _ = try self.addInst(.{4017 _ = try self.addInst(.{
...@@ -4045,19 +4022,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4045,19 +4022,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4045 }),4022 }),
4046 .data = undefined,4023 .data = undefined,
4047 });4024 });
4048 } else if (func_value.castTag(.extern_fn)) |func_payload| {4025 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4049 const extern_fn = func_payload.data;4026 try fn_owner_decl.link.macho.ensureInitialized(macho_file);
4050 const decl_name = mod.declPtr(extern_fn.owner_decl).name;4027 const sym_index = fn_owner_decl.link.macho.getSymbolIndex().?;
4051 if (extern_fn.lib_name) |lib_name| {
4052 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
4053 decl_name,
4054 lib_name,
4055 });
4056 }
4057 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4058 try self.genSetReg(Type.initTag(.usize), .rax, .{4028 try self.genSetReg(Type.initTag(.usize), .rax, .{
4059 .linker_load = .{4029 .linker_load = .{
4060 .type = .import,4030 .type = .got,
4061 .sym_index = sym_index,4031 .sym_index = sym_index,
4062 },4032 },
4063 });4033 });
...@@ -4069,35 +4039,37 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4069,35 +4039,37 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4069 }),4039 }),
4070 .data = undefined,4040 .data = undefined,
4071 });4041 });
4072 } else {4042 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4073 return self.fail("TODO implement calling bitcasted functions", .{});4043 try p9.seeDecl(func.owner_decl);
4044 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4045 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4046 const got_addr = p9.bases.data;
4047 const got_index = fn_owner_decl.link.plan9.got_index.?;
4048 const fn_got_addr = got_addr + got_index * ptr_bytes;
4049 _ = try self.addInst(.{
4050 .tag = .call,
4051 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4052 .data = .{ .imm = @intCast(u32, fn_got_addr) },
4053 });
4054 } else unreachable;
4055 } else if (func_value.castTag(.extern_fn)) |func_payload| {
4056 const extern_fn = func_payload.data;
4057 const decl_name = mod.declPtr(extern_fn.owner_decl).name;
4058 if (extern_fn.lib_name) |lib_name| {
4059 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
4060 decl_name,
4061 lib_name,
4062 });
4074 }4063 }
4075 } else {4064
4076 assert(ty.zigTypeTag() == .Pointer);4065 if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4077 const mcv = try self.resolveInst(callee);4066 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4078 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4079 _ = try self.addInst(.{
4080 .tag = .call,
4081 .ops = Mir.Inst.Ops.encode(.{
4082 .reg1 = .rax,
4083 .flags = 0b01,
4084 }),
4085 .data = undefined,
4086 });
4087 }
4088 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4089 if (self.air.value(callee)) |func_value| {
4090 if (func_value.castTag(.function)) |func_payload| {
4091 const func = func_payload.data;
4092 const fn_owner_decl = mod.declPtr(func.owner_decl);
4093 const sym_index = fn_owner_decl.link.macho.sym_index;
4094 try self.genSetReg(Type.initTag(.usize), .rax, .{4067 try self.genSetReg(Type.initTag(.usize), .rax, .{
4095 .linker_load = .{4068 .linker_load = .{
4096 .type = .got,4069 .type = .import,
4097 .sym_index = sym_index,4070 .sym_index = sym_index,
4098 },4071 },
4099 });4072 });
4100 // callq *%rax
4101 _ = try self.addInst(.{4073 _ = try self.addInst(.{
4102 .tag = .call,4074 .tag = .call,
4103 .ops = Mir.Inst.Ops.encode(.{4075 .ops = Mir.Inst.Ops.encode(.{
...@@ -4106,71 +4078,37 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4106,71 +4078,37 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4106 }),4078 }),
4107 .data = undefined,4079 .data = undefined,
4108 });4080 });
4109 } else if (func_value.castTag(.extern_fn)) |func_payload| {4081 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4110 const extern_fn = func_payload.data;
4111 const decl_name = mod.declPtr(extern_fn.owner_decl).name;
4112 if (extern_fn.lib_name) |lib_name| {
4113 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
4114 decl_name,
4115 lib_name,
4116 });
4117 }
4118 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));4082 const sym_index = try macho_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4119 _ = try self.addInst(.{4083 _ = try self.addInst(.{
4120 .tag = .call_extern,4084 .tag = .call_extern,
4121 .ops = undefined,4085 .ops = undefined,
4122 .data = .{4086 .data = .{
4123 .relocation = .{4087 .relocation = .{
4124 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,4088 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.getSymbolIndex().?,
4125 .sym_index = sym_index,4089 .sym_index = sym_index,
4126 },4090 },
4127 },4091 },
4128 });4092 });
4129 } else {4093 } else {
4130 return self.fail("TODO implement calling bitcasted functions", .{});4094 return self.fail("TODO implement calling extern functions", .{});
4131 }4095 }
4132 } else {4096 } else {
4133 assert(ty.zigTypeTag() == .Pointer);4097 return self.fail("TODO implement calling bitcasted functions", .{});
4134 const mcv = try self.resolveInst(callee);
4135 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4136 _ = try self.addInst(.{
4137 .tag = .call,
4138 .ops = Mir.Inst.Ops.encode(.{
4139 .reg1 = .rax,
4140 .flags = 0b01,
4141 }),
4142 .data = undefined,
4143 });
4144 }4098 }
4145 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {4099 } else {
4146 if (self.air.value(callee)) |func_value| {4100 assert(ty.zigTypeTag() == .Pointer);
4147 if (func_value.castTag(.function)) |func_payload| {4101 const mcv = try self.resolveInst(callee);
4148 try p9.seeDecl(func_payload.data.owner_decl);4102 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4149 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4103 _ = try self.addInst(.{
4150 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4104 .tag = .call,
4151 const got_addr = p9.bases.data;4105 .ops = Mir.Inst.Ops.encode(.{
4152 const got_index = mod.declPtr(func_payload.data.owner_decl).link.plan9.got_index.?;4106 .reg1 = .rax,
4153 const fn_got_addr = got_addr + got_index * ptr_bytes;4107 .flags = 0b01,
4154 _ = try self.addInst(.{4108 }),
4155 .tag = .call,4109 .data = undefined,
4156 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),4110 });
4157 .data = .{ .imm = @intCast(u32, fn_got_addr) },4111 }
4158 });
4159 } else return self.fail("TODO implement calling extern fn on plan9", .{});
4160 } else {
4161 assert(ty.zigTypeTag() == .Pointer);
4162 const mcv = try self.resolveInst(callee);
4163 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4164 _ = try self.addInst(.{
4165 .tag = .call,
4166 .ops = Mir.Inst.Ops.encode(.{
4167 .reg1 = .rax,
4168 .flags = 0b01,
4169 }),
4170 .data = undefined,
4171 });
4172 }
4173 } else unreachable;
41744112
4175 if (info.stack_byte_count > 0) {4113 if (info.stack_byte_count > 0) {
4176 // Readjust the stack4114 // Readjust the stack
...@@ -6781,20 +6719,19 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6781,20 +6719,19 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6781 module.markDeclAlive(decl);6719 module.markDeclAlive(decl);
67826720
6783 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6721 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6784 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];6722 try decl.link.elf.ensureInitialized(elf_file);
6785 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;6723 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6786 return MCValue{ .memory = got_addr };6724 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6787 } else if (self.bin_file.cast(link.File.MachO)) |_| {6725 try decl.link.macho.ensureInitialized(macho_file);
6788 assert(decl.link.macho.sym_index != 0);
6789 return MCValue{ .linker_load = .{6726 return MCValue{ .linker_load = .{
6790 .type = .got,6727 .type = .got,
6791 .sym_index = decl.link.macho.sym_index,6728 .sym_index = decl.link.macho.getSymbolIndex().?,
6792 } };6729 } };
6793 } else if (self.bin_file.cast(link.File.Coff)) |_| {6730 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6794 assert(decl.link.coff.sym_index != 0);6731 try decl.link.coff.ensureInitialized(coff_file);
6795 return MCValue{ .linker_load = .{6732 return MCValue{ .linker_load = .{
6796 .type = .got,6733 .type = .got,
6797 .sym_index = decl.link.coff.sym_index,6734 .sym_index = decl.link.coff.getSymbolIndex().?,
6798 } };6735 } };
6799 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {6736 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
6800 try p9.seeDecl(decl_index);6737 try p9.seeDecl(decl_index);
src/link.zig+5-28
...@@ -533,8 +533,7 @@ pub const File = struct {...@@ -533,8 +533,7 @@ pub const File = struct {
533 }533 }
534 }534 }
535535
536 /// May be called before or after updateDeclExports but must be called536 /// May be called before or after updateDeclExports for any given Decl.
537 /// after allocateDeclIndexes for any given Decl.
538 pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {537 pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
539 const decl = module.declPtr(decl_index);538 const decl = module.declPtr(decl_index);
540 log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmtDebug() });539 log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmtDebug() });
...@@ -557,8 +556,7 @@ pub const File = struct {...@@ -557,8 +556,7 @@ pub const File = struct {
557 }556 }
558 }557 }
559558
560 /// May be called before or after updateDeclExports but must be called559 /// May be called before or after updateDeclExports for any given Decl.
561 /// after allocateDeclIndexes for any given Decl.
562 pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void {560 pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void {
563 const owner_decl = module.declPtr(func.owner_decl);561 const owner_decl = module.declPtr(func.owner_decl);
564 log.debug("updateFunc {*} ({s}), type={}", .{562 log.debug("updateFunc {*} ({s}), type={}", .{
...@@ -602,28 +600,6 @@ pub const File = struct {...@@ -602,28 +600,6 @@ pub const File = struct {
602 }600 }
603 }601 }
604602
605 /// Must be called before any call to updateDecl or updateDeclExports for
606 /// any given Decl.
607 /// TODO we're transitioning to deleting this function and instead having
608 /// each linker backend notice the first time updateDecl or updateFunc is called, or
609 /// a callee referenced from AIR.
610 pub fn allocateDeclIndexes(base: *File, decl_index: Module.Decl.Index) error{OutOfMemory}!void {
611 const decl = base.options.module.?.declPtr(decl_index);
612 log.debug("allocateDeclIndexes {*} ({s})", .{ decl, decl.name });
613 if (build_options.only_c) {
614 assert(base.tag == .c);
615 return;
616 }
617 switch (base.tag) {
618 .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl_index),
619 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl_index),
620 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl_index),
621 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl_index),
622 .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl_index),
623 .c, .spirv, .nvptx => {},
624 }
625 }
626
627 pub fn releaseLock(self: *File) void {603 pub fn releaseLock(self: *File) void {
628 if (self.lock) |*lock| {604 if (self.lock) |*lock| {
629 lock.release();605 lock.release();
...@@ -874,8 +850,7 @@ pub const File = struct {...@@ -874,8 +850,7 @@ pub const File = struct {
874 AnalysisFail,850 AnalysisFail,
875 };851 };
876852
877 /// May be called before or after updateDecl, but must be called after853 /// May be called before or after updateDecl for any given Decl.
878 /// allocateDeclIndexes for any given Decl.
879 pub fn updateDeclExports(854 pub fn updateDeclExports(
880 base: *File,855 base: *File,
881 module: *Module,856 module: *Module,
...@@ -911,6 +886,8 @@ pub const File = struct {...@@ -911,6 +886,8 @@ pub const File = struct {
911 /// The linker is passed information about the containing atom, `parent_atom_index`, and offset within it's886 /// The linker is passed information about the containing atom, `parent_atom_index`, and offset within it's
912 /// memory buffer, `offset`, so that it can make a note of potential relocation sites, should the887 /// memory buffer, `offset`, so that it can make a note of potential relocation sites, should the
913 /// `Decl`'s address was not yet resolved, or the containing atom gets moved in virtual memory.888 /// `Decl`'s address was not yet resolved, or the containing atom gets moved in virtual memory.
889 /// May be called before or after updateFunc/updateDecl therefore it is up to the linker to allocate
890 /// the block/atom.
914 pub fn getDeclVAddr(base: *File, decl_index: Module.Decl.Index, reloc_info: RelocInfo) !u64 {891 pub fn getDeclVAddr(base: *File, decl_index: Module.Decl.Index, reloc_info: RelocInfo) !u64 {
915 if (build_options.only_c) unreachable;892 if (build_options.only_c) unreachable;
916 switch (base.tag) {893 switch (base.tag) {
src/link/Coff.zig+79-73
...@@ -480,16 +480,6 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {...@@ -480,16 +480,6 @@ fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {
480 header.virtual_size = increased_size;480 header.virtual_size = increased_size;
481}481}
482482
483pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {
484 if (self.llvm_object) |_| return;
485 const decl = self.base.options.module.?.declPtr(decl_index);
486 if (decl.link.coff.sym_index != 0) return;
487 decl.link.coff.sym_index = try self.allocateSymbol();
488 const gpa = self.base.allocator;
489 try self.atom_by_index_table.putNoClobber(gpa, decl.link.coff.sym_index, &decl.link.coff);
490 try self.decls.putNoClobber(gpa, decl_index, null);
491}
492
493fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 {483fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 {
494 const tracy = trace(@src());484 const tracy = trace(@src());
495 defer tracy.end();485 defer tracy.end();
...@@ -615,7 +605,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u...@@ -615,7 +605,7 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u
615 return vaddr;605 return vaddr;
616}606}
617607
618fn allocateSymbol(self: *Coff) !u32 {608pub fn allocateSymbol(self: *Coff) !u32 {
619 const gpa = self.base.allocator;609 const gpa = self.base.allocator;
620 try self.locals.ensureUnusedCapacity(gpa, 1);610 try self.locals.ensureUnusedCapacity(gpa, 1);
621611
...@@ -716,12 +706,11 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {...@@ -716,12 +706,11 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
716 const atom = try gpa.create(Atom);706 const atom = try gpa.create(Atom);
717 errdefer gpa.destroy(atom);707 errdefer gpa.destroy(atom);
718 atom.* = Atom.empty;708 atom.* = Atom.empty;
719 atom.sym_index = try self.allocateSymbol();709 try atom.ensureInitialized(self);
720 atom.size = @sizeOf(u64);710 atom.size = @sizeOf(u64);
721 atom.alignment = @alignOf(u64);711 atom.alignment = @alignOf(u64);
722712
723 try self.managed_atoms.append(gpa, atom);713 try self.managed_atoms.append(gpa, atom);
724 try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom);
725714
726 const sym = atom.getSymbolPtr(self);715 const sym = atom.getSymbolPtr(self);
727 sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1);716 sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1);
...@@ -754,12 +743,11 @@ fn createImportAtom(self: *Coff) !*Atom {...@@ -754,12 +743,11 @@ fn createImportAtom(self: *Coff) !*Atom {
754 const atom = try gpa.create(Atom);743 const atom = try gpa.create(Atom);
755 errdefer gpa.destroy(atom);744 errdefer gpa.destroy(atom);
756 atom.* = Atom.empty;745 atom.* = Atom.empty;
757 atom.sym_index = try self.allocateSymbol();746 try atom.ensureInitialized(self);
758 atom.size = @sizeOf(u64);747 atom.size = @sizeOf(u64);
759 atom.alignment = @alignOf(u64);748 atom.alignment = @alignOf(u64);
760749
761 try self.managed_atoms.append(gpa, atom);750 try self.managed_atoms.append(gpa, atom);
762 try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom);
763751
764 const sym = atom.getSymbolPtr(self);752 const sym = atom.getSymbolPtr(self);
765 sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1);753 sym.section_number = @intToEnum(coff.SectionNumber, self.idata_section_index.? + 1);
...@@ -790,7 +778,11 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void {...@@ -790,7 +778,11 @@ fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void {
790 const sym = atom.getSymbol(self);778 const sym = atom.getSymbol(self);
791 const section = self.sections.get(@enumToInt(sym.section_number) - 1);779 const section = self.sections.get(@enumToInt(sym.section_number) - 1);
792 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;780 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
793 log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{ atom.getName(self), file_offset, file_offset + code.len });781 log.debug("writing atom for symbol {s} at file offset 0x{x} to 0x{x}", .{
782 atom.getName(self),
783 file_offset,
784 file_offset + code.len,
785 });
794 try self.base.file.?.pwriteAll(code, file_offset);786 try self.base.file.?.pwriteAll(code, file_offset);
795 try self.resolveRelocs(atom);787 try self.resolveRelocs(atom);
796}788}
...@@ -848,6 +840,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void {...@@ -848,6 +840,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
848 // Remove any relocs and base relocs associated with this Atom840 // Remove any relocs and base relocs associated with this Atom
849 self.freeRelocationsForAtom(atom);841 self.freeRelocationsForAtom(atom);
850842
843 const gpa = self.base.allocator;
851 const sym = atom.getSymbol(self);844 const sym = atom.getSymbol(self);
852 const sect_id = @enumToInt(sym.section_number) - 1;845 const sect_id = @enumToInt(sym.section_number) - 1;
853 const free_list = &self.sections.items(.free_list)[sect_id];846 const free_list = &self.sections.items(.free_list)[sect_id];
...@@ -885,7 +878,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void {...@@ -885,7 +878,7 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
885 if (!already_have_free_list_node and prev.freeListEligible(self)) {878 if (!already_have_free_list_node and prev.freeListEligible(self)) {
886 // The free list is heuristics, it doesn't have to be perfect, so we can879 // The free list is heuristics, it doesn't have to be perfect, so we can
887 // ignore the OOM here.880 // ignore the OOM here.
888 free_list.append(self.base.allocator, prev) catch {};881 free_list.append(gpa, prev) catch {};
889 }882 }
890 } else {883 } else {
891 atom.prev = null;884 atom.prev = null;
...@@ -896,6 +889,28 @@ fn freeAtom(self: *Coff, atom: *Atom) void {...@@ -896,6 +889,28 @@ fn freeAtom(self: *Coff, atom: *Atom) void {
896 } else {889 } else {
897 atom.next = null;890 atom.next = null;
898 }891 }
892
893 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
894 const sym_index = atom.getSymbolIndex().?;
895 self.locals_free_list.append(gpa, sym_index) catch {};
896
897 // Try freeing GOT atom if this decl had one
898 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
899 if (self.got_entries_table.get(got_target)) |got_index| {
900 self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {};
901 self.got_entries.items[got_index] = .{
902 .target = .{ .sym_index = 0, .file = null },
903 .sym_index = 0,
904 };
905 _ = self.got_entries_table.remove(got_target);
906
907 log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index });
908 }
909
910 self.locals.items[sym_index].section_number = .UNDEFINED;
911 _ = self.atom_by_index_table.remove(sym_index);
912 log.debug(" adding local symbol index {d} to free list", .{sym_index});
913 atom.sym_index = 0;
899}914}
900915
901pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {916pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
...@@ -912,8 +927,15 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live...@@ -912,8 +927,15 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
912927
913 const decl_index = func.owner_decl;928 const decl_index = func.owner_decl;
914 const decl = module.declPtr(decl_index);929 const decl = module.declPtr(decl_index);
915 self.freeUnnamedConsts(decl_index);930 const atom = &decl.link.coff;
916 self.freeRelocationsForAtom(&decl.link.coff);931 try atom.ensureInitialized(self);
932 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
933 if (gop.found_existing) {
934 self.freeUnnamedConsts(decl_index);
935 self.freeRelocationsForAtom(&decl.link.coff);
936 } else {
937 gop.value_ptr.* = null;
938 }
917939
918 var code_buffer = std.ArrayList(u8).init(self.base.allocator);940 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
919 defer code_buffer.deinit();941 defer code_buffer.deinit();
...@@ -960,9 +982,9 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -960,9 +982,9 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
960 const atom = try gpa.create(Atom);982 const atom = try gpa.create(Atom);
961 errdefer gpa.destroy(atom);983 errdefer gpa.destroy(atom);
962 atom.* = Atom.empty;984 atom.* = Atom.empty;
985 try atom.ensureInitialized(self);
986 try self.managed_atoms.append(gpa, atom);
963987
964 atom.sym_index = try self.allocateSymbol();
965 const sym = atom.getSymbolPtr(self);
966 const sym_name = blk: {988 const sym_name = blk: {
967 const decl_name = try decl.getFullyQualifiedName(mod);989 const decl_name = try decl.getFullyQualifiedName(mod);
968 defer gpa.free(decl_name);990 defer gpa.free(decl_name);
...@@ -971,14 +993,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -971,14 +993,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
971 break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });993 break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
972 };994 };
973 defer gpa.free(sym_name);995 defer gpa.free(sym_name);
974 try self.setSymbolName(sym, sym_name);996 try self.setSymbolName(atom.getSymbolPtr(self), sym_name);
975 sym.section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1);997 atom.getSymbolPtr(self).section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1);
976
977 try self.managed_atoms.append(gpa, atom);
978 try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom);
979998
980 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{999 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{
981 .parent_atom_index = atom.sym_index,1000 .parent_atom_index = atom.getSymbolIndex().?,
982 });1001 });
983 const code = switch (res) {1002 const code = switch (res) {
984 .ok => code_buffer.items,1003 .ok => code_buffer.items,
...@@ -993,17 +1012,17 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -993,17 +1012,17 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
993 const required_alignment = tv.ty.abiAlignment(self.base.options.target);1012 const required_alignment = tv.ty.abiAlignment(self.base.options.target);
994 atom.alignment = required_alignment;1013 atom.alignment = required_alignment;
995 atom.size = @intCast(u32, code.len);1014 atom.size = @intCast(u32, code.len);
996 sym.value = try self.allocateAtom(atom, atom.size, atom.alignment);1015 atom.getSymbolPtr(self).value = try self.allocateAtom(atom, atom.size, atom.alignment);
997 errdefer self.freeAtom(atom);1016 errdefer self.freeAtom(atom);
9981017
999 try unnamed_consts.append(gpa, atom);1018 try unnamed_consts.append(gpa, atom);
10001019
1001 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, sym.value });1020 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value });
1002 log.debug(" (required alignment 0x{x})", .{required_alignment});1021 log.debug(" (required alignment 0x{x})", .{required_alignment});
10031022
1004 try self.writeAtom(atom, code);1023 try self.writeAtom(atom, code);
10051024
1006 return atom.sym_index;1025 return atom.getSymbolIndex().?;
1007}1026}
10081027
1009pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void {1028pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void {
...@@ -1028,7 +1047,14 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1028,7 +1047,14 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1028 }1047 }
1029 }1048 }
10301049
1031 self.freeRelocationsForAtom(&decl.link.coff);1050 const atom = &decl.link.coff;
1051 try atom.ensureInitialized(self);
1052 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1053 if (gop.found_existing) {
1054 self.freeRelocationsForAtom(atom);
1055 } else {
1056 gop.value_ptr.* = null;
1057 }
10321058
1033 var code_buffer = std.ArrayList(u8).init(self.base.allocator);1059 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
1034 defer code_buffer.deinit();1060 defer code_buffer.deinit();
...@@ -1038,7 +1064,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1038,7 +1064,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1038 .ty = decl.ty,1064 .ty = decl.ty,
1039 .val = decl_val,1065 .val = decl_val,
1040 }, &code_buffer, .none, .{1066 }, &code_buffer, .none, .{
1041 .parent_atom_index = decl.link.coff.sym_index,1067 .parent_atom_index = decl.link.coff.getSymbolIndex().?,
1042 });1068 });
1043 const code = switch (res) {1069 const code = switch (res) {
1044 .ok => code_buffer.items,1070 .ok => code_buffer.items,
...@@ -1099,7 +1125,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,...@@ -1099,7 +1125,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
10991125
1100 const code_len = @intCast(u32, code.len);1126 const code_len = @intCast(u32, code.len);
1101 const atom = &decl.link.coff;1127 const atom = &decl.link.coff;
1102 assert(atom.sym_index != 0); // Caller forgot to allocateDeclIndexes()1128
1103 if (atom.size != 0) {1129 if (atom.size != 0) {
1104 const sym = atom.getSymbolPtr(self);1130 const sym = atom.getSymbolPtr(self);
1105 try self.setSymbolName(sym, decl_name);1131 try self.setSymbolName(sym, decl_name);
...@@ -1116,7 +1142,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,...@@ -1116,7 +1142,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
1116 if (vaddr != sym.value) {1142 if (vaddr != sym.value) {
1117 sym.value = vaddr;1143 sym.value = vaddr;
1118 log.debug(" (updating GOT entry)", .{});1144 log.debug(" (updating GOT entry)", .{});
1119 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };1145 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };
1120 const got_atom = self.getGotAtomForSymbol(got_target).?;1146 const got_atom = self.getGotAtomForSymbol(got_target).?;
1121 self.markRelocsDirtyByTarget(got_target);1147 self.markRelocsDirtyByTarget(got_target);
1122 try self.writePtrWidthAtom(got_atom);1148 try self.writePtrWidthAtom(got_atom);
...@@ -1137,10 +1163,10 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,...@@ -1137,10 +1163,10 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8,
1137 atom.size = code_len;1163 atom.size = code_len;
1138 sym.value = vaddr;1164 sym.value = vaddr;
11391165
1140 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };1166 const got_target = SymbolWithLoc{ .sym_index = atom.getSymbolIndex().?, .file = null };
1141 const got_index = try self.allocateGotEntry(got_target);1167 const got_index = try self.allocateGotEntry(got_target);
1142 const got_atom = try self.createGotAtom(got_target);1168 const got_atom = try self.createGotAtom(got_target);
1143 self.got_entries.items[got_index].sym_index = got_atom.sym_index;1169 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
1144 try self.writePtrWidthAtom(got_atom);1170 try self.writePtrWidthAtom(got_atom);
1145 }1171 }
11461172
...@@ -1160,11 +1186,6 @@ fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void {...@@ -1160,11 +1186,6 @@ fn freeUnnamedConsts(self: *Coff, decl_index: Module.Decl.Index) void {
1160 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;1186 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
1161 for (unnamed_consts.items) |atom| {1187 for (unnamed_consts.items) |atom| {
1162 self.freeAtom(atom);1188 self.freeAtom(atom);
1163 self.locals_free_list.append(gpa, atom.sym_index) catch {};
1164 self.locals.items[atom.sym_index].section_number = .UNDEFINED;
1165 _ = self.atom_by_index_table.remove(atom.sym_index);
1166 log.debug(" adding local symbol index {d} to free list", .{atom.sym_index});
1167 atom.sym_index = 0;
1168 }1189 }
1169 unnamed_consts.clearAndFree(gpa);1190 unnamed_consts.clearAndFree(gpa);
1170}1191}
...@@ -1179,35 +1200,11 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {...@@ -1179,35 +1200,11 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
11791200
1180 log.debug("freeDecl {*}", .{decl});1201 log.debug("freeDecl {*}", .{decl});
11811202
1182 const kv = self.decls.fetchRemove(decl_index);1203 if (self.decls.fetchRemove(decl_index)) |kv| {
1183 if (kv.?.value) |_| {1204 if (kv.value) |_| {
1184 self.freeAtom(&decl.link.coff);1205 self.freeAtom(&decl.link.coff);
1185 self.freeUnnamedConsts(decl_index);1206 self.freeUnnamedConsts(decl_index);
1186 }
1187
1188 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
1189 const gpa = self.base.allocator;
1190 const sym_index = decl.link.coff.sym_index;
1191 if (sym_index != 0) {
1192 self.locals_free_list.append(gpa, sym_index) catch {};
1193
1194 // Try freeing GOT atom if this decl had one
1195 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1196 if (self.got_entries_table.get(got_target)) |got_index| {
1197 self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {};
1198 self.got_entries.items[got_index] = .{
1199 .target = .{ .sym_index = 0, .file = null },
1200 .sym_index = 0,
1201 };
1202 _ = self.got_entries_table.remove(got_target);
1203
1204 log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index });
1205 }1207 }
1206
1207 self.locals.items[sym_index].section_number = .UNDEFINED;
1208 _ = self.atom_by_index_table.remove(sym_index);
1209 log.debug(" adding local symbol index {d} to free list", .{sym_index});
1210 decl.link.coff.sym_index = 0;
1211 }1208 }
1212}1209}
12131210
...@@ -1261,7 +1258,14 @@ pub fn updateDeclExports(...@@ -1261,7 +1258,14 @@ pub fn updateDeclExports(
12611258
1262 const decl = module.declPtr(decl_index);1259 const decl = module.declPtr(decl_index);
1263 const atom = &decl.link.coff;1260 const atom = &decl.link.coff;
1264 if (atom.sym_index == 0) return;1261
1262 if (atom.getSymbolIndex() == null) return;
1263
1264 const gop = try self.decls.getOrPut(gpa, decl_index);
1265 if (!gop.found_existing) {
1266 gop.value_ptr.* = self.getDeclOutputSection(decl);
1267 }
1268
1265 const decl_sym = atom.getSymbol(self);1269 const decl_sym = atom.getSymbol(self);
12661270
1267 for (exports) |exp| {1271 for (exports) |exp| {
...@@ -1416,7 +1420,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1416,7 +1420,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
14161420
1417 const import_index = try self.allocateImportEntry(global);1421 const import_index = try self.allocateImportEntry(global);
1418 const import_atom = try self.createImportAtom();1422 const import_atom = try self.createImportAtom();
1419 self.imports.items[import_index].sym_index = import_atom.sym_index;1423 self.imports.items[import_index].sym_index = import_atom.getSymbolIndex().?;
1420 try self.writePtrWidthAtom(import_atom);1424 try self.writePtrWidthAtom(import_atom);
1421 }1425 }
14221426
...@@ -1460,10 +1464,12 @@ pub fn getDeclVAddr(...@@ -1460,10 +1464,12 @@ pub fn getDeclVAddr(
1460 const decl = mod.declPtr(decl_index);1464 const decl = mod.declPtr(decl_index);
14611465
1462 assert(self.llvm_object == null);1466 assert(self.llvm_object == null);
1463 assert(decl.link.coff.sym_index != 0);1467
1468 try decl.link.coff.ensureInitialized(self);
1469 const sym_index = decl.link.coff.getSymbolIndex().?;
14641470
1465 const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;1471 const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
1466 const target = SymbolWithLoc{ .sym_index = decl.link.coff.sym_index, .file = null };1472 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1467 try atom.addRelocation(self, .{1473 try atom.addRelocation(self, .{
1468 .type = .direct,1474 .type = .direct,
1469 .target = target,1475 .target = target,
src/link/Coff/Atom.zig+19-4
...@@ -39,30 +39,45 @@ pub const empty = Atom{...@@ -39,30 +39,45 @@ pub const empty = Atom{
39 .next = null,39 .next = null,
40};40};
4141
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}
47
48pub fn getSymbolIndex(self: Atom) ?u32 {
49 if (self.sym_index == 0) return null;
50 return self.sym_index;
51}
52
42/// Returns symbol referencing this atom.53/// Returns symbol referencing this atom.
43pub fn getSymbol(self: Atom, coff_file: *const Coff) *const coff.Symbol {54pub fn getSymbol(self: Atom, coff_file: *const Coff) *const coff.Symbol {
55 const sym_index = self.getSymbolIndex().?;
44 return coff_file.getSymbol(.{56 return coff_file.getSymbol(.{
45 .sym_index = self.sym_index,57 .sym_index = sym_index,
46 .file = self.file,58 .file = self.file,
47 });59 });
48}60}
4961
50/// Returns pointer-to-symbol referencing this atom.62/// Returns pointer-to-symbol referencing this atom.
51pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol {63pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol {
64 const sym_index = self.getSymbolIndex().?;
52 return coff_file.getSymbolPtr(.{65 return coff_file.getSymbolPtr(.{
53 .sym_index = self.sym_index,66 .sym_index = sym_index,
54 .file = self.file,67 .file = self.file,
55 });68 });
56}69}
5770
58pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {71pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {
59 return .{ .sym_index = self.sym_index, .file = self.file };72 const sym_index = self.getSymbolIndex().?;
73 return .{ .sym_index = sym_index, .file = self.file };
60}74}
6175
62/// Returns the name of this atom.76/// Returns the name of this atom.
63pub fn getName(self: Atom, coff_file: *const Coff) []const u8 {77pub fn getName(self: Atom, coff_file: *const Coff) []const u8 {
78 const sym_index = self.getSymbolIndex().?;
64 return coff_file.getSymbolName(.{79 return coff_file.getSymbolName(.{
65 .sym_index = self.sym_index,80 .sym_index = sym_index,
66 .file = self.file,81 .file = self.file,
67 });82 });
68}83}
src/link/Elf.zig+99-131
...@@ -10,6 +10,7 @@ const fs = std.fs;...@@ -10,6 +10,7 @@ const fs = std.fs;
10const elf = std.elf;10const elf = std.elf;
11const log = std.log.scoped(.link);11const log = std.log.scoped(.link);
1212
13const Atom = @import("Elf/Atom.zig");
13const Module = @import("../Module.zig");14const Module = @import("../Module.zig");
14const Compilation = @import("../Compilation.zig");15const Compilation = @import("../Compilation.zig");
15const Dwarf = @import("Dwarf.zig");16const Dwarf = @import("Dwarf.zig");
...@@ -31,6 +32,8 @@ const Air = @import("../Air.zig");...@@ -31,6 +32,8 @@ const Air = @import("../Air.zig");
31const Liveness = @import("../Liveness.zig");32const Liveness = @import("../Liveness.zig");
32const LlvmObject = @import("../codegen/llvm.zig").Object;33const LlvmObject = @import("../codegen/llvm.zig").Object;
3334
35pub const TextBlock = Atom;
36
34const default_entry_addr = 0x8000000;37const default_entry_addr = 0x8000000;
3538
36pub const base_tag: File.Tag = .elf;39pub const base_tag: File.Tag = .elf;
...@@ -188,62 +191,10 @@ const ideal_factor = 3;...@@ -188,62 +191,10 @@ const ideal_factor = 3;
188/// it as a possible place to put new symbols, it must have enough room for this many bytes191/// it as a possible place to put new symbols, it must have enough room for this many bytes
189/// (plus extra for reserved capacity).192/// (plus extra for reserved capacity).
190const minimum_text_block_size = 64;193const minimum_text_block_size = 64;
191const min_text_capacity = padToIdeal(minimum_text_block_size);194pub const min_text_capacity = padToIdeal(minimum_text_block_size);
192195
193pub const PtrWidth = enum { p32, p64 };196pub const PtrWidth = enum { p32, p64 };
194197
195pub const TextBlock = struct {
196 /// Each decl always gets a local symbol with the fully qualified name.
197 /// The vaddr and size are found here directly.
198 /// The file offset is found by computing the vaddr offset from the section vaddr
199 /// the symbol references, and adding that to the file offset of the section.
200 /// If this field is 0, it means the codegen size = 0 and there is no symbol or
201 /// offset table entry.
202 local_sym_index: u32,
203 /// This field is undefined for symbols with size = 0.
204 offset_table_index: u32,
205 /// Points to the previous and next neighbors, based on the `text_offset`.
206 /// This can be used to find, for example, the capacity of this `TextBlock`.
207 prev: ?*TextBlock,
208 next: ?*TextBlock,
209
210 dbg_info_atom: Dwarf.Atom,
211
212 pub const empty = TextBlock{
213 .local_sym_index = 0,
214 .offset_table_index = undefined,
215 .prev = null,
216 .next = null,
217 .dbg_info_atom = undefined,
218 };
219
220 /// Returns how much room there is to grow in virtual address space.
221 /// File offset relocation happens transparently, so it is not included in
222 /// this calculation.
223 fn capacity(self: TextBlock, elf_file: Elf) u64 {
224 const self_sym = elf_file.local_symbols.items[self.local_sym_index];
225 if (self.next) |next| {
226 const next_sym = elf_file.local_symbols.items[next.local_sym_index];
227 return next_sym.st_value - self_sym.st_value;
228 } else {
229 // We are the last block. The capacity is limited only by virtual address space.
230 return std.math.maxInt(u32) - self_sym.st_value;
231 }
232 }
233
234 fn freeListEligible(self: TextBlock, elf_file: Elf) bool {
235 // No need to keep a free list node for the last block.
236 const next = self.next orelse return false;
237 const self_sym = elf_file.local_symbols.items[self.local_sym_index];
238 const next_sym = elf_file.local_symbols.items[next.local_sym_index];
239 const cap = next_sym.st_value - self_sym.st_value;
240 const ideal_cap = padToIdeal(self_sym.st_size);
241 if (cap <= ideal_cap) return false;
242 const surplus = cap - ideal_cap;
243 return surplus >= min_text_capacity;
244 }
245};
246
247pub const Export = struct {198pub const Export = struct {
248 sym_index: ?u32 = null,199 sym_index: ?u32 = null,
249};200};
...@@ -393,9 +344,10 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File....@@ -393,9 +344,10 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.
393 const decl = mod.declPtr(decl_index);344 const decl = mod.declPtr(decl_index);
394345
395 assert(self.llvm_object == null);346 assert(self.llvm_object == null);
396 assert(decl.link.elf.local_sym_index != 0);
397347
398 const target = decl.link.elf.local_sym_index;348 try decl.link.elf.ensureInitialized(self);
349 const target = decl.link.elf.getSymbolIndex().?;
350
399 const vaddr = self.local_symbols.items[target].st_value;351 const vaddr = self.local_symbols.items[target].st_value;
400 const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?;352 const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?;
401 const gop = try self.relocs.getOrPut(self.base.allocator, atom);353 const gop = try self.relocs.getOrPut(self.base.allocator, atom);
...@@ -496,7 +448,7 @@ fn makeString(self: *Elf, bytes: []const u8) !u32 {...@@ -496,7 +448,7 @@ fn makeString(self: *Elf, bytes: []const u8) !u32 {
496 return @intCast(u32, result);448 return @intCast(u32, result);
497}449}
498450
499fn getString(self: Elf, str_off: u32) []const u8 {451pub fn getString(self: Elf, str_off: u32) []const u8 {
500 assert(str_off < self.shstrtab.items.len);452 assert(str_off < self.shstrtab.items.len);
501 return mem.sliceTo(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off), 0);453 return mem.sliceTo(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off), 0);
502}454}
...@@ -941,7 +893,7 @@ fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u...@@ -941,7 +893,7 @@ fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u
941 // Must move the entire section.893 // Must move the entire section.
942 const new_offset = self.findFreeSpace(needed_size, self.page_size);894 const new_offset = self.findFreeSpace(needed_size, self.page_size);
943 const existing_size = if (self.atoms.get(phdr_index)) |last| blk: {895 const existing_size = if (self.atoms.get(phdr_index)) |last| blk: {
944 const sym = self.local_symbols.items[last.local_sym_index];896 const sym = last.getSymbol(self);
945 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;897 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
946 } else if (shdr_index == self.got_section_index.?) blk: {898 } else if (shdr_index == self.got_section_index.?) blk: {
947 break :blk shdr.sh_size;899 break :blk shdr.sh_size;
...@@ -1079,7 +1031,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1079,7 +1031,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1079 while (it.next()) |entry| {1031 while (it.next()) |entry| {
1080 const atom = entry.key_ptr.*;1032 const atom = entry.key_ptr.*;
1081 const relocs = entry.value_ptr.*;1033 const relocs = entry.value_ptr.*;
1082 const source_sym = self.local_symbols.items[atom.local_sym_index];1034 const source_sym = atom.getSymbol(self);
1083 const source_shdr = self.sections.items[source_sym.st_shndx];1035 const source_shdr = self.sections.items[source_sym.st_shndx];
10841036
1085 log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)});1037 log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)});
...@@ -2082,11 +2034,13 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2082,11 +2034,13 @@ fn writeElfHeader(self: *Elf) !void {
2082}2034}
20832035
2084fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {2036fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
2085 const local_sym = self.local_symbols.items[text_block.local_sym_index];2037 const local_sym = text_block.getSymbol(self);
2086 const name_str_index = local_sym.st_name;2038 const name_str_index = local_sym.st_name;
2087 const name = self.getString(name_str_index);2039 const name = self.getString(name_str_index);
2088 log.debug("freeTextBlock {*} ({s})", .{ text_block, name });2040 log.debug("freeTextBlock {*} ({s})", .{ text_block, name });
20892041
2042 self.freeRelocationsForTextBlock(text_block);
2043
2090 const free_list = self.atom_free_lists.getPtr(phdr_index).?;2044 const free_list = self.atom_free_lists.getPtr(phdr_index).?;
2091 var already_have_free_list_node = false;2045 var already_have_free_list_node = false;
2092 {2046 {
...@@ -2118,7 +2072,7 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {...@@ -2118,7 +2072,7 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
2118 if (text_block.prev) |prev| {2072 if (text_block.prev) |prev| {
2119 prev.next = text_block.next;2073 prev.next = text_block.next;
21202074
2121 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {2075 if (!already_have_free_list_node and prev.freeListEligible(self)) {
2122 // The free list is heuristics, it doesn't have to be perfect, so we can2076 // The free list is heuristics, it doesn't have to be perfect, so we can
2123 // ignore the OOM here.2077 // ignore the OOM here.
2124 free_list.append(self.base.allocator, prev) catch {};2078 free_list.append(self.base.allocator, prev) catch {};
...@@ -2133,6 +2087,15 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {...@@ -2133,6 +2087,15 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
2133 text_block.next = null;2087 text_block.next = null;
2134 }2088 }
21352089
2090 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2091 const local_sym_index = text_block.getSymbolIndex().?;
2092 self.local_symbol_free_list.append(self.base.allocator, local_sym_index) catch {};
2093 self.local_symbols.items[local_sym_index].st_info = 0;
2094 _ = self.atom_by_index_table.remove(local_sym_index);
2095 text_block.local_sym_index = 0;
2096
2097 self.offset_table_free_list.append(self.base.allocator, text_block.offset_table_index) catch {};
2098
2136 if (self.dwarf) |*dw| {2099 if (self.dwarf) |*dw| {
2137 dw.freeAtom(&text_block.dbg_info_atom);2100 dw.freeAtom(&text_block.dbg_info_atom);
2138 }2101 }
...@@ -2146,9 +2109,9 @@ fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr...@@ -2146,9 +2109,9 @@ fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr
2146}2109}
21472110
2148fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {2111fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
2149 const sym = self.local_symbols.items[text_block.local_sym_index];2112 const sym = text_block.getSymbol(self);
2150 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;2113 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;
2151 const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*);2114 const need_realloc = !align_ok or new_block_size > text_block.capacity(self);
2152 if (!need_realloc) return sym.st_value;2115 if (!need_realloc) return sym.st_value;
2153 return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index);2116 return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index);
2154}2117}
...@@ -2176,8 +2139,8 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2176,8 +2139,8 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2176 const big_block = free_list.items[i];2139 const big_block = free_list.items[i];
2177 // We now have a pointer to a live text block that has too much capacity.2140 // We now have a pointer to a live text block that has too much capacity.
2178 // Is it enough that we could fit this new text block?2141 // Is it enough that we could fit this new text block?
2179 const sym = self.local_symbols.items[big_block.local_sym_index];2142 const sym = big_block.getSymbol(self);
2180 const capacity = big_block.capacity(self.*);2143 const capacity = big_block.capacity(self);
2181 const ideal_capacity = padToIdeal(capacity);2144 const ideal_capacity = padToIdeal(capacity);
2182 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;2145 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;
2183 const capacity_end_vaddr = sym.st_value + capacity;2146 const capacity_end_vaddr = sym.st_value + capacity;
...@@ -2187,7 +2150,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2187,7 +2150,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2187 // Additional bookkeeping here to notice if this free list node2150 // Additional bookkeeping here to notice if this free list node
2188 // should be deleted because the block that it points to has grown to take up2151 // should be deleted because the block that it points to has grown to take up
2189 // more of the extra capacity.2152 // more of the extra capacity.
2190 if (!big_block.freeListEligible(self.*)) {2153 if (!big_block.freeListEligible(self)) {
2191 _ = free_list.swapRemove(i);2154 _ = free_list.swapRemove(i);
2192 } else {2155 } else {
2193 i += 1;2156 i += 1;
...@@ -2207,7 +2170,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2207,7 +2170,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2207 }2170 }
2208 break :blk new_start_vaddr;2171 break :blk new_start_vaddr;
2209 } else if (self.atoms.get(phdr_index)) |last| {2172 } else if (self.atoms.get(phdr_index)) |last| {
2210 const sym = self.local_symbols.items[last.local_sym_index];2173 const sym = last.getSymbol(self);
2211 const ideal_capacity = padToIdeal(sym.st_size);2174 const ideal_capacity = padToIdeal(sym.st_size);
2212 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;2175 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;
2213 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);2176 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
...@@ -2262,7 +2225,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2262,7 +2225,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2262 return vaddr;2225 return vaddr;
2263}2226}
22642227
2265fn allocateLocalSymbol(self: *Elf) !u32 {2228pub fn allocateLocalSymbol(self: *Elf) !u32 {
2266 try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1);2229 try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1);
22672230
2268 const index = blk: {2231 const index = blk: {
...@@ -2289,40 +2252,35 @@ fn allocateLocalSymbol(self: *Elf) !u32 {...@@ -2289,40 +2252,35 @@ fn allocateLocalSymbol(self: *Elf) !u32 {
2289 return index;2252 return index;
2290}2253}
22912254
2292pub fn allocateDeclIndexes(self: *Elf, decl_index: Module.Decl.Index) !void {2255pub fn allocateGotOffset(self: *Elf) !u32 {
2293 if (self.llvm_object) |_| return;
2294
2295 const mod = self.base.options.module.?;
2296 const decl = mod.declPtr(decl_index);
2297 if (decl.link.elf.local_sym_index != 0) return;
2298
2299 try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1);2256 try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1);
2300 try self.decls.putNoClobber(self.base.allocator, decl_index, null);
23012257
2302 const decl_name = try decl.getFullyQualifiedName(mod);2258 const index = blk: {
2303 defer self.base.allocator.free(decl_name);2259 if (self.offset_table_free_list.popOrNull()) |index| {
2260 log.debug(" (reusing GOT offset at index {d})", .{index});
2261 break :blk index;
2262 } else {
2263 log.debug(" (allocating GOT offset at index {d})", .{self.offset_table.items.len});
2264 const index = @intCast(u32, self.offset_table.items.len);
2265 _ = self.offset_table.addOneAssumeCapacity();
2266 self.offset_table_count_dirty = true;
2267 break :blk index;
2268 }
2269 };
23042270
2305 log.debug("allocating symbol indexes for {s}", .{decl_name});2271 self.offset_table.items[index] = 0;
2306 decl.link.elf.local_sym_index = try self.allocateLocalSymbol();2272 return index;
2307 try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.elf.local_sym_index, &decl.link.elf);2273}
23082274
2309 if (self.offset_table_free_list.popOrNull()) |i| {2275fn freeRelocationsForTextBlock(self: *Elf, text_block: *TextBlock) void {
2310 decl.link.elf.offset_table_index = i;2276 var removed_relocs = self.relocs.fetchRemove(text_block);
2311 } else {2277 if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator);
2312 decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len);
2313 _ = self.offset_table.addOneAssumeCapacity();
2314 self.offset_table_count_dirty = true;
2315 }
2316 self.offset_table.items[decl.link.elf.offset_table_index] = 0;
2317}2278}
23182279
2319fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {2280fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
2320 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;2281 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
2321 for (unnamed_consts.items) |atom| {2282 for (unnamed_consts.items) |atom| {
2322 self.freeTextBlock(atom, self.phdr_load_ro_index.?);2283 self.freeTextBlock(atom, self.phdr_load_ro_index.?);
2323 self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {};
2324 self.local_symbols.items[atom.local_sym_index].st_info = 0;
2325 _ = self.atom_by_index_table.remove(atom.local_sym_index);
2326 }2284 }
2327 unnamed_consts.clearAndFree(self.base.allocator);2285 unnamed_consts.clearAndFree(self.base.allocator);
2328}2286}
...@@ -2335,20 +2293,13 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {...@@ -2335,20 +2293,13 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
2335 const mod = self.base.options.module.?;2293 const mod = self.base.options.module.?;
2336 const decl = mod.declPtr(decl_index);2294 const decl = mod.declPtr(decl_index);
23372295
2338 const kv = self.decls.fetchRemove(decl_index);2296 log.debug("freeDecl {*}", .{decl});
2339 if (kv.?.value) |index| {
2340 self.freeTextBlock(&decl.link.elf, index);
2341 self.freeUnnamedConsts(decl_index);
2342 }
2343
2344 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2345 if (decl.link.elf.local_sym_index != 0) {
2346 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
2347 self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;
2348 _ = self.atom_by_index_table.remove(decl.link.elf.local_sym_index);
2349 decl.link.elf.local_sym_index = 0;
23502297
2351 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};2298 if (self.decls.fetchRemove(decl_index)) |kv| {
2299 if (kv.value) |index| {
2300 self.freeTextBlock(&decl.link.elf, index);
2301 self.freeUnnamedConsts(decl_index);
2302 }
2352 }2303 }
23532304
2354 if (self.dwarf) |*dw| {2305 if (self.dwarf) |*dw| {
...@@ -2397,10 +2348,9 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2397,10 +2348,9 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2397 const phdr_index = decl_ptr.*.?;2348 const phdr_index = decl_ptr.*.?;
2398 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;2349 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
23992350
2400 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()2351 const local_sym = decl.link.elf.getSymbolPtr(self);
2401 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
2402 if (local_sym.st_size != 0) {2352 if (local_sym.st_size != 0) {
2403 const capacity = decl.link.elf.capacity(self.*);2353 const capacity = decl.link.elf.capacity(self);
2404 const need_realloc = code.len > capacity or2354 const need_realloc = code.len > capacity or
2405 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);2355 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
2406 if (need_realloc) {2356 if (need_realloc) {
...@@ -2422,7 +2372,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2422,7 +2372,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2422 local_sym.st_other = 0;2372 local_sym.st_other = 0;
2423 local_sym.st_shndx = shdr_index;2373 local_sym.st_shndx = shdr_index;
2424 // TODO this write could be avoided if no fields of the symbol were changed.2374 // TODO this write could be avoided if no fields of the symbol were changed.
2425 try self.writeSymbol(decl.link.elf.local_sym_index);2375 try self.writeSymbol(decl.link.elf.getSymbolIndex().?);
2426 } else {2376 } else {
2427 const name_str_index = try self.makeString(decl_name);2377 const name_str_index = try self.makeString(decl_name);
2428 const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index);2378 const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index);
...@@ -2439,7 +2389,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2439,7 +2389,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2439 };2389 };
2440 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;2390 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
24412391
2442 try self.writeSymbol(decl.link.elf.local_sym_index);2392 try self.writeSymbol(decl.link.elf.getSymbolIndex().?);
2443 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);2393 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2444 }2394 }
24452395
...@@ -2461,12 +2411,20 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2461,12 +2411,20 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2461 const tracy = trace(@src());2411 const tracy = trace(@src());
2462 defer tracy.end();2412 defer tracy.end();
24632413
2464 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2465 defer code_buffer.deinit();
2466
2467 const decl_index = func.owner_decl;2414 const decl_index = func.owner_decl;
2468 const decl = module.declPtr(decl_index);2415 const decl = module.declPtr(decl_index);
2469 self.freeUnnamedConsts(decl_index);2416 const atom = &decl.link.elf;
2417 try atom.ensureInitialized(self);
2418 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2419 if (gop.found_existing) {
2420 self.freeUnnamedConsts(decl_index);
2421 self.freeRelocationsForTextBlock(atom);
2422 } else {
2423 gop.value_ptr.* = null;
2424 }
2425
2426 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2427 defer code_buffer.deinit();
24702428
2471 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;2429 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
2472 defer if (decl_state) |*ds| ds.deinit();2430 defer if (decl_state) |*ds| ds.deinit();
...@@ -2527,6 +2485,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2527,6 +2485,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
25272485
2528 assert(!self.unnamed_const_atoms.contains(decl_index));2486 assert(!self.unnamed_const_atoms.contains(decl_index));
25292487
2488 const atom = &decl.link.elf;
2489 try atom.ensureInitialized(self);
2490 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2491 if (gop.found_existing) {
2492 self.freeRelocationsForTextBlock(atom);
2493 } else {
2494 gop.value_ptr.* = null;
2495 }
2496
2530 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2497 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2531 defer code_buffer.deinit();2498 defer code_buffer.deinit();
25322499
...@@ -2542,14 +2509,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2542,14 +2509,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2542 }, &code_buffer, .{2509 }, &code_buffer, .{
2543 .dwarf = ds,2510 .dwarf = ds,
2544 }, .{2511 }, .{
2545 .parent_atom_index = decl.link.elf.local_sym_index,2512 .parent_atom_index = decl.link.elf.getSymbolIndex().?,
2546 })2513 })
2547 else2514 else
2548 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{2515 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2549 .ty = decl.ty,2516 .ty = decl.ty,
2550 .val = decl_val,2517 .val = decl_val,
2551 }, &code_buffer, .none, .{2518 }, &code_buffer, .none, .{
2552 .parent_atom_index = decl.link.elf.local_sym_index,2519 .parent_atom_index = decl.link.elf.getSymbolIndex().?,
2553 });2520 });
25542521
2555 const code = switch (res) {2522 const code = switch (res) {
...@@ -2593,6 +2560,8 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2593,6 +2560,8 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2593 const atom = try self.base.allocator.create(TextBlock);2560 const atom = try self.base.allocator.create(TextBlock);
2594 errdefer self.base.allocator.destroy(atom);2561 errdefer self.base.allocator.destroy(atom);
2595 atom.* = TextBlock.empty;2562 atom.* = TextBlock.empty;
2563 // TODO for unnamed consts we don't need GOT offset/entry allocated
2564 try atom.ensureInitialized(self);
2596 try self.managed_atoms.append(self.base.allocator, atom);2565 try self.managed_atoms.append(self.base.allocator, atom);
25972566
2598 const name_str_index = blk: {2567 const name_str_index = blk: {
...@@ -2607,14 +2576,10 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2607,14 +2576,10 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2607 };2576 };
2608 const name = self.getString(name_str_index);2577 const name = self.getString(name_str_index);
26092578
2610 log.debug("allocating symbol indexes for {s}", .{name});
2611 atom.local_sym_index = try self.allocateLocalSymbol();
2612 try self.atom_by_index_table.putNoClobber(self.base.allocator, atom.local_sym_index, atom);
2613
2614 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{2579 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
2615 .none = {},2580 .none = {},
2616 }, .{2581 }, .{
2617 .parent_atom_index = atom.local_sym_index,2582 .parent_atom_index = atom.getSymbolIndex().?,
2618 });2583 });
2619 const code = switch (res) {2584 const code = switch (res) {
2620 .ok => code_buffer.items,2585 .ok => code_buffer.items,
...@@ -2634,7 +2599,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2634,7 +2599,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
26342599
2635 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });2600 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });
26362601
2637 const local_sym = &self.local_symbols.items[atom.local_sym_index];2602 const local_sym = atom.getSymbolPtr(self);
2638 local_sym.* = .{2603 local_sym.* = .{
2639 .st_name = name_str_index,2604 .st_name = name_str_index,
2640 .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT,2605 .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT,
...@@ -2644,14 +2609,14 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2644,14 +2609,14 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2644 .st_size = code.len,2609 .st_size = code.len,
2645 };2610 };
26462611
2647 try self.writeSymbol(atom.local_sym_index);2612 try self.writeSymbol(atom.getSymbolIndex().?);
2648 try unnamed_consts.append(self.base.allocator, atom);2613 try unnamed_consts.append(self.base.allocator, atom);
26492614
2650 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;2615 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;
2651 const file_offset = self.sections.items[shdr_index].sh_offset + section_offset;2616 const file_offset = self.sections.items[shdr_index].sh_offset + section_offset;
2652 try self.base.file.?.pwriteAll(code, file_offset);2617 try self.base.file.?.pwriteAll(code, file_offset);
26532618
2654 return atom.local_sym_index;2619 return atom.getSymbolIndex().?;
2655}2620}
26562621
2657pub fn updateDeclExports(2622pub fn updateDeclExports(
...@@ -2670,16 +2635,19 @@ pub fn updateDeclExports(...@@ -2670,16 +2635,19 @@ pub fn updateDeclExports(
2670 const tracy = trace(@src());2635 const tracy = trace(@src());
2671 defer tracy.end();2636 defer tracy.end();
26722637
2673 try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len);
2674 const decl = module.declPtr(decl_index);2638 const decl = module.declPtr(decl_index);
2675 if (decl.link.elf.local_sym_index == 0) return;2639 const atom = &decl.link.elf;
2676 const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];
26772640
2678 const decl_ptr = self.decls.getPtr(decl_index).?;2641 if (atom.getSymbolIndex() == null) return;
2679 if (decl_ptr.* == null) {2642
2680 decl_ptr.* = try self.getDeclPhdrIndex(decl);2643 const decl_sym = atom.getSymbol(self);
2644 try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len);
2645
2646 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2647 if (!gop.found_existing) {
2648 gop.value_ptr.* = try self.getDeclPhdrIndex(decl);
2681 }2649 }
2682 const phdr_index = decl_ptr.*.?;2650 const phdr_index = gop.value_ptr.*.?;
2683 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;2651 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
26842652
2685 for (exports) |exp| {2653 for (exports) |exp| {
...@@ -3040,7 +3008,7 @@ fn getLDMOption(target: std.Target) ?[]const u8 {...@@ -3040,7 +3008,7 @@ fn getLDMOption(target: std.Target) ?[]const u8 {
3040 }3008 }
3041}3009}
30423010
3043fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {3011pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
3044 return actual_size +| (actual_size / ideal_factor);3012 return actual_size +| (actual_size / ideal_factor);
3045}3013}
30463014
src/link/Elf/Atom.zig created+96
...@@ -0,0 +1,96 @@
1const Atom = @This();
2
3const std = @import("std");
4const assert = std.debug.assert;
5const elf = std.elf;
6
7const Dwarf = @import("../Dwarf.zig");
8const Elf = @import("../Elf.zig");
9
10/// Each decl always gets a local symbol with the fully qualified name.
11/// The vaddr and size are found here directly.
12/// The file offset is found by computing the vaddr offset from the section vaddr
13/// the symbol references, and adding that to the file offset of the section.
14/// If this field is 0, it means the codegen size = 0 and there is no symbol or
15/// offset table entry.
16local_sym_index: u32,
17
18/// This field is undefined for symbols with size = 0.
19offset_table_index: u32,
20
21/// 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`.
23prev: ?*Atom,
24next: ?*Atom,
25
26dbg_info_atom: Dwarf.Atom,
27
28pub const empty = Atom{
29 .local_sym_index = 0,
30 .offset_table_index = undefined,
31 .prev = null,
32 .next = null,
33 .dbg_info_atom = undefined,
34};
35
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 {
44 if (self.local_sym_index == 0) return null;
45 return self.local_sym_index;
46}
47
48pub fn getSymbol(self: Atom, elf_file: *Elf) elf.Elf64_Sym {
49 const sym_index = self.getSymbolIndex().?;
50 return elf_file.local_symbols.items[sym_index];
51}
52
53pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym {
54 const sym_index = self.getSymbolIndex().?;
55 return &elf_file.local_symbols.items[sym_index];
56}
57
58pub fn getName(self: Atom, elf_file: *Elf) []const u8 {
59 const sym = self.getSymbol();
60 return elf_file.getString(sym.st_name);
61}
62
63pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
64 assert(self.getSymbolIndex() != null);
65 const target = elf_file.base.options.target;
66 const ptr_bits = target.cpu.arch.ptrBitWidth();
67 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
68 const got = elf_file.program_headers.items[elf_file.phdr_got_index.?];
69 return got.p_vaddr + self.offset_table_index * ptr_bytes;
70}
71
72/// Returns how much room there is to grow in virtual address space.
73/// File offset relocation happens transparently, so it is not included in
74/// this calculation.
75pub fn capacity(self: Atom, elf_file: *Elf) u64 {
76 const self_sym = self.getSymbol(elf_file);
77 if (self.next) |next| {
78 const next_sym = next.getSymbol(elf_file);
79 return next_sym.st_value - self_sym.st_value;
80 } else {
81 // We are the last block. The capacity is limited only by virtual address space.
82 return std.math.maxInt(u32) - self_sym.st_value;
83 }
84}
85
86pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
87 // No need to keep a free list node for the last block.
88 const next = self.next orelse return false;
89 const self_sym = self.getSymbol(elf_file);
90 const next_sym = next.getSymbol(elf_file);
91 const cap = next_sym.st_value - self_sym.st_value;
92 const ideal_cap = Elf.padToIdeal(self_sym.st_size);
93 if (cap <= ideal_cap) return false;
94 const surplus = cap - ideal_cap;
95 return surplus >= Elf.min_text_capacity;
96}
src/link/MachO.zig+125-148
...@@ -1056,19 +1056,14 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {...@@ -1056,19 +1056,14 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {
1056pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {1056pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
1057 const gpa = self.base.allocator;1057 const gpa = self.base.allocator;
10581058
1059 const sym_index = try self.allocateSymbol();1059 const atom = try gpa.create(Atom);
1060 const atom = blk: {1060 atom.* = Atom.empty;
1061 const atom = try gpa.create(Atom);1061 try atom.ensureInitialized(self);
1062 atom.* = Atom.empty;1062 atom.size = @sizeOf(u64);
1063 atom.sym_index = sym_index;1063 atom.alignment = @alignOf(u64);
1064 atom.size = @sizeOf(u64);
1065 atom.alignment = @alignOf(u64);
1066 break :blk atom;
1067 };
1068 errdefer gpa.destroy(atom);1064 errdefer gpa.destroy(atom);
10691065
1070 try self.managed_atoms.append(gpa, atom);1066 try self.managed_atoms.append(gpa, atom);
1071 try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom);
10721067
1073 const sym = atom.getSymbolPtr(self);1068 const sym = atom.getSymbolPtr(self);
1074 sym.n_type = macho.N_SECT;1069 sym.n_type = macho.N_SECT;
...@@ -1109,15 +1104,11 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {...@@ -1109,15 +1104,11 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
11091104
1110 const gpa = self.base.allocator;1105 const gpa = self.base.allocator;
11111106
1112 const sym_index = try self.allocateSymbol();1107 const atom = try gpa.create(Atom);
1113 const atom = blk: {1108 atom.* = Atom.empty;
1114 const atom = try gpa.create(Atom);1109 try atom.ensureInitialized(self);
1115 atom.* = Atom.empty;1110 atom.size = @sizeOf(u64);
1116 atom.sym_index = sym_index;1111 atom.alignment = @alignOf(u64);
1117 atom.size = @sizeOf(u64);
1118 atom.alignment = @alignOf(u64);
1119 break :blk atom;
1120 };
1121 errdefer gpa.destroy(atom);1112 errdefer gpa.destroy(atom);
11221113
1123 const sym = atom.getSymbolPtr(self);1114 const sym = atom.getSymbolPtr(self);
...@@ -1126,7 +1117,6 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {...@@ -1126,7 +1117,6 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
1126 self.dyld_private_atom = atom;1117 self.dyld_private_atom = atom;
11271118
1128 try self.managed_atoms.append(gpa, atom);1119 try self.managed_atoms.append(gpa, atom);
1129 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
11301120
1131 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));1121 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));
1132 log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value});1122 log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value});
...@@ -1144,18 +1134,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1144,18 +1134,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1144 .aarch64 => 6 * @sizeOf(u32),1134 .aarch64 => 6 * @sizeOf(u32),
1145 else => unreachable,1135 else => unreachable,
1146 };1136 };
1147 const sym_index = try self.allocateSymbol();1137 const atom = try gpa.create(Atom);
1148 const atom = blk: {1138 atom.* = Atom.empty;
1149 const atom = try gpa.create(Atom);1139 try atom.ensureInitialized(self);
1150 atom.* = Atom.empty;1140 atom.size = size;
1151 atom.sym_index = sym_index;1141 atom.alignment = switch (arch) {
1152 atom.size = size;1142 .x86_64 => 1,
1153 atom.alignment = switch (arch) {1143 .aarch64 => @alignOf(u32),
1154 .x86_64 => 1,1144 else => unreachable,
1155 .aarch64 => @alignOf(u32),
1156 else => unreachable,
1157 };
1158 break :blk atom;
1159 };1145 };
1160 errdefer gpa.destroy(atom);1146 errdefer gpa.destroy(atom);
11611147
...@@ -1163,7 +1149,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1163,7 +1149,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1163 sym.n_type = macho.N_SECT;1149 sym.n_type = macho.N_SECT;
1164 sym.n_sect = self.stub_helper_section_index.? + 1;1150 sym.n_sect = self.stub_helper_section_index.? + 1;
11651151
1166 const dyld_private_sym_index = self.dyld_private_atom.?.sym_index;1152 const dyld_private_sym_index = self.dyld_private_atom.?.getSymbolIndex().?;
11671153
1168 const code = try gpa.alloc(u8, size);1154 const code = try gpa.alloc(u8, size);
1169 defer gpa.free(code);1155 defer gpa.free(code);
...@@ -1258,7 +1244,6 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1258,7 +1244,6 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void {
1258 self.stub_helper_preamble_atom = atom;1244 self.stub_helper_preamble_atom = atom;
12591245
1260 try self.managed_atoms.append(gpa, atom);1246 try self.managed_atoms.append(gpa, atom);
1261 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
12621247
1263 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);1248 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1264 log.debug("allocated stub preamble atom at 0x{x}", .{sym.n_value});1249 log.debug("allocated stub preamble atom at 0x{x}", .{sym.n_value});
...@@ -1273,18 +1258,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1273,18 +1258,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
1273 .aarch64 => 3 * @sizeOf(u32),1258 .aarch64 => 3 * @sizeOf(u32),
1274 else => unreachable,1259 else => unreachable,
1275 };1260 };
1276 const sym_index = try self.allocateSymbol();1261 const atom = try gpa.create(Atom);
1277 const atom = blk: {1262 atom.* = Atom.empty;
1278 const atom = try gpa.create(Atom);1263 try atom.ensureInitialized(self);
1279 atom.* = Atom.empty;1264 atom.size = size;
1280 atom.sym_index = sym_index;1265 atom.alignment = switch (arch) {
1281 atom.size = size;1266 .x86_64 => 1,
1282 atom.alignment = switch (arch) {1267 .aarch64 => @alignOf(u32),
1283 .x86_64 => 1,1268 else => unreachable,
1284 .aarch64 => @alignOf(u32),
1285 else => unreachable,
1286 };
1287 break :blk atom;
1288 };1269 };
1289 errdefer gpa.destroy(atom);1270 errdefer gpa.destroy(atom);
12901271
...@@ -1306,7 +1287,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1306,7 +1287,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
13061287
1307 try atom.addRelocation(self, .{1288 try atom.addRelocation(self, .{
1308 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),1289 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
1309 .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null },1290 .target = .{ .sym_index = self.stub_helper_preamble_atom.?.getSymbolIndex().?, .file = null },
1310 .offset = 6,1291 .offset = 6,
1311 .addend = 0,1292 .addend = 0,
1312 .pcrel = true,1293 .pcrel = true,
...@@ -1329,7 +1310,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1329,7 +1310,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
13291310
1330 try atom.addRelocation(self, .{1311 try atom.addRelocation(self, .{
1331 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),1312 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),
1332 .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null },1313 .target = .{ .sym_index = self.stub_helper_preamble_atom.?.getSymbolIndex().?, .file = null },
1333 .offset = 4,1314 .offset = 4,
1334 .addend = 0,1315 .addend = 0,
1335 .pcrel = true,1316 .pcrel = true,
...@@ -1340,7 +1321,6 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1340,7 +1321,6 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
1340 }1321 }
13411322
1342 try self.managed_atoms.append(gpa, atom);1323 try self.managed_atoms.append(gpa, atom);
1343 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
13441324
1345 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);1325 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1346 log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value});1326 log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value});
...@@ -1351,15 +1331,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -1351,15 +1331,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
13511331
1352pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom {1332pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom {
1353 const gpa = self.base.allocator;1333 const gpa = self.base.allocator;
1354 const sym_index = try self.allocateSymbol();1334 const atom = try gpa.create(Atom);
1355 const atom = blk: {1335 atom.* = Atom.empty;
1356 const atom = try gpa.create(Atom);1336 try atom.ensureInitialized(self);
1357 atom.* = Atom.empty;1337 atom.size = @sizeOf(u64);
1358 atom.sym_index = sym_index;1338 atom.alignment = @alignOf(u64);
1359 atom.size = @sizeOf(u64);
1360 atom.alignment = @alignOf(u64);
1361 break :blk atom;
1362 };
1363 errdefer gpa.destroy(atom);1339 errdefer gpa.destroy(atom);
13641340
1365 const sym = atom.getSymbolPtr(self);1341 const sym = atom.getSymbolPtr(self);
...@@ -1385,7 +1361,6 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi...@@ -1385,7 +1361,6 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi
1385 });1361 });
13861362
1387 try self.managed_atoms.append(gpa, atom);1363 try self.managed_atoms.append(gpa, atom);
1388 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
13891364
1390 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));1365 sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64));
1391 log.debug("allocated lazy pointer atom at 0x{x} ({s})", .{ sym.n_value, self.getSymbolName(target) });1366 log.debug("allocated lazy pointer atom at 0x{x} ({s})", .{ sym.n_value, self.getSymbolName(target) });
...@@ -1402,19 +1377,15 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -1402,19 +1377,15 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
1402 .aarch64 => 3 * @sizeOf(u32),1377 .aarch64 => 3 * @sizeOf(u32),
1403 else => unreachable, // unhandled architecture type1378 else => unreachable, // unhandled architecture type
1404 };1379 };
1405 const sym_index = try self.allocateSymbol();1380 const atom = try gpa.create(Atom);
1406 const atom = blk: {1381 atom.* = Atom.empty;
1407 const atom = try gpa.create(Atom);1382 try atom.ensureInitialized(self);
1408 atom.* = Atom.empty;1383 atom.size = size;
1409 atom.sym_index = sym_index;1384 atom.alignment = switch (arch) {
1410 atom.size = size;1385 .x86_64 => 1,
1411 atom.alignment = switch (arch) {1386 .aarch64 => @alignOf(u32),
1412 .x86_64 => 1,1387 else => unreachable, // unhandled architecture type
1413 .aarch64 => @alignOf(u32),
1414 else => unreachable, // unhandled architecture type
14151388
1416 };
1417 break :blk atom;
1418 };1389 };
1419 errdefer gpa.destroy(atom);1390 errdefer gpa.destroy(atom);
14201391
...@@ -1476,7 +1447,6 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -1476,7 +1447,6 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
1476 }1447 }
14771448
1478 try self.managed_atoms.append(gpa, atom);1449 try self.managed_atoms.append(gpa, atom);
1479 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
14801450
1481 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);1451 sym.n_value = try self.allocateAtom(atom, size, atom.alignment);
1482 log.debug("allocated stub atom at 0x{x}", .{sym.n_value});1452 log.debug("allocated stub atom at 0x{x}", .{sym.n_value});
...@@ -1617,9 +1587,9 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {...@@ -1617,9 +1587,9 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void {
16171587
1618 const stub_index = try self.allocateStubEntry(global);1588 const stub_index = try self.allocateStubEntry(global);
1619 const stub_helper_atom = try self.createStubHelperAtom();1589 const stub_helper_atom = try self.createStubHelperAtom();
1620 const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.sym_index, global);1590 const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, global);
1621 const stub_atom = try self.createStubAtom(laptr_atom.sym_index);1591 const stub_atom = try self.createStubAtom(laptr_atom.getSymbolIndex().?);
1622 self.stubs.items[stub_index].sym_index = stub_atom.sym_index;1592 self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
1623 self.markRelocsDirtyByTarget(global);1593 self.markRelocsDirtyByTarget(global);
1624 }1594 }
16251595
...@@ -1717,7 +1687,7 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {...@@ -1717,7 +1687,7 @@ pub fn resolveDyldStubBinder(self: *MachO) !void {
1717 // Add dyld_stub_binder as the final GOT entry.1687 // Add dyld_stub_binder as the final GOT entry.
1718 const got_index = try self.allocateGotEntry(global);1688 const got_index = try self.allocateGotEntry(global);
1719 const got_atom = try self.createGotAtom(global);1689 const got_atom = try self.createGotAtom(global);
1720 self.got_entries.items[got_index].sym_index = got_atom.sym_index;1690 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
17211691
1722 try self.writePtrWidthAtom(got_atom);1692 try self.writePtrWidthAtom(got_atom);
1723}1693}
...@@ -1811,6 +1781,8 @@ pub fn deinit(self: *MachO) void {...@@ -1811,6 +1781,8 @@ pub fn deinit(self: *MachO) void {
1811fn freeAtom(self: *MachO, atom: *Atom) void {1781fn freeAtom(self: *MachO, atom: *Atom) void {
1812 log.debug("freeAtom {*}", .{atom});1782 log.debug("freeAtom {*}", .{atom});
18131783
1784 const gpa = self.base.allocator;
1785
1814 // Remove any relocs and base relocs associated with this Atom1786 // Remove any relocs and base relocs associated with this Atom
1815 self.freeRelocationsForAtom(atom);1787 self.freeRelocationsForAtom(atom);
18161788
...@@ -1850,7 +1822,7 @@ fn freeAtom(self: *MachO, atom: *Atom) void {...@@ -1850,7 +1822,7 @@ fn freeAtom(self: *MachO, atom: *Atom) void {
1850 if (!already_have_free_list_node and prev.freeListEligible(self)) {1822 if (!already_have_free_list_node and prev.freeListEligible(self)) {
1851 // The free list is heuristics, it doesn't have to be perfect, so we can ignore1823 // The free list is heuristics, it doesn't have to be perfect, so we can ignore
1852 // the OOM here.1824 // the OOM here.
1853 free_list.append(self.base.allocator, prev) catch {};1825 free_list.append(gpa, prev) catch {};
1854 }1826 }
1855 } else {1827 } else {
1856 atom.prev = null;1828 atom.prev = null;
...@@ -1862,6 +1834,33 @@ fn freeAtom(self: *MachO, atom: *Atom) void {...@@ -1862,6 +1834,33 @@ fn freeAtom(self: *MachO, atom: *Atom) void {
1862 atom.next = null;1834 atom.next = null;
1863 }1835 }
18641836
1837 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
1838 const sym_index = atom.getSymbolIndex().?;
1839
1840 self.locals_free_list.append(gpa, sym_index) catch {};
1841
1842 // Try freeing GOT atom if this decl had one
1843 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1844 if (self.got_entries_table.get(got_target)) |got_index| {
1845 self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {};
1846 self.got_entries.items[got_index] = .{
1847 .target = .{ .sym_index = 0, .file = null },
1848 .sym_index = 0,
1849 };
1850 _ = self.got_entries_table.remove(got_target);
1851
1852 if (self.d_sym) |*d_sym| {
1853 d_sym.swapRemoveRelocs(sym_index);
1854 }
1855
1856 log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index });
1857 }
1858
1859 self.locals.items[sym_index].n_type = 0;
1860 _ = self.atom_by_index_table.remove(sym_index);
1861 log.debug(" adding local symbol index {d} to free list", .{sym_index});
1862 atom.sym_index = 0;
1863
1865 if (self.d_sym) |*d_sym| {1864 if (self.d_sym) |*d_sym| {
1866 d_sym.dwarf.freeAtom(&atom.dbg_info_atom);1865 d_sym.dwarf.freeAtom(&atom.dbg_info_atom);
1867 }1866 }
...@@ -1883,7 +1882,7 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64...@@ -1883,7 +1882,7 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64
1883 return self.allocateAtom(atom, new_atom_size, alignment);1882 return self.allocateAtom(atom, new_atom_size, alignment);
1884}1883}
18851884
1886fn allocateSymbol(self: *MachO) !u32 {1885pub fn allocateSymbol(self: *MachO) !u32 {
1887 try self.locals.ensureUnusedCapacity(self.base.allocator, 1);1886 try self.locals.ensureUnusedCapacity(self.base.allocator, 1);
18881887
1889 const index = blk: {1888 const index = blk: {
...@@ -1975,16 +1974,6 @@ pub fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 {...@@ -1975,16 +1974,6 @@ pub fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 {
1975 return index;1974 return index;
1976}1975}
19771976
1978pub fn allocateDeclIndexes(self: *MachO, decl_index: Module.Decl.Index) !void {
1979 if (self.llvm_object) |_| return;
1980 const decl = self.base.options.module.?.declPtr(decl_index);
1981 if (decl.link.macho.sym_index != 0) return;
1982
1983 decl.link.macho.sym_index = try self.allocateSymbol();
1984 try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.macho.sym_index, &decl.link.macho);
1985 try self.decls.putNoClobber(self.base.allocator, decl_index, null);
1986}
1987
1988pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {1977pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
1989 if (build_options.skip_non_native and builtin.object_format != .macho) {1978 if (build_options.skip_non_native and builtin.object_format != .macho) {
1990 @panic("Attempted to compile for object format that was disabled by build configuration");1979 @panic("Attempted to compile for object format that was disabled by build configuration");
...@@ -1997,8 +1986,15 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -1997,8 +1986,15 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
19971986
1998 const decl_index = func.owner_decl;1987 const decl_index = func.owner_decl;
1999 const decl = module.declPtr(decl_index);1988 const decl = module.declPtr(decl_index);
2000 self.freeUnnamedConsts(decl_index);1989 const atom = &decl.link.macho;
2001 self.freeRelocationsForAtom(&decl.link.macho);1990 try atom.ensureInitialized(self);
1991 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1992 if (gop.found_existing) {
1993 self.freeUnnamedConsts(decl_index);
1994 self.freeRelocationsForAtom(atom);
1995 } else {
1996 gop.value_ptr.* = null;
1997 }
20021998
2003 var code_buffer = std.ArrayList(u8).init(self.base.allocator);1999 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2004 defer code_buffer.deinit();2000 defer code_buffer.deinit();
...@@ -2072,14 +2068,11 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -2072,14 +2068,11 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
2072 const atom = try gpa.create(Atom);2068 const atom = try gpa.create(Atom);
2073 errdefer gpa.destroy(atom);2069 errdefer gpa.destroy(atom);
2074 atom.* = Atom.empty;2070 atom.* = Atom.empty;
20752071 try atom.ensureInitialized(self);
2076 atom.sym_index = try self.allocateSymbol();
2077
2078 try self.managed_atoms.append(gpa, atom);2072 try self.managed_atoms.append(gpa, atom);
2079 try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom);
20802073
2081 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{2074 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{
2082 .parent_atom_index = atom.sym_index,2075 .parent_atom_index = atom.getSymbolIndex().?,
2083 });2076 });
2084 const code = switch (res) {2077 const code = switch (res) {
2085 .ok => code_buffer.items,2078 .ok => code_buffer.items,
...@@ -2111,7 +2104,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -2111,7 +2104,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
21112104
2112 try self.writeAtom(atom, code);2105 try self.writeAtom(atom, code);
21132106
2114 return atom.sym_index;2107 return atom.getSymbolIndex().?;
2115}2108}
21162109
2117pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void {2110pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void {
...@@ -2136,7 +2129,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2136,7 +2129,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2136 }2129 }
2137 }2130 }
21382131
2139 self.freeRelocationsForAtom(&decl.link.macho);2132 const atom = &decl.link.macho;
2133 try atom.ensureInitialized(self);
2134 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2135 if (gop.found_existing) {
2136 self.freeRelocationsForAtom(atom);
2137 } else {
2138 gop.value_ptr.* = null;
2139 }
21402140
2141 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2141 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2142 defer code_buffer.deinit();2142 defer code_buffer.deinit();
...@@ -2155,14 +2155,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2155,14 +2155,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2155 }, &code_buffer, .{2155 }, &code_buffer, .{
2156 .dwarf = ds,2156 .dwarf = ds,
2157 }, .{2157 }, .{
2158 .parent_atom_index = decl.link.macho.sym_index,2158 .parent_atom_index = decl.link.macho.getSymbolIndex().?,
2159 })2159 })
2160 else2160 else
2161 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{2161 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2162 .ty = decl.ty,2162 .ty = decl.ty,
2163 .val = decl_val,2163 .val = decl_val,
2164 }, &code_buffer, .none, .{2164 }, &code_buffer, .none, .{
2165 .parent_atom_index = decl.link.macho.sym_index,2165 .parent_atom_index = decl.link.macho.getSymbolIndex().?,
2166 });2166 });
21672167
2168 const code = switch (res) {2168 const code = switch (res) {
...@@ -2337,12 +2337,12 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)...@@ -2337,12 +2337,12 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
2337 const decl = mod.declPtr(decl_index);2337 const decl = mod.declPtr(decl_index);
23382338
2339 const required_alignment = decl.getAlignment(self.base.options.target);2339 const required_alignment = decl.getAlignment(self.base.options.target);
2340 assert(decl.link.macho.sym_index != 0); // Caller forgot to call allocateDeclIndexes()
23412340
2342 const sym_name = try decl.getFullyQualifiedName(mod);2341 const sym_name = try decl.getFullyQualifiedName(mod);
2343 defer self.base.allocator.free(sym_name);2342 defer self.base.allocator.free(sym_name);
23442343
2345 const atom = &decl.link.macho;2344 const atom = &decl.link.macho;
2345 const sym_index = atom.getSymbolIndex().?; // Atom was not initialized
2346 const decl_ptr = self.decls.getPtr(decl_index).?;2346 const decl_ptr = self.decls.getPtr(decl_index).?;
2347 if (decl_ptr.* == null) {2347 if (decl_ptr.* == null) {
2348 decl_ptr.* = self.getDeclOutputSection(decl);2348 decl_ptr.* = self.getDeclOutputSection(decl);
...@@ -2368,7 +2368,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)...@@ -2368,7 +2368,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
2368 if (vaddr != sym.n_value) {2368 if (vaddr != sym.n_value) {
2369 sym.n_value = vaddr;2369 sym.n_value = vaddr;
2370 log.debug(" (updating GOT entry)", .{});2370 log.debug(" (updating GOT entry)", .{});
2371 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };2371 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2372 const got_atom = self.getGotAtomForSymbol(got_target).?;2372 const got_atom = self.getGotAtomForSymbol(got_target).?;
2373 self.markRelocsDirtyByTarget(got_target);2373 self.markRelocsDirtyByTarget(got_target);
2374 try self.writePtrWidthAtom(got_atom);2374 try self.writePtrWidthAtom(got_atom);
...@@ -2399,10 +2399,10 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)...@@ -2399,10 +2399,10 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
2399 atom.size = code_len;2399 atom.size = code_len;
2400 sym.n_value = vaddr;2400 sym.n_value = vaddr;
24012401
2402 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };2402 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2403 const got_index = try self.allocateGotEntry(got_target);2403 const got_index = try self.allocateGotEntry(got_target);
2404 const got_atom = try self.createGotAtom(got_target);2404 const got_atom = try self.createGotAtom(got_target);
2405 self.got_entries.items[got_index].sym_index = got_atom.sym_index;2405 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
2406 try self.writePtrWidthAtom(got_atom);2406 try self.writePtrWidthAtom(got_atom);
2407 }2407 }
24082408
...@@ -2438,8 +2438,16 @@ pub fn updateDeclExports(...@@ -2438,8 +2438,16 @@ pub fn updateDeclExports(
2438 const gpa = self.base.allocator;2438 const gpa = self.base.allocator;
24392439
2440 const decl = module.declPtr(decl_index);2440 const decl = module.declPtr(decl_index);
2441 if (decl.link.macho.sym_index == 0) return;2441 const atom = &decl.link.macho;
2442 const decl_sym = decl.link.macho.getSymbol(self);2442
2443 if (atom.getSymbolIndex() == null) return;
2444
2445 const gop = try self.decls.getOrPut(gpa, decl_index);
2446 if (!gop.found_existing) {
2447 gop.value_ptr.* = self.getDeclOutputSection(decl);
2448 }
2449
2450 const decl_sym = atom.getSymbol(self);
24432451
2444 for (exports) |exp| {2452 for (exports) |exp| {
2445 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name});2453 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name});
...@@ -2573,11 +2581,6 @@ fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {...@@ -2573,11 +2581,6 @@ fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {
2573 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;2581 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
2574 for (unnamed_consts.items) |atom| {2582 for (unnamed_consts.items) |atom| {
2575 self.freeAtom(atom);2583 self.freeAtom(atom);
2576 self.locals_free_list.append(gpa, atom.sym_index) catch {};
2577 self.locals.items[atom.sym_index].n_type = 0;
2578 _ = self.atom_by_index_table.remove(atom.sym_index);
2579 log.debug(" adding local symbol index {d} to free list", .{atom.sym_index});
2580 atom.sym_index = 0;
2581 }2584 }
2582 unnamed_consts.clearAndFree(gpa);2585 unnamed_consts.clearAndFree(gpa);
2583}2586}
...@@ -2591,39 +2594,11 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {...@@ -2591,39 +2594,11 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {
25912594
2592 log.debug("freeDecl {*}", .{decl});2595 log.debug("freeDecl {*}", .{decl});
25932596
2594 const kv = self.decls.fetchSwapRemove(decl_index);2597 if (self.decls.fetchSwapRemove(decl_index)) |kv| {
2595 if (kv.?.value) |_| {2598 if (kv.value) |_| {
2596 self.freeAtom(&decl.link.macho);2599 self.freeAtom(&decl.link.macho);
2597 self.freeUnnamedConsts(decl_index);2600 self.freeUnnamedConsts(decl_index);
2598 }
2599
2600 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2601 const gpa = self.base.allocator;
2602 const sym_index = decl.link.macho.sym_index;
2603 if (sym_index != 0) {
2604 self.locals_free_list.append(gpa, sym_index) catch {};
2605
2606 // Try freeing GOT atom if this decl had one
2607 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2608 if (self.got_entries_table.get(got_target)) |got_index| {
2609 self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {};
2610 self.got_entries.items[got_index] = .{
2611 .target = .{ .sym_index = 0, .file = null },
2612 .sym_index = 0,
2613 };
2614 _ = self.got_entries_table.remove(got_target);
2615
2616 if (self.d_sym) |*d_sym| {
2617 d_sym.swapRemoveRelocs(sym_index);
2618 }
2619
2620 log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index });
2621 }2601 }
2622
2623 self.locals.items[sym_index].n_type = 0;
2624 _ = self.atom_by_index_table.remove(sym_index);
2625 log.debug(" adding local symbol index {d} to free list", .{sym_index});
2626 decl.link.macho.sym_index = 0;
2627 }2602 }
26282603
2629 if (self.d_sym) |*d_sym| {2604 if (self.d_sym) |*d_sym| {
...@@ -2636,7 +2611,9 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -2636,7 +2611,9 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
2636 const decl = mod.declPtr(decl_index);2611 const decl = mod.declPtr(decl_index);
26372612
2638 assert(self.llvm_object == null);2613 assert(self.llvm_object == null);
2639 assert(decl.link.macho.sym_index != 0);2614
2615 try decl.link.macho.ensureInitialized(self);
2616 const sym_index = decl.link.macho.getSymbolIndex().?;
26402617
2641 const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;2618 const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
2642 try atom.addRelocation(self, .{2619 try atom.addRelocation(self, .{
...@@ -2645,7 +2622,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -2645,7 +2622,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
2645 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),2622 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
2646 else => unreachable,2623 else => unreachable,
2647 },2624 },
2648 .target = .{ .sym_index = decl.link.macho.sym_index, .file = null },2625 .target = .{ .sym_index = sym_index, .file = null },
2649 .offset = @intCast(u32, reloc_info.offset),2626 .offset = @intCast(u32, reloc_info.offset),
2650 .addend = reloc_info.addend,2627 .addend = reloc_info.addend,
2651 .pcrel = false,2628 .pcrel = false,
...@@ -3179,7 +3156,7 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {...@@ -3179,7 +3156,7 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {
3179 const slice = self.sections.slice();3156 const slice = self.sections.slice();
31803157
3181 for (self.rebases.keys()) |atom, i| {3158 for (self.rebases.keys()) |atom, i| {
3182 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });3159 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });
31833160
3184 const sym = atom.getSymbol(self);3161 const sym = atom.getSymbol(self);
3185 const segment_index = slice.items(.segment_index)[sym.n_sect - 1];3162 const segment_index = slice.items(.segment_index)[sym.n_sect - 1];
...@@ -3208,7 +3185,7 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {...@@ -3208,7 +3185,7 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {
3208 const slice = self.sections.slice();3185 const slice = self.sections.slice();
32093186
3210 for (raw_bindings.keys()) |atom, i| {3187 for (raw_bindings.keys()) |atom, i| {
3211 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });3188 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });
32123189
3213 const sym = atom.getSymbol(self);3190 const sym = atom.getSymbol(self);
3214 const segment_index = slice.items(.segment_index)[sym.n_sect - 1];3191 const segment_index = slice.items(.segment_index)[sym.n_sect - 1];
...@@ -4277,8 +4254,8 @@ pub fn logAtoms(self: *MachO) void {...@@ -4277,8 +4254,8 @@ pub fn logAtoms(self: *MachO) void {
4277pub fn logAtom(self: *MachO, atom: *const Atom) void {4254pub fn logAtom(self: *MachO, atom: *const Atom) void {
4278 const sym = atom.getSymbol(self);4255 const sym = atom.getSymbol(self);
4279 const sym_name = atom.getName(self);4256 const sym_name = atom.getName(self);
4280 log.debug(" ATOM(%{d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{4257 log.debug(" ATOM(%{?d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{
4281 atom.sym_index,4258 atom.getSymbolIndex(),
4282 sym_name,4259 sym_name,
4283 sym.n_value,4260 sym.n_value,
4284 atom.size,4261 atom.size,
src/link/MachO/Atom.zig+22-8
...@@ -64,6 +64,17 @@ pub const empty = Atom{...@@ -64,6 +64,17 @@ pub const empty = Atom{
64 .dbg_info_atom = undefined,64 .dbg_info_atom = undefined,
65};65};
6666
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 {
74 if (self.sym_index == 0) return null;
75 return self.sym_index;
76}
77
67/// Returns symbol referencing this atom.78/// Returns symbol referencing this atom.
68pub fn getSymbol(self: Atom, macho_file: *MachO) macho.nlist_64 {79pub fn getSymbol(self: Atom, macho_file: *MachO) macho.nlist_64 {
69 return self.getSymbolPtr(macho_file).*;80 return self.getSymbolPtr(macho_file).*;
...@@ -71,20 +82,23 @@ pub fn getSymbol(self: Atom, macho_file: *MachO) macho.nlist_64 {...@@ -71,20 +82,23 @@ pub fn getSymbol(self: Atom, macho_file: *MachO) macho.nlist_64 {
7182
72/// Returns pointer-to-symbol referencing this atom.83/// Returns pointer-to-symbol referencing this atom.
73pub fn getSymbolPtr(self: Atom, macho_file: *MachO) *macho.nlist_64 {84pub fn getSymbolPtr(self: Atom, macho_file: *MachO) *macho.nlist_64 {
85 const sym_index = self.getSymbolIndex().?;
74 return macho_file.getSymbolPtr(.{86 return macho_file.getSymbolPtr(.{
75 .sym_index = self.sym_index,87 .sym_index = sym_index,
76 .file = self.file,88 .file = self.file,
77 });89 });
78}90}
7991
80pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {92pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {
81 return .{ .sym_index = self.sym_index, .file = self.file };93 const sym_index = self.getSymbolIndex().?;
94 return .{ .sym_index = sym_index, .file = self.file };
82}95}
8396
84/// Returns the name of this atom.97/// Returns the name of this atom.
85pub fn getName(self: Atom, macho_file: *MachO) []const u8 {98pub fn getName(self: Atom, macho_file: *MachO) []const u8 {
99 const sym_index = self.getSymbolIndex().?;
86 return macho_file.getSymbolName(.{100 return macho_file.getSymbolName(.{
87 .sym_index = self.sym_index,101 .sym_index = sym_index,
88 .file = self.file,102 .file = self.file,
89 });103 });
90}104}
...@@ -144,7 +158,7 @@ pub fn addRelocations(...@@ -144,7 +158,7 @@ pub fn addRelocations(
144158
145pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void {159pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void {
146 const gpa = macho_file.base.allocator;160 const gpa = macho_file.base.allocator;
147 log.debug(" (adding rebase at offset 0x{x} in %{d})", .{ offset, self.sym_index });161 log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, self.getSymbolIndex() });
148 const gop = try macho_file.rebases.getOrPut(gpa, self);162 const gop = try macho_file.rebases.getOrPut(gpa, self);
149 if (!gop.found_existing) {163 if (!gop.found_existing) {
150 gop.value_ptr.* = .{};164 gop.value_ptr.* = .{};
...@@ -154,10 +168,10 @@ pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void {...@@ -154,10 +168,10 @@ pub fn addRebase(self: *Atom, macho_file: *MachO, offset: u32) !void {
154168
155pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {169pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {
156 const gpa = macho_file.base.allocator;170 const gpa = macho_file.base.allocator;
157 log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{d})", .{171 log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{?d})", .{
158 macho_file.getSymbolName(binding.target),172 macho_file.getSymbolName(binding.target),
159 binding.offset,173 binding.offset,
160 self.sym_index,174 self.getSymbolIndex(),
161 });175 });
162 const gop = try macho_file.bindings.getOrPut(gpa, self);176 const gop = try macho_file.bindings.getOrPut(gpa, self);
163 if (!gop.found_existing) {177 if (!gop.found_existing) {
...@@ -168,10 +182,10 @@ pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {...@@ -168,10 +182,10 @@ pub fn addBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {
168182
169pub fn addLazyBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {183pub fn addLazyBinding(self: *Atom, macho_file: *MachO, binding: Binding) !void {
170 const gpa = macho_file.base.allocator;184 const gpa = macho_file.base.allocator;
171 log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{d})", .{185 log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{?d})", .{
172 macho_file.getSymbolName(binding.target),186 macho_file.getSymbolName(binding.target),
173 binding.offset,187 binding.offset,
174 self.sym_index,188 self.getSymbolIndex(),
175 });189 });
176 const gop = try macho_file.lazy_bindings.getOrPut(gpa, self);190 const gop = try macho_file.lazy_bindings.getOrPut(gpa, self);
177 if (!gop.found_existing) {191 if (!gop.found_existing) {
src/link/Plan9.zig+2-7
...@@ -424,7 +424,7 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void {...@@ -424,7 +424,7 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void {
424 // write the internal linker metadata424 // write the internal linker metadata
425 decl.link.plan9.type = sym_t;425 decl.link.plan9.type = sym_t;
426 // write the symbol426 // write the symbol
427 // we already have the got index because that got allocated in allocateDeclIndexes427 // we already have the got index
428 const sym: aout.Sym = .{428 const sym: aout.Sym = .{
429 .value = undefined, // the value of stuff gets filled in in flushModule429 .value = undefined, // the value of stuff gets filled in in flushModule
430 .type = decl.link.plan9.type,430 .type = decl.link.plan9.type,
...@@ -737,7 +737,7 @@ fn addDeclExports(...@@ -737,7 +737,7 @@ fn addDeclExports(
737737
738pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {738pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void {
739 // TODO audit the lifetimes of decls table entries. It's possible to get739 // TODO audit the lifetimes of decls table entries. It's possible to get
740 // allocateDeclIndexes and then freeDecl without any updateDecl in between.740 // freeDecl without any updateDecl in between.
741 // However that is planned to change, see the TODO comment in Module.zig741 // However that is planned to change, see the TODO comment in Module.zig
742 // in the deleteUnusedDecl function.742 // in the deleteUnusedDecl function.
743 const mod = self.base.options.module.?;743 const mod = self.base.options.module.?;
...@@ -959,11 +959,6 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -959,11 +959,6 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
959 }959 }
960}960}
961961
962/// this will be removed, moved to updateFinish
963pub fn allocateDeclIndexes(self: *Plan9, decl_index: Module.Decl.Index) !void {
964 _ = self;
965 _ = decl_index;
966}
967/// Must be called only after a successful call to `updateDecl`.962/// Must be called only after a successful call to `updateDecl`.
968pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl: *const Module.Decl) !void {963pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl: *const Module.Decl) !void {
969 _ = self;964 _ = self;
src/link/Wasm.zig+30-40
...@@ -986,31 +986,23 @@ pub fn deinit(wasm: *Wasm) void {...@@ -986,31 +986,23 @@ pub fn deinit(wasm: *Wasm) void {
986 }986 }
987}987}
988988
989pub fn allocateDeclIndexes(wasm: *Wasm, decl_index: Module.Decl.Index) !void {989/// Allocates a new symbol and returns its index.
990 if (wasm.llvm_object) |_| return;990/// Will re-use slots when a symbol was freed at an earlier stage.
991 const decl = wasm.base.options.module.?.declPtr(decl_index);991pub fn allocateSymbol(wasm: *Wasm) !u32 {
992 if (decl.link.wasm.sym_index != 0) return;
993
994 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);992 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);
995 try wasm.decls.putNoClobber(wasm.base.allocator, decl_index, {});
996
997 const atom = &decl.link.wasm;
998
999 var symbol: Symbol = .{993 var symbol: Symbol = .{
1000 .name = undefined, // will be set after updateDecl994 .name = undefined, // will be set after updateDecl
1001 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),995 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1002 .tag = undefined, // will be set after updateDecl996 .tag = undefined, // will be set after updateDecl
1003 .index = undefined, // will be set after updateDecl997 .index = undefined, // will be set after updateDecl
1004 };998 };
1005
1006 if (wasm.symbols_free_list.popOrNull()) |index| {999 if (wasm.symbols_free_list.popOrNull()) |index| {
1007 atom.sym_index = index;
1008 wasm.symbols.items[index] = symbol;1000 wasm.symbols.items[index] = symbol;
1009 } else {1001 return index;
1010 atom.sym_index = @intCast(u32, wasm.symbols.items.len);
1011 wasm.symbols.appendAssumeCapacity(symbol);
1012 }1002 }
1013 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom);1003 const index = @intCast(u32, wasm.symbols.items.len);
1004 wasm.symbols.appendAssumeCapacity(symbol);
1005 return index;
1014}1006}
10151007
1016pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {1008pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
...@@ -1026,9 +1018,12 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes...@@ -1026,9 +1018,12 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
10261018
1027 const decl_index = func.owner_decl;1019 const decl_index = func.owner_decl;
1028 const decl = mod.declPtr(decl_index);1020 const decl = mod.declPtr(decl_index);
1029 assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes()1021 const atom = &decl.link.wasm;
10301022 try atom.ensureInitialized(wasm);
1031 decl.link.wasm.clear();1023 const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
1024 if (gop.found_existing) {
1025 atom.clear();
1026 } else gop.value_ptr.* = {};
10321027
1033 var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;1028 var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;
1034 defer if (decl_state) |*ds| ds.deinit();1029 defer if (decl_state) |*ds| ds.deinit();
...@@ -1083,16 +1078,19 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi...@@ -1083,16 +1078,19 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
1083 defer tracy.end();1078 defer tracy.end();
10841079
1085 const decl = mod.declPtr(decl_index);1080 const decl = mod.declPtr(decl_index);
1086 assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes()
1087
1088 decl.link.wasm.clear();
1089
1090 if (decl.val.castTag(.function)) |_| {1081 if (decl.val.castTag(.function)) |_| {
1091 return;1082 return;
1092 } else if (decl.val.castTag(.extern_fn)) |_| {1083 } else if (decl.val.castTag(.extern_fn)) |_| {
1093 return;1084 return;
1094 }1085 }
10951086
1087 const atom = &decl.link.wasm;
1088 try atom.ensureInitialized(wasm);
1089 const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
1090 if (gop.found_existing) {
1091 atom.clear();
1092 } else gop.value_ptr.* = {};
1093
1096 if (decl.isExtern()) {1094 if (decl.isExtern()) {
1097 const variable = decl.getVariable().?;1095 const variable = decl.getVariable().?;
1098 const name = mem.sliceTo(decl.name, 0);1096 const name = mem.sliceTo(decl.name, 0);
...@@ -1148,8 +1146,8 @@ fn finishUpdateDecl(wasm: *Wasm, decl: *Module.Decl, code: []const u8) !void {...@@ -1148,8 +1146,8 @@ fn finishUpdateDecl(wasm: *Wasm, decl: *Module.Decl, code: []const u8) !void {
1148 try atom.code.appendSlice(wasm.base.allocator, code);1146 try atom.code.appendSlice(wasm.base.allocator, code);
1149 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});1147 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});
11501148
1151 if (code.len == 0) return;
1152 atom.size = @intCast(u32, code.len);1149 atom.size = @intCast(u32, code.len);
1150 if (code.len == 0) return;
1153 atom.alignment = decl.ty.abiAlignment(wasm.base.options.target);1151 atom.alignment = decl.ty.abiAlignment(wasm.base.options.target);
1154}1152}
11551153
...@@ -1211,28 +1209,19 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1211,28 +1209,19 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1211 defer wasm.base.allocator.free(fqdn);1209 defer wasm.base.allocator.free(fqdn);
1212 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index });1210 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index });
1213 defer wasm.base.allocator.free(name);1211 defer wasm.base.allocator.free(name);
1214 var symbol: Symbol = .{
1215 .name = try wasm.string_table.put(wasm.base.allocator, name),
1216 .flags = 0,
1217 .tag = .data,
1218 .index = undefined,
1219 };
1220 symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
12211212
1222 const atom = try decl.link.wasm.locals.addOne(wasm.base.allocator);1213 const atom = try decl.link.wasm.locals.addOne(wasm.base.allocator);
1223 atom.* = Atom.empty;1214 atom.* = Atom.empty;
1215 try atom.ensureInitialized(wasm);
1224 atom.alignment = tv.ty.abiAlignment(wasm.base.options.target);1216 atom.alignment = tv.ty.abiAlignment(wasm.base.options.target);
1225 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);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 };
12261223
1227 if (wasm.symbols_free_list.popOrNull()) |index| {
1228 atom.sym_index = index;
1229 wasm.symbols.items[index] = symbol;
1230 } else {
1231 atom.sym_index = @intCast(u32, wasm.symbols.items.len);
1232 wasm.symbols.appendAssumeCapacity(symbol);
1233 }
1234 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});1224 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});
1235 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom);
12361225
1237 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);1226 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
1238 defer value_bytes.deinit();1227 defer value_bytes.deinit();
...@@ -1304,8 +1293,8 @@ pub fn getDeclVAddr(...@@ -1304,8 +1293,8 @@ pub fn getDeclVAddr(
1304) !u64 {1293) !u64 {
1305 const mod = wasm.base.options.module.?;1294 const mod = wasm.base.options.module.?;
1306 const decl = mod.declPtr(decl_index);1295 const decl = mod.declPtr(decl_index);
1296 try decl.link.wasm.ensureInitialized(wasm);
1307 const target_symbol_index = decl.link.wasm.sym_index;1297 const target_symbol_index = decl.link.wasm.sym_index;
1308 assert(target_symbol_index != 0);
1309 assert(reloc_info.parent_atom_index != 0);1298 assert(reloc_info.parent_atom_index != 0);
1310 const atom = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;1299 const atom = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
1311 const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;1300 const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;
...@@ -1363,6 +1352,7 @@ pub fn updateDeclExports(...@@ -1363,6 +1352,7 @@ pub fn updateDeclExports(
1363 }1352 }
13641353
1365 const decl = mod.declPtr(decl_index);1354 const decl = mod.declPtr(decl_index);
1355 if (decl.link.wasm.getSymbolIndex() == null) return; // unititialized
13661356
1367 for (exports) |exp| {1357 for (exports) |exp| {
1368 if (exp.options.section) |section| {1358 if (exp.options.section) |section| {
src/link/Wasm/Atom.zig+11
...@@ -95,6 +95,17 @@ pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {...@@ -95,6 +95,17 @@ pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
95 return .{ .file = atom.file, .index = atom.sym_index };95 return .{ .file = atom.file, .index = atom.sym_index };
96}96}
9797
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 {
105 if (atom.sym_index == 0) return null;
106 return atom.sym_index;
107}
108
98/// Returns the virtual address of the `Atom`. This is the address starting109/// Returns the virtual address of the `Atom`. This is the address starting
99/// from the first entry within a section.110/// from the first entry within a section.
100pub fn getVA(atom: Atom, wasm: *const Wasm, symbol: *const Symbol) u32 {111pub fn getVA(atom: Atom, wasm: *const Wasm, symbol: *const Symbol) u32 {