authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-06 14:42:32+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-06 14:42:32+02:00
log93120a81fee404e3ae90c5ea6d0ad2e71037bee0
tree8e65cc321757f8cc42a5c83e562d13f7a63a5bcf
parenta9df098cd2dd04e2c363b439233ff2e14e198413

elf: lift-off - get it to compile and run until the error!


5 files changed, 151 insertions(+), 131 deletions(-)

src/link/Elf.zig+65-108
...@@ -105,7 +105,7 @@ atoms: std.ArrayListUnmanaged(Atom) = .{},...@@ -105,7 +105,7 @@ atoms: std.ArrayListUnmanaged(Atom) = .{},
105///105///
106/// value assigned to label `foo` is an unnamed constant belonging/associated106/// value assigned to label `foo` is an unnamed constant belonging/associated
107/// with `Decl` `main`, and lives as long as that `Decl`.107/// with `Decl` `main`, and lives as long as that `Decl`.
108unnamed_const_atoms: UnnamedConstTable = .{},108unnamed_consts: UnnamedConstTable = .{},
109109
110/// A table of relocations indexed by the owning them `TextBlock`.110/// A table of relocations indexed by the owning them `TextBlock`.
111relocs: RelocTable = .{},111relocs: RelocTable = .{},
...@@ -251,11 +251,11 @@ pub fn deinit(self: *Elf) void {...@@ -251,11 +251,11 @@ pub fn deinit(self: *Elf) void {
251 self.lazy_syms.deinit(gpa);251 self.lazy_syms.deinit(gpa);
252252
253 {253 {
254 var it = self.unnamed_const_atoms.valueIterator();254 var it = self.unnamed_consts.valueIterator();
255 while (it.next()) |atoms| {255 while (it.next()) |syms| {
256 atoms.deinit(gpa);256 syms.deinit(gpa);
257 }257 }
258 self.unnamed_const_atoms.deinit(gpa);258 self.unnamed_consts.deinit(gpa);
259 }259 }
260260
261 {261 {
...@@ -279,7 +279,7 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link....@@ -279,7 +279,7 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.
279 const vaddr = this_sym.value;279 const vaddr = this_sym.value;
280 const parent_atom_index = self.symbol(reloc_info.parent_atom_index).atom_index;280 const parent_atom_index = self.symbol(reloc_info.parent_atom_index).atom_index;
281 try Atom.addRelocation(self, parent_atom_index, .{281 try Atom.addRelocation(self, parent_atom_index, .{
282 .target = this_sym,282 .target = this_sym_index,
283 .offset = reloc_info.offset,283 .offset = reloc_info.offset,
284 .addend = reloc_info.addend,284 .addend = reloc_info.addend,
285 .prev_vaddr = vaddr,285 .prev_vaddr = vaddr,
...@@ -830,6 +830,12 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -830,6 +830,12 @@ pub fn populateMissingMetadata(self: *Elf) !void {
830830
831 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);831 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);
832 }832 }
833
834 if (self.zig_module_index == null) {
835 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
836 self.files.set(index, .{ .zig_module = .{ .index = index } });
837 self.zig_module_index = index;
838 }
833}839}
834840
835pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {841pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
...@@ -967,12 +973,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -967,12 +973,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
967 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;973 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
968 _ = module;974 _ = module;
969975
970 self.zig_module_index = blk: {
971 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
972 self.files.set(index, .{ .zig_module = .{ .index = index } });
973 break :blk index;
974 };
975
976 self.linker_defined_index = blk: {976 self.linker_defined_index = blk: {
977 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));977 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
978 self.files.set(index, .{ .linker_defined = .{ .index = index } });978 self.files.set(index, .{ .linker_defined = .{ .index = index } });
...@@ -980,6 +980,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -980,6 +980,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
980 };980 };
981981
982 std.debug.print("{}\n", .{self.dumpState()});982 std.debug.print("{}\n", .{self.dumpState()});
983 return error.FlushFailure;
983984
984 // if (self.lazy_syms.getPtr(.none)) |metadata| {985 // if (self.lazy_syms.getPtr(.none)) |metadata| {
985 // // Most lazy symbols can be updated on first use, but986 // // Most lazy symbols can be updated on first use, but
...@@ -2078,78 +2079,21 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2078,78 +2079,21 @@ fn writeElfHeader(self: *Elf) !void {
2078 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);2079 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
2079}2080}
20802081
2081fn freeAtom(self: *Elf, atom_index: Atom.Index) void {2082fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
2082 const atom_ptr = self.atom(atom_index);2083 const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
2083 log.debug("freeAtom {d} ({s})", .{ atom_index, atom_ptr.name(self) });2084 for (unnamed_consts.items) |sym_index| {
20842085 self.freeDeclMetadata(sym_index);
2085 Atom.freeRelocations(self, atom_index);
2086
2087 const gpa = self.base.allocator;
2088 const shndx = atom_ptr.symbol(self).st_shndx;
2089 const free_list = &self.sections.items(.free_list)[shndx];
2090 var already_have_free_list_node = false;
2091 {
2092 var i: usize = 0;
2093 // TODO turn free_list into a hash map
2094 while (i < free_list.items.len) {
2095 if (free_list.items[i] == atom_index) {
2096 _ = free_list.swapRemove(i);
2097 continue;
2098 }
2099 if (free_list.items[i] == atom_ptr.prev_index) {
2100 already_have_free_list_node = true;
2101 }
2102 i += 1;
2103 }
2104 }
2105
2106 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[shndx];
2107 if (maybe_last_atom_index.*) |last_atom_index| {
2108 if (last_atom_index == atom_index) {
2109 if (atom_ptr.prev_index) |prev_index| {
2110 // TODO shrink the section size here
2111 maybe_last_atom_index.* = prev_index;
2112 } else {
2113 maybe_last_atom_index.* = null;
2114 }
2115 }
2116 }
2117
2118 if (atom_ptr.prev_index) |prev_index| {
2119 const prev = self.atom(prev_index);
2120 prev.next_index = atom_ptr.next_index;
2121
2122 if (!already_have_free_list_node and prev.*.freeListEligible(self)) {
2123 // The free list is heuristics, it doesn't have to be perfect, so we can
2124 // ignore the OOM here.
2125 free_list.append(gpa, prev_index) catch {};
2126 }
2127 } else {
2128 atom_ptr.prev_index = null;
2129 }
2130
2131 if (atom_ptr.next_index) |next_index| {
2132 self.atom(next_index).prev_index = atom_ptr.prev_index;
2133 } else {
2134 atom_ptr.next_index = null;
2135 }2086 }
2087 unnamed_consts.clearAndFree(self.base.allocator);
2088}
21362089
2137 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.2090fn freeDeclMetadata(self: *Elf, sym_index: Symbol.Index) void {
2138 const sym_index = atom_ptr.symbolIndex().?;2091 const sym = self.symbol(sym_index);
21392092 sym.atom(self).?.free(self);
2140 log.debug("adding %{d} to local symbols free list", .{sym_index});2093 log.debug("adding %{d} to local symbols free list", .{sym_index});
2141 self.symbols_free_list.append(gpa, sym_index) catch {};2094 self.symbols_free_list.append(self.base.allocator, sym_index) catch {};
2142 self.symbols.items[sym_index] = .{};2095 self.symbols.items[sym_index] = .{};
2143 atom_ptr.sym_index = 0;2096 self.got_table.freeEntry(self.base.allocator, sym_index);
2144 self.got_table.freeEntry(gpa, sym_index);
2145}
2146
2147fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
2148 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
2149 for (unnamed_consts.items) |atom_index| {
2150 self.freeAtom(atom_index);
2151 }
2152 unnamed_consts.clearAndFree(self.base.allocator);
2153}2097}
21542098
2155pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {2099pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
...@@ -2162,7 +2106,8 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {...@@ -2162,7 +2106,8 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
21622106
2163 if (self.decls.fetchRemove(decl_index)) |const_kv| {2107 if (self.decls.fetchRemove(decl_index)) |const_kv| {
2164 var kv = const_kv;2108 var kv = const_kv;
2165 self.freeAtom(kv.value.atom);2109 const sym_index = kv.value.symbol_index;
2110 self.freeDeclMetadata(sym_index);
2166 self.freeUnnamedConsts(decl_index);2111 self.freeUnnamedConsts(decl_index);
2167 kv.value.exports.deinit(self.base.allocator);2112 kv.value.exports.deinit(self.base.allocator);
2168 }2113 }
...@@ -2196,7 +2141,7 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) !...@@ -2196,7 +2141,7 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) !
2196 .code => self.text_section_index.?,2141 .code => self.text_section_index.?,
2197 .const_data => self.rodata_section_index.?,2142 .const_data => self.rodata_section_index.?,
2198 }, self),2143 }, self),
2199 .pending_flush => return metadata.atom.*,2144 .pending_flush => return metadata.symbol_index.*,
2200 .flushed => {},2145 .flushed => {},
2201 }2146 }
2202 metadata.state.* = .pending_flush;2147 metadata.state.* = .pending_flush;
...@@ -2271,6 +2216,7 @@ fn updateDeclCode(...@@ -2271,6 +2216,7 @@ fn updateDeclCode(
2271 esym.st_size = code.len;2216 esym.st_size = code.len;
22722217
2273 const old_size = atom_ptr.size;2218 const old_size = atom_ptr.size;
2219 const old_vaddr = atom_ptr.value;
2274 atom_ptr.alignment = math.log2_int(u64, required_alignment);2220 atom_ptr.alignment = math.log2_int(u64, required_alignment);
2275 atom_ptr.size = code.len;2221 atom_ptr.size = code.len;
22762222
...@@ -2278,11 +2224,11 @@ fn updateDeclCode(...@@ -2278,11 +2224,11 @@ fn updateDeclCode(
2278 const capacity = atom_ptr.capacity(self);2224 const capacity = atom_ptr.capacity(self);
2279 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);2225 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
2280 if (need_realloc) {2226 if (need_realloc) {
2281 const vaddr = try atom_ptr.grow(self);2227 try atom_ptr.grow(self);
2282 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });2228 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });
2283 if (vaddr != sym.value) {2229 if (old_vaddr != atom_ptr.value) {
2284 sym.value = vaddr;2230 sym.value = atom_ptr.value;
2285 esym.st_value = vaddr;2231 esym.st_value = atom_ptr.value;
22862232
2287 log.debug(" (writing new offset table entry)", .{});2233 log.debug(" (writing new offset table entry)", .{});
2288 const got_entry_index = self.got_table.lookup.get(sym_index).?;2234 const got_entry_index = self.got_table.lookup.get(sym_index).?;
...@@ -2293,12 +2239,16 @@ fn updateDeclCode(...@@ -2293,12 +2239,16 @@ fn updateDeclCode(
2293 atom_ptr.shrink(self);2239 atom_ptr.shrink(self);
2294 }2240 }
2295 } else {2241 } else {
2296 const vaddr = try atom_ptr.allocate(self);2242 try atom_ptr.allocate(self);
2297 errdefer self.freeAtom(atom_ptr);2243 errdefer self.freeDeclMetadata(sym_index);
2298 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr });2244 log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{
2245 decl_name,
2246 atom_ptr.value,
2247 atom_ptr.value + atom_ptr.size,
2248 });
22992249
2300 sym.value = vaddr;2250 sym.value = atom_ptr.value;
2301 esym.st_value = vaddr;2251 esym.st_value = atom_ptr.value;
23022252
2303 const got_entry_index = try sym.getOrCreateOffsetTableEntry(self);2253 const got_entry_index = try sym.getOrCreateOffsetTableEntry(self);
2304 try self.writeOffsetTableEntry(got_entry_index);2254 try self.writeOffsetTableEntry(got_entry_index);
...@@ -2518,17 +2468,23 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol....@@ -2518,17 +2468,23 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
2518 const atom_ptr = local_sym.atom(self).?;2468 const atom_ptr = local_sym.atom(self).?;
2519 atom_ptr.alignment = math.log2_int(u64, required_alignment);2469 atom_ptr.alignment = math.log2_int(u64, required_alignment);
2520 atom_ptr.size = code.len;2470 atom_ptr.size = code.len;
2521 const vaddr = try atom_ptr.allocate(self);
2522 errdefer self.freeAtom(atom_ptr);
2523 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });
25242471
2525 local_sym.value = vaddr;2472 try atom_ptr.allocate(self);
2526 local_esym.st_value = vaddr;2473 errdefer self.freeDeclMetadata(symbol_index);
2474
2475 log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{
2476 name,
2477 atom_ptr.value,
2478 atom_ptr.value + atom_ptr.size,
2479 });
2480
2481 local_sym.value = atom_ptr.value;
2482 local_esym.st_value = atom_ptr.value;
25272483
2528 const got_entry_index = try local_sym.getOrCreateOffsetTableEntry(self);2484 const got_entry_index = try local_sym.getOrCreateOffsetTableEntry(self);
2529 try self.writeOffsetTableEntry(got_entry_index);2485 try self.writeOffsetTableEntry(got_entry_index);
25302486
2531 const section_offset = vaddr - self.program_headers.items[phdr_index].p_vaddr;2487 const section_offset = atom_ptr.value - self.program_headers.items[phdr_index].p_vaddr;
2532 const file_offset = self.sections.items(.shdr)[local_sym.output_section_index].sh_offset + section_offset;2488 const file_offset = self.sections.items(.shdr)[local_sym.output_section_index].sh_offset + section_offset;
2533 try self.base.file.?.pwriteAll(code, file_offset);2489 try self.base.file.?.pwriteAll(code, file_offset);
2534}2490}
...@@ -2540,7 +2496,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2540,7 +2496,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2540 defer code_buffer.deinit();2496 defer code_buffer.deinit();
25412497
2542 const mod = self.base.options.module.?;2498 const mod = self.base.options.module.?;
2543 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);2499 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
2544 if (!gop.found_existing) {2500 if (!gop.found_existing) {
2545 gop.value_ptr.* = .{};2501 gop.value_ptr.* = .{};
2546 }2502 }
...@@ -2586,17 +2542,18 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2586,17 +2542,18 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2586 const atom_ptr = local_sym.atom(self).?;2542 const atom_ptr = local_sym.atom(self).?;
2587 atom_ptr.alignment = math.log2_int(u64, required_alignment);2543 atom_ptr.alignment = math.log2_int(u64, required_alignment);
2588 atom_ptr.size = code.len;2544 atom_ptr.size = code.len;
2589 const vaddr = try atom_ptr.allocateAtom(self);
2590 errdefer self.freeAtom(atom_ptr);
25912545
2592 log.debug("allocated text block for {s} at 0x{x}", .{ name, local_sym.st_value });2546 try atom_ptr.allocate(self);
2547 errdefer self.freeDeclMetadata(sym_index);
2548
2549 log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{ name, atom_ptr.value, atom_ptr.value + atom_ptr.size });
25932550
2594 local_sym.value = vaddr;2551 local_sym.value = atom_ptr.value;
2595 local_esym.st_value = vaddr;2552 local_esym.st_value = atom_ptr.value;
25962553
2597 try unnamed_consts.append(gpa, atom_ptr.atom_index);2554 try unnamed_consts.append(gpa, atom_ptr.atom_index);
25982555
2599 const section_offset = local_sym.value - self.program_headers.items[phdr_index].p_vaddr;2556 const section_offset = atom_ptr.value - self.program_headers.items[phdr_index].p_vaddr;
2600 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;2557 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
2601 try self.base.file.?.pwriteAll(code, file_offset);2558 try self.base.file.?.pwriteAll(code, file_offset);
26022559
...@@ -2624,7 +2581,7 @@ pub fn updateDeclExports(...@@ -2624,7 +2581,7 @@ pub fn updateDeclExports(
2624 const decl = mod.declPtr(decl_index);2581 const decl = mod.declPtr(decl_index);
2625 const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index);2582 const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index);
2626 const decl_sym = self.symbol(decl_sym_index);2583 const decl_sym = self.symbol(decl_sym_index);
2627 const decl_esym = symbol.sourceSymbol(self);2584 const decl_esym = decl_sym.sourceSymbol(self);
2628 const decl_metadata = self.decls.getPtr(decl_index).?;2585 const decl_metadata = self.decls.getPtr(decl_index).?;
26292586
2630 for (exports) |exp| {2587 for (exports) |exp| {
...@@ -2658,7 +2615,7 @@ pub fn updateDeclExports(...@@ -2658,7 +2615,7 @@ pub fn updateDeclExports(
2658 continue;2615 continue;
2659 },2616 },
2660 };2617 };
2661 const stt_bits: u8 = @as(u4, @truncate(decl_sym.st_info));2618 const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info));
26622619
2663 const sym_index = if (decl_metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {2620 const sym_index = if (decl_metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
2664 const zig_module = self.file(self.zig_module_index.?).?.zig_module;2621 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
...@@ -3220,7 +3177,7 @@ pub fn addSymbol(self: *Elf) !Symbol.Index {...@@ -3220,7 +3177,7 @@ pub fn addSymbol(self: *Elf) !Symbol.Index {
3220 break :blk index;3177 break :blk index;
3221 }3178 }
3222 };3179 };
3223 self.symbols.items[index] = .{ .symbol_index = index };3180 self.symbols.items[index] = .{ .index = index };
3224 return index;3181 return index;
3225}3182}
32263183
src/link/Elf/Atom.zig+64-7
...@@ -79,7 +79,7 @@ pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {...@@ -79,7 +79,7 @@ pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {
79 if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator);79 if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator);
80}80}
8181
82pub fn allocate(self: *Atom, elf_file: *Elf) !u64 {82pub fn allocate(self: *Atom, elf_file: *Elf) !void {
83 const phdr_index = elf_file.sections.items(.phdr_index)[self.output_section_index];83 const phdr_index = elf_file.sections.items(.phdr_index)[self.output_section_index];
84 const phdr = &elf_file.program_headers.items[phdr_index];84 const phdr = &elf_file.program_headers.items[phdr_index];
85 const shdr = &elf_file.sections.items(.shdr)[self.output_section_index];85 const shdr = &elf_file.sections.items(.shdr)[self.output_section_index];
...@@ -98,7 +98,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !u64 {...@@ -98,7 +98,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !u64 {
9898
99 // First we look for an appropriately sized free list node.99 // First we look for an appropriately sized free list node.
100 // The list is unordered. We'll just take the first thing that works.100 // The list is unordered. We'll just take the first thing that works.
101 const vaddr = blk: {101 self.value = blk: {
102 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;102 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;
103 while (i < free_list.items.len) {103 while (i < free_list.items.len) {
104 const big_atom_index = free_list.items[i];104 const big_atom_index = free_list.items[i];
...@@ -152,7 +152,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !u64 {...@@ -152,7 +152,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !u64 {
152 else152 else
153 true;153 true;
154 if (expand_section) {154 if (expand_section) {
155 const needed_size = (vaddr + self.size) - phdr.p_vaddr;155 const needed_size = (self.value + self.size) - phdr.p_vaddr;
156 try elf_file.growAllocSection(self.output_section_index, needed_size);156 try elf_file.growAllocSection(self.output_section_index, needed_size);
157 maybe_last_atom_index.* = self.atom_index;157 maybe_last_atom_index.* = self.atom_index;
158158
...@@ -193,7 +193,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !u64 {...@@ -193,7 +193,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !u64 {
193 if (free_list_removal) |i| {193 if (free_list_removal) |i| {
194 _ = free_list.swapRemove(i);194 _ = free_list.swapRemove(i);
195 }195 }
196 return vaddr;
197}196}
198197
199pub fn shrink(self: *Atom, elf_file: *Elf) void {198pub fn shrink(self: *Atom, elf_file: *Elf) void {
...@@ -201,12 +200,69 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void {...@@ -201,12 +200,69 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void {
201 _ = elf_file;200 _ = elf_file;
202}201}
203202
204pub fn grow(self: *Atom, elf_file: *Elf) !u64 {203pub fn grow(self: *Atom, elf_file: *Elf) !void {
205 const alignment = try std.math.powi(u64, 2, self.alignment);204 const alignment = try std.math.powi(u64, 2, self.alignment);
206 const align_ok = std.mem.alignBackward(u64, self.value, alignment) == self.value;205 const align_ok = std.mem.alignBackward(u64, self.value, alignment) == self.value;
207 const need_realloc = !align_ok or self.size > self.capacity(elf_file);206 const need_realloc = !align_ok or self.size > self.capacity(elf_file);
208 if (!need_realloc) return self.value;207 if (need_realloc) try self.allocate(elf_file);
209 return self.allocate(elf_file);208}
209
210pub fn free(self: *Atom, elf_file: *Elf) void {
211 log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });
212
213 Atom.freeRelocations(elf_file, self.atom_index);
214
215 const gpa = elf_file.base.allocator;
216 const shndx = self.output_section_index;
217 const free_list = &elf_file.sections.items(.free_list)[shndx];
218 var already_have_free_list_node = false;
219 {
220 var i: usize = 0;
221 // TODO turn free_list into a hash map
222 while (i < free_list.items.len) {
223 if (free_list.items[i] == self.atom_index) {
224 _ = free_list.swapRemove(i);
225 continue;
226 }
227 if (free_list.items[i] == self.prev_index) {
228 already_have_free_list_node = true;
229 }
230 i += 1;
231 }
232 }
233
234 const maybe_last_atom_index = &elf_file.sections.items(.last_atom_index)[shndx];
235 if (maybe_last_atom_index.*) |last_atom_index| {
236 if (last_atom_index == self.atom_index) {
237 if (self.prev_index) |prev_index| {
238 // TODO shrink the section size here
239 maybe_last_atom_index.* = prev_index;
240 } else {
241 maybe_last_atom_index.* = null;
242 }
243 }
244 }
245
246 if (self.prev_index) |prev_index| {
247 const prev = elf_file.atom(prev_index);
248 prev.next_index = self.next_index;
249
250 if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) {
251 // The free list is heuristics, it doesn't have to be perfect, so we can
252 // ignore the OOM here.
253 free_list.append(gpa, prev_index) catch {};
254 }
255 } else {
256 self.prev_index = null;
257 }
258
259 if (self.next_index) |next_index| {
260 elf_file.atom(next_index).prev_index = self.prev_index;
261 } else {
262 self.next_index = null;
263 }
264
265 self.* = .{};
210}266}
211267
212pub const Index = u32;268pub const Index = u32;
...@@ -221,6 +277,7 @@ pub const Reloc = struct {...@@ -221,6 +277,7 @@ pub const Reloc = struct {
221const std = @import("std");277const std = @import("std");
222const assert = std.debug.assert;278const assert = std.debug.assert;
223const elf = std.elf;279const elf = std.elf;
280const log = std.log.scoped(.link);
224281
225const Atom = @This();282const Atom = @This();
226const Elf = @import("../Elf.zig");283const Elf = @import("../Elf.zig");
src/link/Elf/Symbol.zig+13-7
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1//! Represents a defined symbol.1//! Represents a defined symbol.
22
3index: Index = 0,
4
3/// Allocated address value of this symbol.5/// Allocated address value of this symbol.
4value: u64 = 0,6value: u64 = 0,
57
...@@ -18,8 +20,8 @@ atom_index: Atom.Index = 0,...@@ -18,8 +20,8 @@ atom_index: Atom.Index = 0,
18output_section_index: u16 = 0,20output_section_index: u16 = 0,
1921
20/// Index of the source symbol this symbol references.22/// Index of the source symbol this symbol references.
21/// Use `getSourceSymbol` to pull the source symbol from the relevant file.23/// Use `sourceSymbol` to pull the source symbol from the relevant file.
22symbol_index: Index = 0,24esym_index: Index = 0,
2325
24/// Index of the source version symbol this symbol references if any.26/// Index of the source version symbol this symbol references if any.
25/// If the symbol is unversioned it will have either VER_NDX_LOCAL or VER_NDX_GLOBAL.27/// If the symbol is unversioned it will have either VER_NDX_LOCAL or VER_NDX_GLOBAL.
...@@ -64,7 +66,11 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {...@@ -64,7 +66,11 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
64}66}
6567
66pub fn sourceSymbol(symbol: Symbol, elf_file: *Elf) *elf.Elf64_Sym {68pub fn sourceSymbol(symbol: Symbol, elf_file: *Elf) *elf.Elf64_Sym {
67 return symbol.file(elf_file).?.sourceSymbol(symbol.symbol_index);69 const file_ptr = symbol.file(elf_file).?;
70 switch (file_ptr) {
71 .zig_module => return file_ptr.zig_module.sourceSymbol(symbol.index, elf_file),
72 .linker_defined => return file_ptr.linker_defined.sourceSymbol(symbol.esym_index),
73 }
68}74}
6975
70pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {76pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
...@@ -80,14 +86,14 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {...@@ -80,14 +86,14 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
80/// If entry already exists, returns index to it.86/// If entry already exists, returns index to it.
81/// Otherwise, creates a new entry in the Global Offset Table for this Symbol.87/// Otherwise, creates a new entry in the Global Offset Table for this Symbol.
82pub fn getOrCreateOffsetTableEntry(self: Symbol, elf_file: *Elf) !Symbol.Index {88pub fn getOrCreateOffsetTableEntry(self: Symbol, elf_file: *Elf) !Symbol.Index {
83 if (elf_file.got_table.lookup.get(self.symbol_index)) |index| return index;89 if (elf_file.got_table.lookup.get(self.index)) |index| return index;
84 const index = try elf_file.got_table.allocateEntry(elf_file.base.allocator, self.symbol_index);90 const index = try elf_file.got_table.allocateEntry(elf_file.base.allocator, self.index);
85 elf_file.got_table_count_dirty = true;91 elf_file.got_table_count_dirty = true;
86 return index;92 return index;
87}93}
8894
89pub fn getOffsetTableAddress(self: Symbol, elf_file: *Elf) u64 {95pub fn getOffsetTableAddress(self: Symbol, elf_file: *Elf) u64 {
90 const got_entry_index = elf_file.got_table.lookup.get(self.symbol_index).?;96 const got_entry_index = elf_file.got_table.lookup.get(self.index).?;
91 const target = elf_file.base.options.target;97 const target = elf_file.base.options.target;
92 const ptr_bits = target.ptrBitWidth();98 const ptr_bits = target.ptrBitWidth();
93 const ptr_bytes: u64 = @divExact(ptr_bits, 8);99 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
...@@ -263,7 +269,7 @@ fn format2(...@@ -263,7 +269,7 @@ fn format2(
263 _ = options;269 _ = options;
264 _ = unused_fmt_string;270 _ = unused_fmt_string;
265 const symbol = ctx.symbol;271 const symbol = ctx.symbol;
266 try writer.print("%{d} : {s} : @{x}", .{ symbol.symbol_index, symbol.fmtName(ctx.elf_file), symbol.value });272 try writer.print("%{d} : {s} : @{x}", .{ symbol.index, symbol.fmtName(ctx.elf_file), symbol.value });
267 if (symbol.file(ctx.elf_file)) |file_ptr| {273 if (symbol.file(ctx.elf_file)) |file_ptr| {
268 if (symbol.isAbs(ctx.elf_file)) {274 if (symbol.isAbs(ctx.elf_file)) {
269 if (symbol.sourceSymbol(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {275 if (symbol.sourceSymbol(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
src/link/Elf/ZigModule.zig+9-3
...@@ -33,6 +33,7 @@ pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !...@@ -33,6 +33,7 @@ pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !
33 symbol_ptr.file_index = self.index;33 symbol_ptr.file_index = self.index;
34 symbol_ptr.atom_index = atom_index;34 symbol_ptr.atom_index = atom_index;
35 symbol_ptr.output_section_index = output_section_index;35 symbol_ptr.output_section_index = output_section_index;
36 symbol_ptr.esym_index = @as(Symbol.Index, @intCast(self.elf_local_symbols.items.len));
3637
37 const local_esym = try self.elf_local_symbols.addOne(gpa);38 const local_esym = try self.elf_local_symbols.addOne(gpa);
38 local_esym.* = .{39 local_esym.* = .{
...@@ -55,6 +56,7 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I...@@ -55,6 +56,7 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I
55 try self.elf_global_symbols.ensureUnusedCapacity(gpa, 1);56 try self.elf_global_symbols.ensureUnusedCapacity(gpa, 1);
56 try self.global_symbols.ensureUnusedCapacity(gpa, 1);57 try self.global_symbols.ensureUnusedCapacity(gpa, 1);
57 const off = try elf_file.strtab.insert(gpa, name);58 const off = try elf_file.strtab.insert(gpa, name);
59 const esym_index = @as(Symbol.Index, @intCast(self.elf_global_symbols.items.len));
58 self.elf_global_symbols.appendAssumeCapacity(.{60 self.elf_global_symbols.appendAssumeCapacity(.{
59 .st_name = off,61 .st_name = off,
60 .st_info = elf.STB_GLOBAL << 4,62 .st_info = elf.STB_GLOBAL << 4,
...@@ -64,14 +66,18 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I...@@ -64,14 +66,18 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I
64 .st_size = 0,66 .st_size = 0,
65 });67 });
66 const gop = try elf_file.getOrPutGlobal(off);68 const gop = try elf_file.getOrPutGlobal(off);
69 const sym = elf_file.symbol(gop.index);
70 sym.file_index = self.index;
71 sym.esym_index = esym_index;
67 self.global_symbols.putAssumeCapacityNoClobber(gop.index, {});72 self.global_symbols.putAssumeCapacityNoClobber(gop.index, {});
68 return gop.index;73 return gop.index;
69}74}
7075
71pub fn sourceSymbol(self: *ZigModule, symbol_index: Symbol.Index) *elf.Elf64_Sym {76pub fn sourceSymbol(self: *ZigModule, symbol_index: Symbol.Index, elf_file: *Elf) *elf.Elf64_Sym {
72 if (self.local_symbols.get(symbol_index)) |_| return &self.elf_local_symbols.items[symbol_index];77 const sym = elf_file.symbol(symbol_index);
78 if (self.local_symbols.get(symbol_index)) |_| return &self.elf_local_symbols.items[sym.esym_index];
73 assert(self.global_symbols.get(symbol_index) != null);79 assert(self.global_symbols.get(symbol_index) != null);
74 return &self.elf_global_symbols.items[symbol_index];80 return &self.elf_global_symbols.items[sym.esym_index];
75}81}
7682
77pub fn locals(self: *ZigModule) []const Symbol.Index {83pub fn locals(self: *ZigModule) []const Symbol.Index {
src/link/Elf/file.zig-6
...@@ -10,12 +10,6 @@ pub const File = union(enum) {...@@ -10,12 +10,6 @@ pub const File = union(enum) {
10 };10 };
11 }11 }
1212
13 pub fn sourceSymbol(file: File, symbol_index: Symbol.Index) *elf.Elf64_Sym {
14 return switch (file) {
15 inline else => |x| x.sourceSymbol(symbol_index),
16 };
17 }
18
19 pub fn fmtPath(file: File) std.fmt.Formatter(formatPath) {13 pub fn fmtPath(file: File) std.fmt.Formatter(formatPath) {
20 return .{ .data = file };14 return .{ .data = file };
21 }15 }