authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-01-26 13:17:38+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-01-26 14:29:14+01:00
loge1b9800ffa74a637e2b0a6356249c2c37228ec01
tree9a239b77750b0216e8e5fe24ea0c930ebf5943ca
parentfb8d754a4bf823b66bcf3fa281c469af8be6f923

elf: migrate to new non-allocateDeclIndexes API


10 files changed, 175 insertions(+), 163 deletions(-)

src/Module.zig+1-1
...@@ -5324,7 +5324,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void {...@@ -5324,7 +5324,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void {
5324 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we5324 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we
5325 // must call `freeDecl` in the linker backend now.5325 // must call `freeDecl` in the linker backend now.
5326 switch (mod.comp.bin_file.tag) {5326 switch (mod.comp.bin_file.tag) {
5327 .macho, .c => {}, // this linker backend has already migrated to the new API5327 .elf, .macho, .c => {}, // this linker backend has already migrated to the new API
5328 else => if (decl.has_tv) {5328 else => if (decl.has_tv) {
5329 if (decl.ty.isFnOrHasRuntimeBits()) {5329 if (decl.ty.isFnOrHasRuntimeBits()) {
5330 mod.comp.bin_file.freeDecl(decl_index);5330 mod.comp.bin_file.freeDecl(decl_index);
src/arch/aarch64/CodeGen.zig+4-13
...@@ -4307,12 +4307,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4307,12 +4307,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4307 const fn_owner_decl = mod.declPtr(func.owner_decl);4307 const fn_owner_decl = mod.declPtr(func.owner_decl);
43084308
4309 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4309 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4310 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4310 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4311 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4311 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4312 const got_addr = blk: {
4313 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4314 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
4315 };
4316 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });4312 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
4317 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4313 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4318 try fn_owner_decl.link.macho.ensureInitialized(macho_file);4314 try fn_owner_decl.link.macho.ensureInitialized(macho_file);
...@@ -6125,20 +6121,15 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6125,20 +6121,15 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6125 mod.markDeclAlive(decl);6121 mod.markDeclAlive(decl);
61266122
6127 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6123 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6128 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];6124 try decl.link.elf.ensureInitialized(elf_file);
6129 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;6125 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6130 return MCValue{ .memory = got_addr };
6131 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {6126 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6132 // Because MachO is PIE-always-on, we defer memory address resolution until
6133 // the linker has enough info to perform relocations.
6134 try decl.link.macho.ensureInitialized(macho_file);6127 try decl.link.macho.ensureInitialized(macho_file);
6135 return MCValue{ .linker_load = .{6128 return MCValue{ .linker_load = .{
6136 .type = .got,6129 .type = .got,
6137 .sym_index = decl.link.macho.getSymbolIndex().?,6130 .sym_index = decl.link.macho.getSymbolIndex().?,
6138 } };6131 } };
6139 } else if (self.bin_file.cast(link.File.Coff)) |_| {6132 } else if (self.bin_file.cast(link.File.Coff)) |_| {
6140 // Because COFF is PIE-always-on, we defer memory address resolution until
6141 // the linker has enough info to perform relocations.
6142 assert(decl.link.coff.sym_index != 0);6133 assert(decl.link.coff.sym_index != 0);
6143 return MCValue{ .linker_load = .{6134 return MCValue{ .linker_load = .{
6144 .type = .got,6135 .type = .got,
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/x86_64/CodeGen.zig+5-10
...@@ -3998,16 +3998,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -3998,16 +3998,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
3998 const fn_owner_decl = mod.declPtr(func.owner_decl);3998 const fn_owner_decl = mod.declPtr(func.owner_decl);
39993999
4000 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4000 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4001 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4001 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4002 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4002 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4003 const got_addr = blk: {
4004 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4005 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
4006 };
4007 _ = try self.addInst(.{4003 _ = try self.addInst(.{
4008 .tag = .call,4004 .tag = .call,
4009 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),4005 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4010 .data = .{ .imm = @truncate(u32, got_addr) },4006 .data = .{ .imm = got_addr },
4011 });4007 });
4012 } else if (self.bin_file.cast(link.File.Coff)) |_| {4008 } else if (self.bin_file.cast(link.File.Coff)) |_| {
4013 try self.genSetReg(Type.initTag(.usize), .rax, .{4009 try self.genSetReg(Type.initTag(.usize), .rax, .{
...@@ -6721,9 +6717,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6721,9 +6717,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6721 module.markDeclAlive(decl);6717 module.markDeclAlive(decl);
67226718
6723 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6719 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6724 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];6720 try decl.link.elf.ensureInitialized(elf_file);
6725 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;6721 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6726 return MCValue{ .memory = got_addr };
6727 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {6722 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6728 try decl.link.macho.ensureInitialized(macho_file);6723 try decl.link.macho.ensureInitialized(macho_file);
6729 return MCValue{ .linker_load = .{6724 return MCValue{ .linker_load = .{
src/link.zig+1-1
...@@ -616,7 +616,7 @@ pub const File = struct {...@@ -616,7 +616,7 @@ pub const File = struct {
616 }616 }
617 switch (base.tag) {617 switch (base.tag) {
618 .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl_index),618 .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl_index),
619 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl_index),619 .elf => {}, // no-op
620 .macho => {}, // no-op620 .macho => {}, // no-op
621 .wasm => return @fieldParentPtr(Wasm, "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),622 .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl_index),
src/link/Elf.zig+54-56
...@@ -344,9 +344,10 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File....@@ -344,9 +344,10 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.
344 const decl = mod.declPtr(decl_index);344 const decl = mod.declPtr(decl_index);
345345
346 assert(self.llvm_object == null);346 assert(self.llvm_object == null);
347 assert(decl.link.elf.local_sym_index != 0);
348347
349 const target = decl.link.elf.local_sym_index;348 try decl.link.elf.ensureInitialized(self);
349 const target = decl.link.elf.getSymbolIndex().?;
350
350 const vaddr = self.local_symbols.items[target].st_value;351 const vaddr = self.local_symbols.items[target].st_value;
351 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).?;
352 const gop = try self.relocs.getOrPut(self.base.allocator, atom);353 const gop = try self.relocs.getOrPut(self.base.allocator, atom);
...@@ -447,7 +448,7 @@ fn makeString(self: *Elf, bytes: []const u8) !u32 {...@@ -447,7 +448,7 @@ fn makeString(self: *Elf, bytes: []const u8) !u32 {
447 return @intCast(u32, result);448 return @intCast(u32, result);
448}449}
449450
450fn getString(self: Elf, str_off: u32) []const u8 {451pub fn getString(self: Elf, str_off: u32) []const u8 {
451 assert(str_off < self.shstrtab.items.len);452 assert(str_off < self.shstrtab.items.len);
452 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);
453}454}
...@@ -2069,7 +2070,7 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {...@@ -2069,7 +2070,7 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
2069 if (text_block.prev) |prev| {2070 if (text_block.prev) |prev| {
2070 prev.next = text_block.next;2071 prev.next = text_block.next;
20712072
2072 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {2073 if (!already_have_free_list_node and prev.freeListEligible(self)) {
2073 // The free list is heuristics, it doesn't have to be perfect, so we can2074 // The free list is heuristics, it doesn't have to be perfect, so we can
2074 // ignore the OOM here.2075 // ignore the OOM here.
2075 free_list.append(self.base.allocator, prev) catch {};2076 free_list.append(self.base.allocator, prev) catch {};
...@@ -2084,6 +2085,15 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {...@@ -2084,6 +2085,15 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
2084 text_block.next = null;2085 text_block.next = null;
2085 }2086 }
20862087
2088 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2089 const local_sym_index = text_block.getSymbolIndex().?;
2090 self.local_symbol_free_list.append(self.base.allocator, local_sym_index) catch {};
2091 self.local_symbols.items[local_sym_index].st_info = 0;
2092 _ = self.atom_by_index_table.remove(local_sym_index);
2093 text_block.local_sym_index = 0;
2094
2095 self.offset_table_free_list.append(self.base.allocator, text_block.offset_table_index) catch {};
2096
2087 if (self.dwarf) |*dw| {2097 if (self.dwarf) |*dw| {
2088 dw.freeAtom(&text_block.dbg_info_atom);2098 dw.freeAtom(&text_block.dbg_info_atom);
2089 }2099 }
...@@ -2099,7 +2109,7 @@ fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr...@@ -2099,7 +2109,7 @@ fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr
2099fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {2109fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
2100 const sym = self.local_symbols.items[text_block.local_sym_index];2110 const sym = self.local_symbols.items[text_block.local_sym_index];
2101 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;2111 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;
2102 const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*);2112 const need_realloc = !align_ok or new_block_size > text_block.capacity(self);
2103 if (!need_realloc) return sym.st_value;2113 if (!need_realloc) return sym.st_value;
2104 return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index);2114 return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index);
2105}2115}
...@@ -2128,7 +2138,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2128,7 +2138,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2128 // We now have a pointer to a live text block that has too much capacity.2138 // We now have a pointer to a live text block that has too much capacity.
2129 // Is it enough that we could fit this new text block?2139 // Is it enough that we could fit this new text block?
2130 const sym = self.local_symbols.items[big_block.local_sym_index];2140 const sym = self.local_symbols.items[big_block.local_sym_index];
2131 const capacity = big_block.capacity(self.*);2141 const capacity = big_block.capacity(self);
2132 const ideal_capacity = padToIdeal(capacity);2142 const ideal_capacity = padToIdeal(capacity);
2133 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;2143 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;
2134 const capacity_end_vaddr = sym.st_value + capacity;2144 const capacity_end_vaddr = sym.st_value + capacity;
...@@ -2138,7 +2148,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2138,7 +2148,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2138 // Additional bookkeeping here to notice if this free list node2148 // Additional bookkeeping here to notice if this free list node
2139 // should be deleted because the block that it points to has grown to take up2149 // should be deleted because the block that it points to has grown to take up
2140 // more of the extra capacity.2150 // more of the extra capacity.
2141 if (!big_block.freeListEligible(self.*)) {2151 if (!big_block.freeListEligible(self)) {
2142 _ = free_list.swapRemove(i);2152 _ = free_list.swapRemove(i);
2143 } else {2153 } else {
2144 i += 1;2154 i += 1;
...@@ -2213,7 +2223,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2213,7 +2223,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2213 return vaddr;2223 return vaddr;
2214}2224}
22152225
2216fn allocateLocalSymbol(self: *Elf) !u32 {2226pub fn allocateLocalSymbol(self: *Elf) !u32 {
2217 try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1);2227 try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1);
22182228
2219 const index = blk: {2229 const index = blk: {
...@@ -2240,7 +2250,7 @@ fn allocateLocalSymbol(self: *Elf) !u32 {...@@ -2240,7 +2250,7 @@ fn allocateLocalSymbol(self: *Elf) !u32 {
2240 return index;2250 return index;
2241}2251}
22422252
2243fn allocateGotOffset(self: *Elf) !u32 {2253pub fn allocateGotOffset(self: *Elf) !u32 {
2244 try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1);2254 try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1);
22452255
2246 const index = blk: {2256 const index = blk: {
...@@ -2260,32 +2270,10 @@ fn allocateGotOffset(self: *Elf) !u32 {...@@ -2260,32 +2270,10 @@ fn allocateGotOffset(self: *Elf) !u32 {
2260 return index;2270 return index;
2261}2271}
22622272
2263pub fn allocateDeclIndexes(self: *Elf, decl_index: Module.Decl.Index) !void {
2264 if (self.llvm_object) |_| return;
2265
2266 const mod = self.base.options.module.?;
2267 const decl = mod.declPtr(decl_index);
2268 const block = &decl.link.elf;
2269 if (block.local_sym_index != 0) return;
2270
2271 const decl_name = try decl.getFullyQualifiedName(mod);
2272 defer self.base.allocator.free(decl_name);
2273
2274 log.debug("allocating symbol indexes for {s}", .{decl_name});
2275
2276 block.local_sym_index = try self.allocateLocalSymbol();
2277 block.offset_table_index = try self.allocateGotOffset();
2278 try self.atom_by_index_table.putNoClobber(self.base.allocator, block.local_sym_index, block);
2279 try self.decls.putNoClobber(self.base.allocator, decl_index, null);
2280}
2281
2282fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {2273fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
2283 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;2274 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
2284 for (unnamed_consts.items) |atom| {2275 for (unnamed_consts.items) |atom| {
2285 self.freeTextBlock(atom, self.phdr_load_ro_index.?);2276 self.freeTextBlock(atom, self.phdr_load_ro_index.?);
2286 self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {};
2287 self.local_symbols.items[atom.local_sym_index].st_info = 0;
2288 _ = self.atom_by_index_table.remove(atom.local_sym_index);
2289 }2277 }
2290 unnamed_consts.clearAndFree(self.base.allocator);2278 unnamed_consts.clearAndFree(self.base.allocator);
2291}2279}
...@@ -2298,20 +2286,13 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {...@@ -2298,20 +2286,13 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
2298 const mod = self.base.options.module.?;2286 const mod = self.base.options.module.?;
2299 const decl = mod.declPtr(decl_index);2287 const decl = mod.declPtr(decl_index);
23002288
2301 const kv = self.decls.fetchRemove(decl_index);2289 log.debug("freeDecl {*}", .{decl});
2302 if (kv.?.value) |index| {
2303 self.freeTextBlock(&decl.link.elf, index);
2304 self.freeUnnamedConsts(decl_index);
2305 }
2306
2307 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2308 if (decl.link.elf.local_sym_index != 0) {
2309 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
2310 self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;
2311 _ = self.atom_by_index_table.remove(decl.link.elf.local_sym_index);
2312 decl.link.elf.local_sym_index = 0;
23132290
2314 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};2291 if (self.decls.fetchRemove(decl_index)) |kv| {
2292 if (kv.value) |index| {
2293 self.freeTextBlock(&decl.link.elf, index);
2294 self.freeUnnamedConsts(decl_index);
2295 }
2315 }2296 }
23162297
2317 if (self.dwarf) |*dw| {2298 if (self.dwarf) |*dw| {
...@@ -2363,7 +2344,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2363,7 +2344,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2363 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()2344 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
2364 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];2345 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
2365 if (local_sym.st_size != 0) {2346 if (local_sym.st_size != 0) {
2366 const capacity = decl.link.elf.capacity(self.*);2347 const capacity = decl.link.elf.capacity(self);
2367 const need_realloc = code.len > capacity or2348 const need_realloc = code.len > capacity or
2368 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);2349 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
2369 if (need_realloc) {2350 if (need_realloc) {
...@@ -2424,12 +2405,19 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2424,12 +2405,19 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2424 const tracy = trace(@src());2405 const tracy = trace(@src());
2425 defer tracy.end();2406 defer tracy.end();
24262407
2427 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2428 defer code_buffer.deinit();
2429
2430 const decl_index = func.owner_decl;2408 const decl_index = func.owner_decl;
2431 const decl = module.declPtr(decl_index);2409 const decl = module.declPtr(decl_index);
2432 self.freeUnnamedConsts(decl_index);2410 const atom = &decl.link.elf;
2411 try atom.ensureInitialized(self);
2412 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2413 if (gop.found_existing) {
2414 self.freeUnnamedConsts(decl_index);
2415 } else {
2416 gop.value_ptr.* = null;
2417 }
2418
2419 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2420 defer code_buffer.deinit();
24332421
2434 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;2422 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
2435 defer if (decl_state) |*ds| ds.deinit();2423 defer if (decl_state) |*ds| ds.deinit();
...@@ -2490,6 +2478,13 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2490,6 +2478,13 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
24902478
2491 assert(!self.unnamed_const_atoms.contains(decl_index));2479 assert(!self.unnamed_const_atoms.contains(decl_index));
24922480
2481 const atom = &decl.link.elf;
2482 try atom.ensureInitialized(self);
2483 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2484 if (!gop.found_existing) {
2485 gop.value_ptr.* = null;
2486 }
2487
2493 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2488 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2494 defer code_buffer.deinit();2489 defer code_buffer.deinit();
24952490
...@@ -2633,16 +2628,19 @@ pub fn updateDeclExports(...@@ -2633,16 +2628,19 @@ pub fn updateDeclExports(
2633 const tracy = trace(@src());2628 const tracy = trace(@src());
2634 defer tracy.end();2629 defer tracy.end();
26352630
2636 try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len);
2637 const decl = module.declPtr(decl_index);2631 const decl = module.declPtr(decl_index);
2638 if (decl.link.elf.local_sym_index == 0) return;2632 const atom = &decl.link.elf;
2639 const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];
26402633
2641 const decl_ptr = self.decls.getPtr(decl_index).?;2634 if (atom.getSymbolIndex() == null) return;
2642 if (decl_ptr.* == null) {2635
2643 decl_ptr.* = try self.getDeclPhdrIndex(decl);2636 const decl_sym = atom.getSymbol(self);
2637 try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len);
2638
2639 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2640 if (!gop.found_existing) {
2641 gop.value_ptr.* = try self.getDeclPhdrIndex(decl);
2644 }2642 }
2645 const phdr_index = decl_ptr.*.?;2643 const phdr_index = gop.value_ptr.*.?;
2646 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;2644 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
26472645
2648 for (exports) |exp| {2646 for (exports) |exp| {
src/link/Elf/Atom.zig+46-6
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1const Atom = @This();1const Atom = @This();
22
3const std = @import("std");3const std = @import("std");
4const assert = std.debug.assert;
5const elf = std.elf;
46
5const Dwarf = @import("../Dwarf.zig");7const Dwarf = @import("../Dwarf.zig");
6const Elf = @import("../Elf.zig");8const Elf = @import("../Elf.zig");
...@@ -12,8 +14,10 @@ const Elf = @import("../Elf.zig");...@@ -12,8 +14,10 @@ const Elf = @import("../Elf.zig");
12/// If this field is 0, it means the codegen size = 0 and there is no symbol or14/// If this field is 0, it means the codegen size = 0 and there is no symbol or
13/// offset table entry.15/// offset table entry.
14local_sym_index: u32,16local_sym_index: u32,
17
15/// This field is undefined for symbols with size = 0.18/// This field is undefined for symbols with size = 0.
16offset_table_index: u32,19offset_table_index: u32,
20
17/// Points to the previous and next neighbors, based on the `text_offset`.21/// Points to the previous and next neighbors, based on the `text_offset`.
18/// This can be used to find, for example, the capacity of this `TextBlock`.22/// This can be used to find, for example, the capacity of this `TextBlock`.
19prev: ?*Atom,23prev: ?*Atom,
...@@ -29,13 +33,49 @@ pub const empty = Atom{...@@ -29,13 +33,49 @@ pub const empty = Atom{
29 .dbg_info_atom = undefined,33 .dbg_info_atom = undefined,
30};34};
3135
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
32/// Returns how much room there is to grow in virtual address space.72/// Returns how much room there is to grow in virtual address space.
33/// File offset relocation happens transparently, so it is not included in73/// File offset relocation happens transparently, so it is not included in
34/// this calculation.74/// this calculation.
35pub fn capacity(self: Atom, elf_file: Elf) u64 {75pub fn capacity(self: Atom, elf_file: *Elf) u64 {
36 const self_sym = elf_file.local_symbols.items[self.local_sym_index];76 const self_sym = self.getSymbol(elf_file);
37 if (self.next) |next| {77 if (self.next) |next| {
38 const next_sym = elf_file.local_symbols.items[next.local_sym_index];78 const next_sym = next.getSymbol(elf_file);
39 return next_sym.st_value - self_sym.st_value;79 return next_sym.st_value - self_sym.st_value;
40 } else {80 } else {
41 // We are the last block. The capacity is limited only by virtual address space.81 // We are the last block. The capacity is limited only by virtual address space.
...@@ -43,11 +83,11 @@ pub fn capacity(self: Atom, elf_file: Elf) u64 {...@@ -43,11 +83,11 @@ pub fn capacity(self: Atom, elf_file: Elf) u64 {
43 }83 }
44}84}
4585
46pub fn freeListEligible(self: Atom, elf_file: Elf) bool {86pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
47 // No need to keep a free list node for the last block.87 // No need to keep a free list node for the last block.
48 const next = self.next orelse return false;88 const next = self.next orelse return false;
49 const self_sym = elf_file.local_symbols.items[self.local_sym_index];89 const self_sym = self.getSymbol(elf_file);
50 const next_sym = elf_file.local_symbols.items[next.local_sym_index];90 const next_sym = next.getSymbol(elf_file);
51 const cap = next_sym.st_value - self_sym.st_value;91 const cap = next_sym.st_value - self_sym.st_value;
52 const ideal_cap = Elf.padToIdeal(self_sym.st_size);92 const ideal_cap = Elf.padToIdeal(self_sym.st_size);
53 if (cap <= ideal_cap) return false;93 if (cap <= ideal_cap) return false;
src/link/MachO.zig+4-3
...@@ -2472,14 +2472,15 @@ pub fn updateDeclExports(...@@ -2472,14 +2472,15 @@ pub fn updateDeclExports(
24722472
2473 const decl = module.declPtr(decl_index);2473 const decl = module.declPtr(decl_index);
2474 const atom = &decl.link.macho;2474 const atom = &decl.link.macho;
2475 try atom.ensureInitialized(self);2475
2476 if (atom.getSymbolIndex() == null) return;
24762477
2477 const gop = try self.decls.getOrPut(gpa, decl_index);2478 const gop = try self.decls.getOrPut(gpa, decl_index);
2478 if (!gop.found_existing) {2479 if (!gop.found_existing) {
2479 gop.value_ptr.* = null;2480 gop.value_ptr.* = self.getDeclOutputSection(decl);
2480 }2481 }
24812482
2482 const decl_sym = decl.link.macho.getSymbol(self);2483 const decl_sym = atom.getSymbol(self);
24832484
2484 for (exports) |exp| {2485 for (exports) |exp| {
2485 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name});2486 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name});