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 {
53245324 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we
53255325 // must call `freeDecl` in the linker backend now.
53265326 switch (mod.comp.bin_file.tag) {
5327 .macho, .c => {}, // this linker backend has already migrated to the new API
5327 .elf, .macho, .c => {}, // this linker backend has already migrated to the new API
53285328 else => if (decl.has_tv) {
53295329 if (decl.ty.isFnOrHasRuntimeBits()) {
53305330 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
43074307 const fn_owner_decl = mod.declPtr(func.owner_decl);
43084308
43094309 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4310 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4311 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
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 };
4310 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4311 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
43164312 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
43174313 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
43184314 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
61256121 mod.markDeclAlive(decl);
61266122
61276123 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6128 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
6129 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
6130 return MCValue{ .memory = got_addr };
6124 try decl.link.elf.ensureInitialized(elf_file);
6125 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
61316126 } 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.
61346127 try decl.link.macho.ensureInitialized(macho_file);
61356128 return MCValue{ .linker_load = .{
61366129 .type = .got,
61376130 .sym_index = decl.link.macho.getSymbolIndex().?,
61386131 } };
61396132 } 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.
61426133 assert(decl.link.coff.sym_index != 0);
61436134 return MCValue{ .linker_load = .{
61446135 .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
42534253
42544254 // Due to incremental compilation, how function calls are generated depends
42554255 // on linking.
4256 switch (self.bin_file.tag) {
4257 .elf => {
4258 if (self.air.value(callee)) |func_value| {
4259 if (func_value.castTag(.function)) |func_payload| {
4260 const func = func_payload.data;
4261 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4262 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
4263 const mod = self.bin_file.options.module.?;
4264 const fn_owner_decl = mod.declPtr(func.owner_decl);
4265 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
4266 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4267 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
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 }
4256 if (self.air.value(callee)) |func_value| {
4257 if (func_value.castTag(.function)) |func_payload| {
4258 const func = func_payload.data;
4259 const mod = self.bin_file.options.module.?;
4260 const fn_owner_decl = mod.declPtr(func.owner_decl);
4261
4262 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4263 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4264 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4265 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
4266 } else if (self.bin_file.cast(link.File.MachO)) |_| {
4267 unreachable; // unsupported architecture for MachO
42754268 } else {
4276 assert(ty.zigTypeTag() == .Pointer);
4277 const mcv = try self.resolveInst(callee);
4278
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 },
4269 return self.fail("TODO implement call on {s} for {s}", .{
4270 @tagName(self.bin_file.tag),
4271 @tagName(self.target.cpu.arch),
42884272 });
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 // });
43034273 }
4304 },
4305 .macho => unreachable, // unsupported architecture for MachO
4306 .coff => return self.fail("TODO implement call in COFF for {}", .{self.target.cpu.arch}),
4307 .plan9 => return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch}),
4308 else => unreachable,
4274 } else if (func_value.castTag(.extern_fn)) |_| {
4275 return self.fail("TODO implement calling extern functions", .{});
4276 } else {
4277 return self.fail("TODO implement calling bitcasted functions", .{});
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 // });
43094307 }
43104308
43114309 const result: MCValue = result: {
......@@ -6086,9 +6084,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
60866084 mod.markDeclAlive(decl);
60876085
60886086 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6089 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
6090 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
6091 return MCValue{ .memory = got_addr };
6087 try decl.link.elf.ensureInitialized(elf_file);
6088 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
60926089 } else if (self.bin_file.cast(link.File.MachO)) |_| {
60936090 unreachable; // unsupported architecture for MachO
60946091 } 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
17221722 if (func_value.castTag(.function)) |func_payload| {
17231723 const func = func_payload.data;
17241724
1725 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1726 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
17271725 const mod = self.bin_file.options.module.?;
17281726 const fn_owner_decl = mod.declPtr(func.owner_decl);
1729 const got_addr = blk: {
1730 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
1731 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
1732 };
1727 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
1728 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
17331729
17341730 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
17351731 _ = try self.addInst(.{
......@@ -2557,9 +2553,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
25572553 const decl = mod.declPtr(decl_index);
25582554 mod.markDeclAlive(decl);
25592555 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2560 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2561 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2562 return MCValue{ .memory = got_addr };
2556 try decl.link.elf.ensureInitialized(elf_file);
2557 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
25632558 } else if (self.bin_file.cast(link.File.MachO)) |_| {
25642559 // TODO I'm hacking my way through here by repurposing .memory for storing
25652560 // 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
12161216 if (self.bin_file.tag == link.File.Elf.base_tag) {
12171217 if (func_value.castTag(.function)) |func_payload| {
12181218 const func = func_payload.data;
1219 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1220 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1219 const mod = self.bin_file.options.module.?;
1220 const fn_owner_decl = mod.declPtr(func.owner_decl);
12211221 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.?];
1223 const mod = self.bin_file.options.module.?;
1224 break :blk @intCast(u32, got.p_vaddr + mod.declPtr(func.owner_decl).link.elf.offset_table_index * ptr_bytes);
1222 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
1223 break :blk @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
12251224 } else unreachable;
12261225
12271226 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
41934192}
41944193
41954194fn 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
41994195 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
42004196 if (tv.ty.zigTypeTag() == .Pointer) blk: {
42014197 if (tv.ty.castPtrToFn()) |_| break :blk;
......@@ -4209,9 +4205,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
42094205
42104206 mod.markDeclAlive(decl);
42114207 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4212 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4213 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
4214 return MCValue{ .memory = got_addr };
4208 try decl.link.elf.ensureInitialized(elf_file);
4209 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
42154210 } else {
42164211 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
42174212 }
src/arch/x86_64/CodeGen.zig+5-10
......@@ -3998,16 +3998,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
39983998 const fn_owner_decl = mod.declPtr(func.owner_decl);
39993999
40004000 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4001 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
4002 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
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 };
4001 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4002 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
40074003 _ = try self.addInst(.{
40084004 .tag = .call,
40094005 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4010 .data = .{ .imm = @truncate(u32, got_addr) },
4006 .data = .{ .imm = got_addr },
40114007 });
40124008 } else if (self.bin_file.cast(link.File.Coff)) |_| {
40134009 try self.genSetReg(Type.initTag(.usize), .rax, .{
......@@ -6721,9 +6717,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
67216717 module.markDeclAlive(decl);
67226718
67236719 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6724 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
6725 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
6726 return MCValue{ .memory = got_addr };
6720 try decl.link.elf.ensureInitialized(elf_file);
6721 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
67276722 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
67286723 try decl.link.macho.ensureInitialized(macho_file);
67296724 return MCValue{ .linker_load = .{
src/link.zig+1-1
......@@ -616,7 +616,7 @@ pub const File = struct {
616616 }
617617 switch (base.tag) {
618618 .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl_index),
619 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl_index),
619 .elf => {}, // no-op
620620 .macho => {}, // no-op
621621 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl_index),
622622 .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.
344344 const decl = mod.declPtr(decl_index);
345345
346346 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
350351 const vaddr = self.local_symbols.items[target].st_value;
351352 const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?;
352353 const gop = try self.relocs.getOrPut(self.base.allocator, atom);
......@@ -447,7 +448,7 @@ fn makeString(self: *Elf, bytes: []const u8) !u32 {
447448 return @intCast(u32, result);
448449}
449450
450fn getString(self: Elf, str_off: u32) []const u8 {
451pub fn getString(self: Elf, str_off: u32) []const u8 {
451452 assert(str_off < self.shstrtab.items.len);
452453 return mem.sliceTo(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off), 0);
453454}
......@@ -2069,7 +2070,7 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
20692070 if (text_block.prev) |prev| {
20702071 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)) {
20732074 // The free list is heuristics, it doesn't have to be perfect, so we can
20742075 // ignore the OOM here.
20752076 free_list.append(self.base.allocator, prev) catch {};
......@@ -2084,6 +2085,15 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
20842085 text_block.next = null;
20852086 }
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
20872097 if (self.dwarf) |*dw| {
20882098 dw.freeAtom(&text_block.dbg_info_atom);
20892099 }
......@@ -2099,7 +2109,7 @@ fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr
20992109fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
21002110 const sym = self.local_symbols.items[text_block.local_sym_index];
21012111 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);
21032113 if (!need_realloc) return sym.st_value;
21042114 return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index);
21052115}
......@@ -2128,7 +2138,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
21282138 // We now have a pointer to a live text block that has too much capacity.
21292139 // Is it enough that we could fit this new text block?
21302140 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);
21322142 const ideal_capacity = padToIdeal(capacity);
21332143 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;
21342144 const capacity_end_vaddr = sym.st_value + capacity;
......@@ -2138,7 +2148,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
21382148 // Additional bookkeeping here to notice if this free list node
21392149 // should be deleted because the block that it points to has grown to take up
21402150 // more of the extra capacity.
2141 if (!big_block.freeListEligible(self.*)) {
2151 if (!big_block.freeListEligible(self)) {
21422152 _ = free_list.swapRemove(i);
21432153 } else {
21442154 i += 1;
......@@ -2213,7 +2223,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
22132223 return vaddr;
22142224}
22152225
2216fn allocateLocalSymbol(self: *Elf) !u32 {
2226pub fn allocateLocalSymbol(self: *Elf) !u32 {
22172227 try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1);
22182228
22192229 const index = blk: {
......@@ -2240,7 +2250,7 @@ fn allocateLocalSymbol(self: *Elf) !u32 {
22402250 return index;
22412251}
22422252
2243fn allocateGotOffset(self: *Elf) !u32 {
2253pub fn allocateGotOffset(self: *Elf) !u32 {
22442254 try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1);
22452255
22462256 const index = blk: {
......@@ -2260,32 +2270,10 @@ fn allocateGotOffset(self: *Elf) !u32 {
22602270 return index;
22612271}
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
22822273fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
22832274 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
22842275 for (unnamed_consts.items) |atom| {
22852276 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);
22892277 }
22902278 unnamed_consts.clearAndFree(self.base.allocator);
22912279}
......@@ -2298,20 +2286,13 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
22982286 const mod = self.base.options.module.?;
22992287 const decl = mod.declPtr(decl_index);
23002288
2301 const kv = self.decls.fetchRemove(decl_index);
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;
2289 log.debug("freeDecl {*}", .{decl});
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 }
23152296 }
23162297
23172298 if (self.dwarf) |*dw| {
......@@ -2363,7 +2344,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
23632344 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
23642345 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
23652346 if (local_sym.st_size != 0) {
2366 const capacity = decl.link.elf.capacity(self.*);
2347 const capacity = decl.link.elf.capacity(self);
23672348 const need_realloc = code.len > capacity or
23682349 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
23692350 if (need_realloc) {
......@@ -2424,12 +2405,19 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24242405 const tracy = trace(@src());
24252406 defer tracy.end();
24262407
2427 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2428 defer code_buffer.deinit();
2429
24302408 const decl_index = func.owner_decl;
24312409 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
24342422 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
24352423 defer if (decl_state) |*ds| ds.deinit();
......@@ -2490,6 +2478,13 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
24902478
24912479 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
24932488 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
24942489 defer code_buffer.deinit();
24952490
......@@ -2633,16 +2628,19 @@ pub fn updateDeclExports(
26332628 const tracy = trace(@src());
26342629 defer tracy.end();
26352630
2636 try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len);
26372631 const decl = module.declPtr(decl_index);
2638 if (decl.link.elf.local_sym_index == 0) return;
2639 const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];
2632 const atom = &decl.link.elf;
26402633
2641 const decl_ptr = self.decls.getPtr(decl_index).?;
2642 if (decl_ptr.* == null) {
2643 decl_ptr.* = try self.getDeclPhdrIndex(decl);
2634 if (atom.getSymbolIndex() == null) return;
2635
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);
26442642 }
2645 const phdr_index = decl_ptr.*.?;
2643 const phdr_index = gop.value_ptr.*.?;
26462644 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
26472645
26482646 for (exports) |exp| {
src/link/Elf/Atom.zig+46-6
......@@ -1,6 +1,8 @@
11const Atom = @This();
22
33const std = @import("std");
4const assert = std.debug.assert;
5const elf = std.elf;
46
57const Dwarf = @import("../Dwarf.zig");
68const Elf = @import("../Elf.zig");
......@@ -12,8 +14,10 @@ const Elf = @import("../Elf.zig");
1214/// If this field is 0, it means the codegen size = 0 and there is no symbol or
1315/// offset table entry.
1416local_sym_index: u32,
17
1518/// This field is undefined for symbols with size = 0.
1619offset_table_index: u32,
20
1721/// Points to the previous and next neighbors, based on the `text_offset`.
1822/// This can be used to find, for example, the capacity of this `TextBlock`.
1923prev: ?*Atom,
......@@ -29,13 +33,49 @@ pub const empty = Atom{
2933 .dbg_info_atom = undefined,
3034};
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
3272/// Returns how much room there is to grow in virtual address space.
3373/// File offset relocation happens transparently, so it is not included in
3474/// this calculation.
35pub fn capacity(self: Atom, elf_file: Elf) u64 {
36 const self_sym = elf_file.local_symbols.items[self.local_sym_index];
75pub fn capacity(self: Atom, elf_file: *Elf) u64 {
76 const self_sym = self.getSymbol(elf_file);
3777 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);
3979 return next_sym.st_value - self_sym.st_value;
4080 } else {
4181 // 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 {
4383 }
4484}
4585
46pub fn freeListEligible(self: Atom, elf_file: Elf) bool {
86pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
4787 // No need to keep a free list node for the last block.
4888 const next = self.next orelse return false;
49 const self_sym = elf_file.local_symbols.items[self.local_sym_index];
50 const next_sym = elf_file.local_symbols.items[next.local_sym_index];
89 const self_sym = self.getSymbol(elf_file);
90 const next_sym = next.getSymbol(elf_file);
5191 const cap = next_sym.st_value - self_sym.st_value;
5292 const ideal_cap = Elf.padToIdeal(self_sym.st_size);
5393 if (cap <= ideal_cap) return false;
src/link/MachO.zig+4-3
......@@ -2472,14 +2472,15 @@ pub fn updateDeclExports(
24722472
24732473 const decl = module.declPtr(decl_index);
24742474 const atom = &decl.link.macho;
2475 try atom.ensureInitialized(self);
2475
2476 if (atom.getSymbolIndex() == null) return;
24762477
24772478 const gop = try self.decls.getOrPut(gpa, decl_index);
24782479 if (!gop.found_existing) {
2479 gop.value_ptr.* = null;
2480 gop.value_ptr.* = self.getDeclOutputSection(decl);
24802481 }
24812482
2482 const decl_sym = decl.link.macho.getSymbol(self);
2483 const decl_sym = atom.getSymbol(self);
24832484
24842485 for (exports) |exp| {
24852486 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name});