authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-31 13:27:47+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-04 09:08:16+01:00
log25c53f08a6add493043a407ce15bc727dc33356d
tree13adbdc0251f44db469f374b82214a5f135eebce
parentf6de3ec963e3a7d96cd4f6c72b0f076f0437c45d

elf: redo strings management in the linker

* atom names - are stored locally and pulled from defining object's strtab * local symbols - same * global symbols - in principle, we could store them locally, but for better debugging experience - when things go wrong - we store the offsets in a global strtab used by the symbol resolver

17 files changed, 439 insertions(+), 620 deletions(-)

CMakeLists.txt+1-1
...@@ -624,7 +624,7 @@ set(ZIG_STAGE2_SOURCES...@@ -624,7 +624,7 @@ set(ZIG_STAGE2_SOURCES
624 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"624 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
625 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"625 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
626 "${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"626 "${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"
627 "${CMAKE_SOURCE_DIR}/src/link/strtab.zig"627 "${CMAKE_SOURCE_DIR}/src/link/StringTable.zig"
628 "${CMAKE_SOURCE_DIR}/src/link/tapi.zig"628 "${CMAKE_SOURCE_DIR}/src/link/tapi.zig"
629 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"629 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"
630 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig"630 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig"
src/link/Coff.zig+8-8
...@@ -33,10 +33,10 @@ need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{},...@@ -33,10 +33,10 @@ need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{},
33locals_free_list: std.ArrayListUnmanaged(u32) = .{},33locals_free_list: std.ArrayListUnmanaged(u32) = .{},
34globals_free_list: std.ArrayListUnmanaged(u32) = .{},34globals_free_list: std.ArrayListUnmanaged(u32) = .{},
3535
36strtab: StringTable(.strtab) = .{},36strtab: StringTable = .{},
37strtab_offset: ?u32 = null,37strtab_offset: ?u32 = null,
3838
39temp_strtab: StringTable(.temp_strtab) = .{},39temp_strtab: StringTable = .{},
4040
41got_table: TableSection(SymbolWithLoc) = .{},41got_table: TableSection(SymbolWithLoc) = .{},
4242
...@@ -418,7 +418,7 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -418,7 +418,7 @@ fn populateMissingMetadata(self: *Coff) !void {
418 }418 }
419419
420 if (self.strtab_offset == null) {420 if (self.strtab_offset == null) {
421 const file_size = @as(u32, @intCast(self.strtab.len()));421 const file_size = @as(u32, @intCast(self.strtab.buffer.items.len));
422 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here422 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here
423 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });423 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });
424 }424 }
...@@ -2142,7 +2142,7 @@ fn writeStrtab(self: *Coff) !void {...@@ -2142,7 +2142,7 @@ fn writeStrtab(self: *Coff) !void {
2142 if (self.strtab_offset == null) return;2142 if (self.strtab_offset == null) return;
21432143
2144 const allocated_size = self.allocatedSize(self.strtab_offset.?);2144 const allocated_size = self.allocatedSize(self.strtab_offset.?);
2145 const needed_size = @as(u32, @intCast(self.strtab.len()));2145 const needed_size = @as(u32, @intCast(self.strtab.buffer.items.len));
21462146
2147 if (needed_size > allocated_size) {2147 if (needed_size > allocated_size) {
2148 self.strtab_offset = null;2148 self.strtab_offset = null;
...@@ -2154,10 +2154,10 @@ fn writeStrtab(self: *Coff) !void {...@@ -2154,10 +2154,10 @@ fn writeStrtab(self: *Coff) !void {
2154 var buffer = std.ArrayList(u8).init(self.base.allocator);2154 var buffer = std.ArrayList(u8).init(self.base.allocator);
2155 defer buffer.deinit();2155 defer buffer.deinit();
2156 try buffer.ensureTotalCapacityPrecise(needed_size);2156 try buffer.ensureTotalCapacityPrecise(needed_size);
2157 buffer.appendSliceAssumeCapacity(self.strtab.items());2157 buffer.appendSliceAssumeCapacity(self.strtab.buffer.items);
2158 // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead2158 // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead
2159 // we write the length of the strtab to a temporary buffer that goes to file.2159 // we write the length of the strtab to a temporary buffer that goes to file.
2160 mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(self.strtab.len())), .little);2160 mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(self.strtab.buffer.items.len)), .little);
21612161
2162 try self.base.file.?.pwriteAll(buffer.items, self.strtab_offset.?);2162 try self.base.file.?.pwriteAll(buffer.items, self.strtab_offset.?);
2163}2163}
...@@ -2325,7 +2325,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {...@@ -2325,7 +2325,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
2325 const end = start + padToIdeal(size);2325 const end = start + padToIdeal(size);
23262326
2327 if (self.strtab_offset) |off| {2327 if (self.strtab_offset) |off| {
2328 const tight_size = @as(u32, @intCast(self.strtab.len()));2328 const tight_size = @as(u32, @intCast(self.strtab.buffer.items.len));
2329 const increased_size = padToIdeal(tight_size);2329 const increased_size = padToIdeal(tight_size);
2330 const test_end = off + increased_size;2330 const test_end = off + increased_size;
2331 if (end > off and start < test_end) {2331 if (end > off and start < test_end) {
...@@ -2666,7 +2666,7 @@ const InternPool = @import("../InternPool.zig");...@@ -2666,7 +2666,7 @@ const InternPool = @import("../InternPool.zig");
2666const Object = @import("Coff/Object.zig");2666const Object = @import("Coff/Object.zig");
2667const Relocation = @import("Coff/Relocation.zig");2667const Relocation = @import("Coff/Relocation.zig");
2668const TableSection = @import("table_section.zig").TableSection;2668const TableSection = @import("table_section.zig").TableSection;
2669const StringTable = @import("strtab.zig").StringTable;2669const StringTable = @import("StringTable.zig");
2670const Type = @import("../type.zig").Type;2670const Type = @import("../type.zig").Type;
2671const TypedValue = @import("../TypedValue.zig");2671const TypedValue = @import("../TypedValue.zig");
26722672
src/link/Dwarf.zig+2-2
...@@ -23,7 +23,7 @@ abbrev_table_offset: ?u64 = null,...@@ -23,7 +23,7 @@ abbrev_table_offset: ?u64 = null,
2323
24/// TODO replace with InternPool24/// TODO replace with InternPool
25/// Table of debug symbol names.25/// Table of debug symbol names.
26strtab: StringTable(.strtab) = .{},26strtab: StringTable = .{},
2727
28/// Quick lookup array of all defined source files referenced by at least one Decl.28/// Quick lookup array of all defined source files referenced by at least one Decl.
29/// They will end up in the DWARF debug_line header as two lists:29/// They will end up in the DWARF debug_line header as two lists:
...@@ -2760,6 +2760,6 @@ const LinkFn = File.LinkFn;...@@ -2760,6 +2760,6 @@ const LinkFn = File.LinkFn;
2760const LinkerLoad = @import("../codegen.zig").LinkerLoad;2760const LinkerLoad = @import("../codegen.zig").LinkerLoad;
2761const Module = @import("../Module.zig");2761const Module = @import("../Module.zig");
2762const InternPool = @import("../InternPool.zig");2762const InternPool = @import("../InternPool.zig");
2763const StringTable = @import("strtab.zig").StringTable;2763const StringTable = @import("StringTable.zig");
2764const Type = @import("../type.zig").Type;2764const Type = @import("../type.zig").Type;
2765const Value = @import("../value.zig").Value;2765const Value = @import("../value.zig").Value;
src/link/Elf.zig+138-107
...@@ -66,13 +66,15 @@ page_size: u32,...@@ -66,13 +66,15 @@ page_size: u32,
66default_sym_version: elf.Elf64_Versym,66default_sym_version: elf.Elf64_Versym,
6767
68/// .shstrtab buffer68/// .shstrtab buffer
69shstrtab: StringTable(.strtab) = .{},69shstrtab: std.ArrayListUnmanaged(u8) = .{},
70/// .symtab buffer
71symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
70/// .strtab buffer72/// .strtab buffer
71strtab: StringTable(.strtab) = .{},73strtab: std.ArrayListUnmanaged(u8) = .{},
72/// Dynamic symbol table. Only populated and emitted when linking dynamically.74/// Dynamic symbol table. Only populated and emitted when linking dynamically.
73dynsym: DynsymSection = .{},75dynsym: DynsymSection = .{},
74/// .dynstrtab buffer76/// .dynstrtab buffer
75dynstrtab: StringTable(.dynstrtab) = .{},77dynstrtab: std.ArrayListUnmanaged(u8) = .{},
76/// Version symbol table. Only populated and emitted when linking dynamically.78/// Version symbol table. Only populated and emitted when linking dynamically.
77versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},79versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
78/// .verneed section80/// .verneed section
...@@ -156,9 +158,10 @@ start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},...@@ -156,9 +158,10 @@ start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
156/// An array of symbols parsed across all input files.158/// An array of symbols parsed across all input files.
157symbols: std.ArrayListUnmanaged(Symbol) = .{},159symbols: std.ArrayListUnmanaged(Symbol) = .{},
158symbols_extra: std.ArrayListUnmanaged(u32) = .{},160symbols_extra: std.ArrayListUnmanaged(u32) = .{},
159resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
160symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},161symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
161162
163resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
164
162has_text_reloc: bool = false,165has_text_reloc: bool = false,
163num_ifunc_dynrelocs: usize = 0,166num_ifunc_dynrelocs: usize = 0,
164167
...@@ -175,6 +178,10 @@ comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},...@@ -175,6 +178,10 @@ comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
175comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},178comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
176comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},179comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
177180
181/// Global string table used to provide quick access to global symbol resolvers
182/// such as `resolver` and `comdat_groups_table`.
183strings: StringTable = .{},
184
178/// When allocating, the ideal_capacity is calculated by185/// When allocating, the ideal_capacity is calculated by
179/// actual_capacity + (actual_capacity / ideal_factor)186/// actual_capacity + (actual_capacity / ideal_factor)
180const ideal_factor = 3;187const ideal_factor = 3;
...@@ -227,13 +234,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -227,13 +234,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
227 // Append null file at index 0234 // Append null file at index 0
228 try self.files.append(allocator, .null);235 try self.files.append(allocator, .null);
229 // Append null byte to string tables236 // Append null byte to string tables
230 try self.shstrtab.buffer.append(allocator, 0);237 try self.shstrtab.append(allocator, 0);
231 try self.strtab.buffer.append(allocator, 0);238 try self.strtab.append(allocator, 0);
232 // There must always be a null shdr in index 0239 // There must always be a null shdr in index 0
233 _ = try self.addSection(.{ .name = "" });240 _ = try self.addSection(.{ .name = "" });
241 // Append null symbol in output symtab
242 try self.symtab.append(allocator, null_sym);
234243
235 if (!is_obj_or_ar) {244 if (!is_obj_or_ar) {
236 try self.dynstrtab.buffer.append(allocator, 0);245 try self.dynstrtab.append(allocator, 0);
237246
238 // Initialize PT_PHDR program header247 // Initialize PT_PHDR program header
239 const p_align: u16 = switch (self.ptr_width) {248 const p_align: u16 = switch (self.ptr_width) {
...@@ -347,6 +356,7 @@ pub fn deinit(self: *Elf) void {...@@ -347,6 +356,7 @@ pub fn deinit(self: *Elf) void {
347 }356 }
348 self.output_sections.deinit(gpa);357 self.output_sections.deinit(gpa);
349 self.shstrtab.deinit(gpa);358 self.shstrtab.deinit(gpa);
359 self.symtab.deinit(gpa);
350 self.strtab.deinit(gpa);360 self.strtab.deinit(gpa);
351 self.symbols.deinit(gpa);361 self.symbols.deinit(gpa);
352 self.symbols_extra.deinit(gpa);362 self.symbols_extra.deinit(gpa);
...@@ -364,6 +374,7 @@ pub fn deinit(self: *Elf) void {...@@ -364,6 +374,7 @@ pub fn deinit(self: *Elf) void {
364 self.comdat_groups.deinit(gpa);374 self.comdat_groups.deinit(gpa);
365 self.comdat_groups_owners.deinit(gpa);375 self.comdat_groups_owners.deinit(gpa);
366 self.comdat_groups_table.deinit(gpa);376 self.comdat_groups_table.deinit(gpa);
377 self.strings.deinit(gpa);
367378
368 self.got.deinit(gpa);379 self.got.deinit(gpa);
369 self.plt.deinit(gpa);380 self.plt.deinit(gpa);
...@@ -747,7 +758,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {...@@ -747,7 +758,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
747 const new_offset = self.findFreeSpace(needed_size, self.page_size);758 const new_offset = self.findFreeSpace(needed_size, self.page_size);
748759
749 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{760 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
750 self.shstrtab.getAssumeExists(shdr.sh_name),761 self.getShString(shdr.sh_name),
751 new_offset,762 new_offset,
752 new_offset + existing_size,763 new_offset + existing_size,
753 });764 });
...@@ -796,7 +807,7 @@ pub fn growNonAllocSection(...@@ -796,7 +807,7 @@ pub fn growNonAllocSection(
796 const new_offset = self.findFreeSpace(needed_size, min_alignment);807 const new_offset = self.findFreeSpace(needed_size, min_alignment);
797808
798 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{809 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
799 self.shstrtab.getAssumeExists(shdr.sh_name),810 self.getShString(shdr.sh_name),
800 new_offset,811 new_offset,
801 new_offset + existing_size,812 new_offset + existing_size,
802 });813 });
...@@ -1696,7 +1707,7 @@ fn accessLibPath(...@@ -1696,7 +1707,7 @@ fn accessLibPath(
1696/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1707/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1697fn resolveSymbols(self: *Elf) void {1708fn resolveSymbols(self: *Elf) void {
1698 // Resolve symbols in the ZigObject. For now, we assume that it's always live.1709 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1699 if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self);1710 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
1700 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1711 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
1701 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1712 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
1702 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1713 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
...@@ -1705,7 +1716,7 @@ fn resolveSymbols(self: *Elf) void {...@@ -1705,7 +1716,7 @@ fn resolveSymbols(self: *Elf) void {
1705 self.markLive();1716 self.markLive();
17061717
1707 // Reset state of all globals after marking live objects.1718 // Reset state of all globals after marking live objects.
1708 if (self.zigObjectPtr()) |zig_object| zig_object.resetGlobals(self);1719 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);
1709 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);1720 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
1710 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);1721 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
17111722
...@@ -1767,7 +1778,7 @@ fn resolveSymbols(self: *Elf) void {...@@ -1767,7 +1778,7 @@ fn resolveSymbols(self: *Elf) void {
1767/// This routine will prune unneeded objects extracted from archives and1778/// This routine will prune unneeded objects extracted from archives and
1768/// unneeded shared objects.1779/// unneeded shared objects.
1769fn markLive(self: *Elf) void {1780fn markLive(self: *Elf) void {
1770 if (self.zigObjectPtr()) |zig_object| zig_object.markLive(self);1781 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().markLive(self);
1771 for (self.objects.items) |index| {1782 for (self.objects.items) |index| {
1772 const file_ptr = self.file(index).?;1783 const file_ptr = self.file(index).?;
1773 if (file_ptr.isAlive()) file_ptr.markLive(self);1784 if (file_ptr.isAlive()) file_ptr.markLive(self);
...@@ -3358,7 +3369,7 @@ fn sortInitFini(self: *Elf) !void {...@@ -3358,7 +3369,7 @@ fn sortInitFini(self: *Elf) !void {
3358 elf.SHT_FINI_ARRAY,3369 elf.SHT_FINI_ARRAY,
3359 => is_init_fini = true,3370 => is_init_fini = true,
3360 else => {3371 else => {
3361 const name = self.shstrtab.getAssumeExists(shdr.sh_name);3372 const name = self.getShString(shdr.sh_name);
3362 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;3373 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;
3363 },3374 },
3364 }3375 }
...@@ -3520,7 +3531,7 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {...@@ -3520,7 +3531,7 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
35203531
3521fn shdrRank(self: *Elf, shndx: u16) u8 {3532fn shdrRank(self: *Elf, shndx: u16) u8 {
3522 const shdr = self.shdrs.items[shndx];3533 const shdr = self.shdrs.items[shndx];
3523 const name = self.shstrtab.getAssumeExists(shdr.sh_name);3534 const name = self.getShString(shdr.sh_name);
3524 const flags = shdr.sh_flags;3535 const flags = shdr.sh_flags;
35253536
3526 switch (shdr.sh_type) {3537 switch (shdr.sh_type) {
...@@ -3801,7 +3812,7 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3801,7 +3812,7 @@ fn updateSectionSizes(self: *Elf) !void {
3801 }3812 }
38023813
3803 if (self.dynstrtab_section_index) |index| {3814 if (self.dynstrtab_section_index) |index| {
3804 self.shdrs.items[index].sh_size = self.dynstrtab.buffer.items.len;3815 self.shdrs.items[index].sh_size = self.dynstrtab.items.len;
3805 }3816 }
38063817
3807 if (self.versym_section_index) |index| {3818 if (self.versym_section_index) |index| {
...@@ -3816,26 +3827,8 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3816,26 +3827,8 @@ fn updateSectionSizes(self: *Elf) !void {
3816 try self.updateSymtabSize();3827 try self.updateSymtabSize();
3817 }3828 }
38183829
3819 if (self.strtab_section_index) |index| {
3820 // TODO I don't really this here but we need it to add symbol names from GOT and other synthetic
3821 // sections into .strtab for easier debugging.
3822 if (self.zig_got_section_index) |_| {
3823 try self.zig_got.updateStrtab(self);
3824 }
3825 if (self.got_section_index) |_| {
3826 try self.got.updateStrtab(self);
3827 }
3828 if (self.plt_section_index) |_| {
3829 try self.plt.updateStrtab(self);
3830 }
3831 if (self.plt_got_section_index) |_| {
3832 try self.plt_got.updateStrtab(self);
3833 }
3834 self.shdrs.items[index].sh_size = self.strtab.buffer.items.len;
3835 }
3836
3837 if (self.shstrtab_section_index) |index| {3830 if (self.shstrtab_section_index) |index| {
3838 self.shdrs.items[index].sh_size = self.shstrtab.buffer.items.len;3831 self.shdrs.items[index].sh_size = self.shstrtab.items.len;
3839 }3832 }
3840}3833}
38413834
...@@ -4074,7 +4067,7 @@ fn allocateNonAllocSections(self: *Elf) !void {...@@ -4074,7 +4067,7 @@ fn allocateNonAllocSections(self: *Elf) !void {
40744067
4075 if (self.isDebugSection(@intCast(shndx))) {4068 if (self.isDebugSection(@intCast(shndx))) {
4076 log.debug("moving {s} from 0x{x} to 0x{x}", .{4069 log.debug("moving {s} from 0x{x} to 0x{x}", .{
4077 self.shstrtab.getAssumeExists(shdr.sh_name),4070 self.getShString(shdr.sh_name),
4078 shdr.sh_offset,4071 shdr.sh_offset,
4079 new_offset,4072 new_offset,
4080 });4073 });
...@@ -4187,7 +4180,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -4187,7 +4180,7 @@ fn writeAtoms(self: *Elf) !void {
41874180
4188 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;4181 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
41894182
4190 log.debug("writing atoms in '{s}' section", .{self.shstrtab.getAssumeExists(shdr.sh_name)});4183 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
41914184
4192 // TODO really, really handle debug section separately4185 // TODO really, really handle debug section separately
4193 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {4186 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
...@@ -4256,60 +4249,61 @@ fn updateSymtabSize(self: *Elf) !void {...@@ -4256,60 +4249,61 @@ fn updateSymtabSize(self: *Elf) !void {
4256 var sizes = SymtabSize{};4249 var sizes = SymtabSize{};
42574250
4258 if (self.zigObjectPtr()) |zig_object| {4251 if (self.zigObjectPtr()) |zig_object| {
4259 zig_object.updateSymtabSize(self);4252 zig_object.asFile().updateSymtabSize(self);
4260 sizes.nlocals += zig_object.output_symtab_size.nlocals;4253 sizes.add(zig_object.output_symtab_size);
4261 sizes.nglobals += zig_object.output_symtab_size.nglobals;
4262 }4254 }
42634255
4264 for (self.objects.items) |index| {4256 for (self.objects.items) |index| {
4265 const object = self.file(index).?.object;4257 const file_ptr = self.file(index).?;
4266 object.updateSymtabSize(self);4258 file_ptr.updateSymtabSize(self);
4267 sizes.nlocals += object.output_symtab_size.nlocals;4259 sizes.add(file_ptr.object.output_symtab_size);
4268 sizes.nglobals += object.output_symtab_size.nglobals;
4269 }4260 }
42704261
4271 for (self.shared_objects.items) |index| {4262 for (self.shared_objects.items) |index| {
4272 const shared_object = self.file(index).?.shared_object;4263 const file_ptr = self.file(index).?;
4273 shared_object.updateSymtabSize(self);4264 file_ptr.updateSymtabSize(self);
4274 sizes.nglobals += shared_object.output_symtab_size.nglobals;4265 sizes.add(file_ptr.shared_object.output_symtab_size);
4275 }4266 }
42764267
4277 if (self.zig_got_section_index) |_| {4268 if (self.zig_got_section_index) |_| {
4278 self.zig_got.updateSymtabSize(self);4269 self.zig_got.updateSymtabSize(self);
4279 sizes.nlocals += self.zig_got.output_symtab_size.nlocals;4270 sizes.add(self.zig_got.output_symtab_size);
4280 }4271 }
42814272
4282 if (self.got_section_index) |_| {4273 if (self.got_section_index) |_| {
4283 self.got.updateSymtabSize(self);4274 self.got.updateSymtabSize(self);
4284 sizes.nlocals += self.got.output_symtab_size.nlocals;4275 sizes.add(self.got.output_symtab_size);
4285 }4276 }
42864277
4287 if (self.plt_section_index) |_| {4278 if (self.plt_section_index) |_| {
4288 self.plt.updateSymtabSize(self);4279 self.plt.updateSymtabSize(self);
4289 sizes.nlocals += self.plt.output_symtab_size.nlocals;4280 sizes.add(self.plt.output_symtab_size);
4290 }4281 }
42914282
4292 if (self.plt_got_section_index) |_| {4283 if (self.plt_got_section_index) |_| {
4293 self.plt_got.updateSymtabSize(self);4284 self.plt_got.updateSymtabSize(self);
4294 sizes.nlocals += self.plt_got.output_symtab_size.nlocals;4285 sizes.add(self.plt_got.output_symtab_size);
4295 }4286 }
42964287
4297 if (self.linker_defined_index) |index| {4288 if (self.linker_defined_index) |index| {
4298 const linker_defined = self.file(index).?.linker_defined;4289 const file_ptr = self.file(index).?;
4299 linker_defined.updateSymtabSize(self);4290 file_ptr.updateSymtabSize(self);
4300 sizes.nlocals += linker_defined.output_symtab_size.nlocals;4291 sizes.add(file_ptr.linker_defined.output_symtab_size);
4301 }4292 }
43024293
4303 const shdr = &self.shdrs.items[self.symtab_section_index.?];4294 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
4304 shdr.sh_info = sizes.nlocals + 1;4295 symtab_shdr.sh_info = sizes.nlocals + 1;
4305 shdr.sh_link = self.strtab_section_index.?;4296 symtab_shdr.sh_link = self.strtab_section_index.?;
43064297
4307 const sym_size: u64 = switch (self.ptr_width) {4298 const sym_size: u64 = switch (self.ptr_width) {
4308 .p32 => @sizeOf(elf.Elf32_Sym),4299 .p32 => @sizeOf(elf.Elf32_Sym),
4309 .p64 => @sizeOf(elf.Elf64_Sym),4300 .p64 => @sizeOf(elf.Elf64_Sym),
4310 };4301 };
4311 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;4302 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
4312 shdr.sh_size = needed_size;4303 symtab_shdr.sh_size = needed_size;
4304
4305 const strtab = &self.shdrs.items[self.strtab_section_index.?];
4306 strtab.sh_size = sizes.strsize + 1;
4313}4307}
43144308
4315fn writeSyntheticSections(self: *Elf) !void {4309fn writeSyntheticSections(self: *Elf) !void {
...@@ -4370,7 +4364,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4370,7 +4364,7 @@ fn writeSyntheticSections(self: *Elf) !void {
43704364
4371 if (self.dynstrtab_section_index) |shndx| {4365 if (self.dynstrtab_section_index) |shndx| {
4372 const shdr = self.shdrs.items[shndx];4366 const shdr = self.shdrs.items[shndx];
4373 try self.base.file.?.pwriteAll(self.dynstrtab.buffer.items, shdr.sh_offset);4367 try self.base.file.?.pwriteAll(self.dynstrtab.items, shdr.sh_offset);
4374 }4368 }
43754369
4376 if (self.eh_frame_section_index) |shndx| {4370 if (self.eh_frame_section_index) |shndx| {
...@@ -4440,12 +4434,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4440,12 +4434,7 @@ fn writeSyntheticSections(self: *Elf) !void {
44404434
4441 if (self.shstrtab_section_index) |index| {4435 if (self.shstrtab_section_index) |index| {
4442 const shdr = self.shdrs.items[index];4436 const shdr = self.shdrs.items[index];
4443 try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shdr.sh_offset);4437 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
4444 }
4445
4446 if (self.strtab_section_index) |index| {
4447 const shdr = self.shdrs.items[index];
4448 try self.base.file.?.pwriteAll(self.strtab.buffer.items, shdr.sh_offset);
4449 }4438 }
44504439
4451 if (self.symtab_section_index) |_| {4440 if (self.symtab_section_index) |_| {
...@@ -4455,77 +4444,83 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4455,77 +4444,83 @@ fn writeSyntheticSections(self: *Elf) !void {
44554444
4456fn writeSymtab(self: *Elf) !void {4445fn writeSymtab(self: *Elf) !void {
4457 const gpa = self.base.allocator;4446 const gpa = self.base.allocator;
4458 const shdr = &self.shdrs.items[self.symtab_section_index.?];4447 const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
4448 const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
4459 const sym_size: u64 = switch (self.ptr_width) {4449 const sym_size: u64 = switch (self.ptr_width) {
4460 .p32 => @sizeOf(elf.Elf32_Sym),4450 .p32 => @sizeOf(elf.Elf32_Sym),
4461 .p64 => @sizeOf(elf.Elf64_Sym),4451 .p64 => @sizeOf(elf.Elf64_Sym),
4462 };4452 };
4463 const nsyms = math.cast(usize, @divExact(shdr.sh_size, sym_size)) orelse return error.Overflow;4453 const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;
4454
4455 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset });
44644456
4465 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, shdr.sh_offset });4457 try self.symtab.resize(gpa, nsyms);
4458 try self.strtab.ensureUnusedCapacity(gpa, strtab_shdr.sh_size - 1);
44664459
4467 const symtab = try gpa.alloc(elf.Elf64_Sym, nsyms);4460 const Ctx = struct {
4468 defer gpa.free(symtab);4461 ilocal: usize,
4469 symtab[0] = null_sym;4462 iglobal: usize,
44704463
4471 var ctx: struct { ilocal: usize, iglobal: usize, symtab: []elf.Elf64_Sym } = .{4464 fn incr(this: *@This(), ss: SymtabSize) void {
4465 this.ilocal += ss.nlocals;
4466 this.iglobal += ss.nglobals;
4467 }
4468 };
4469 var ctx: Ctx = .{
4472 .ilocal = 1,4470 .ilocal = 1,
4473 .iglobal = shdr.sh_info,4471 .iglobal = symtab_shdr.sh_info,
4474 .symtab = symtab,
4475 };4472 };
44764473
4477 if (self.zigObjectPtr()) |zig_object| {4474 if (self.zigObjectPtr()) |zig_object| {
4478 zig_object.writeSymtab(self, ctx);4475 zig_object.asFile().writeSymtab(self, ctx);
4479 ctx.ilocal += zig_object.output_symtab_size.nlocals;4476 ctx.incr(zig_object.output_symtab_size);
4480 ctx.iglobal += zig_object.output_symtab_size.nglobals;
4481 }4477 }
44824478
4483 for (self.objects.items) |index| {4479 for (self.objects.items) |index| {
4484 const object = self.file(index).?.object;4480 const file_ptr = self.file(index).?;
4485 object.writeSymtab(self, ctx);4481 file_ptr.writeSymtab(self, ctx);
4486 ctx.ilocal += object.output_symtab_size.nlocals;4482 ctx.incr(file_ptr.object.output_symtab_size);
4487 ctx.iglobal += object.output_symtab_size.nglobals;
4488 }4483 }
44894484
4490 for (self.shared_objects.items) |index| {4485 for (self.shared_objects.items) |index| {
4491 const shared_object = self.file(index).?.shared_object;4486 const file_ptr = self.file(index).?;
4492 shared_object.writeSymtab(self, ctx);4487 file_ptr.writeSymtab(self, ctx);
4493 ctx.iglobal += shared_object.output_symtab_size.nglobals;4488 ctx.incr(file_ptr.shared_object.output_symtab_size);
4494 }4489 }
44954490
4496 if (self.zig_got_section_index) |_| {4491 if (self.zig_got_section_index) |_| {
4497 try self.zig_got.writeSymtab(self, ctx);4492 self.zig_got.writeSymtab(self, ctx);
4498 ctx.ilocal += self.zig_got.output_symtab_size.nlocals;4493 ctx.incr(self.zig_got.output_symtab_size);
4499 }4494 }
45004495
4501 if (self.got_section_index) |_| {4496 if (self.got_section_index) |_| {
4502 try self.got.writeSymtab(self, ctx);4497 self.got.writeSymtab(self, ctx);
4503 ctx.ilocal += self.got.output_symtab_size.nlocals;4498 ctx.incr(self.got.output_symtab_size);
4504 }4499 }
45054500
4506 if (self.plt_section_index) |_| {4501 if (self.plt_section_index) |_| {
4507 try self.plt.writeSymtab(self, ctx);4502 self.plt.writeSymtab(self, ctx);
4508 ctx.ilocal += self.plt.output_symtab_size.nlocals;4503 ctx.incr(self.plt.output_symtab_size);
4509 }4504 }
45104505
4511 if (self.plt_got_section_index) |_| {4506 if (self.plt_got_section_index) |_| {
4512 try self.plt_got.writeSymtab(self, ctx);4507 self.plt_got.writeSymtab(self, ctx);
4513 ctx.ilocal += self.plt_got.output_symtab_size.nlocals;4508 ctx.incr(self.plt_got.output_symtab_size);
4514 }4509 }
45154510
4516 if (self.linker_defined_index) |index| {4511 if (self.linker_defined_index) |index| {
4517 const linker_defined = self.file(index).?.linker_defined;4512 const file_ptr = self.file(index).?;
4518 linker_defined.writeSymtab(self, ctx);4513 file_ptr.writeSymtab(self, ctx);
4519 ctx.ilocal += linker_defined.output_symtab_size.nlocals;4514 ctx.incr(file_ptr.linker_defined.output_symtab_size);
4520 }4515 }
45214516
4522 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();4517 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
4523 switch (self.ptr_width) {4518 switch (self.ptr_width) {
4524 .p32 => {4519 .p32 => {
4525 const buf = try gpa.alloc(elf.Elf32_Sym, symtab.len);4520 const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
4526 defer gpa.free(buf);4521 defer gpa.free(buf);
45274522
4528 for (buf, symtab) |*out, sym| {4523 for (buf, self.symtab.items) |*out, sym| {
4529 out.* = .{4524 out.* = .{
4530 .st_name = sym.st_name,4525 .st_name = sym.st_name,
4531 .st_info = sym.st_info,4526 .st_info = sym.st_info,
...@@ -4536,15 +4531,17 @@ fn writeSymtab(self: *Elf) !void {...@@ -4536,15 +4531,17 @@ fn writeSymtab(self: *Elf) !void {
4536 };4531 };
4537 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);4532 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
4538 }4533 }
4539 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), shdr.sh_offset);4534 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
4540 },4535 },
4541 .p64 => {4536 .p64 => {
4542 if (foreign_endian) {4537 if (foreign_endian) {
4543 for (symtab) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);4538 for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
4544 }4539 }
4545 try self.base.file.?.pwriteAll(mem.sliceAsBytes(symtab), shdr.sh_offset);4540 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset);
4546 },4541 },
4547 }4542 }
4543
4544 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
4548}4545}
45494546
4550/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.4547/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
...@@ -4925,7 +4922,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {...@@ -4925,7 +4922,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
4925 const index = @as(u16, @intCast(self.shdrs.items.len));4922 const index = @as(u16, @intCast(self.shdrs.items.len));
4926 const shdr = try self.shdrs.addOne(gpa);4923 const shdr = try self.shdrs.addOne(gpa);
4927 shdr.* = .{4924 shdr.* = .{
4928 .sh_name = try self.shstrtab.insert(gpa, opts.name),4925 .sh_name = try self.insertShString(opts.name),
4929 .sh_type = opts.type,4926 .sh_type = opts.type,
4930 .sh_flags = opts.flags,4927 .sh_flags = opts.flags,
4931 .sh_addr = 0,4928 .sh_addr = 0,
...@@ -4941,7 +4938,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {...@@ -4941,7 +4938,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
49414938
4942pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {4939pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {
4943 for (self.shdrs.items, 0..) |*shdr, i| {4940 for (self.shdrs.items, 0..) |*shdr, i| {
4944 const this_name = self.shstrtab.getAssumeExists(shdr.sh_name);4941 const this_name = self.getShString(shdr.sh_name);
4945 if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));4942 if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));
4946 } else return null;4943 } else return null;
4947}4944}
...@@ -5114,13 +5111,15 @@ const GetOrPutGlobalResult = struct {...@@ -5114,13 +5111,15 @@ const GetOrPutGlobalResult = struct {
5114 index: Symbol.Index,5111 index: Symbol.Index,
5115};5112};
51165113
5117pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {5114pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
5118 const gpa = self.base.allocator;5115 const gpa = self.base.allocator;
5116 const name_off = try self.strings.insert(gpa, name);
5119 const gop = try self.resolver.getOrPut(gpa, name_off);5117 const gop = try self.resolver.getOrPut(gpa, name_off);
5120 if (!gop.found_existing) {5118 if (!gop.found_existing) {
5121 const index = try self.addSymbol();5119 const index = try self.addSymbol();
5122 const global = self.symbol(index);5120 const global = self.symbol(index);
5123 global.name_offset = name_off;5121 global.name_offset = name_off;
5122 global.flags.global = true;
5124 gop.value_ptr.* = index;5123 gop.value_ptr.* = index;
5125 }5124 }
5126 return .{5125 return .{
...@@ -5130,7 +5129,7 @@ pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {...@@ -5130,7 +5129,7 @@ pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {
5130}5129}
51315130
5132pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {5131pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
5133 const name_off = self.strtab.getOffset(name) orelse return null;5132 const name_off = self.strings.getOffset(name) orelse return null;
5134 return self.resolver.get(name_off);5133 return self.resolver.get(name_off);
5135}5134}
51365135
...@@ -5148,8 +5147,9 @@ const GetOrCreateComdatGroupOwnerResult = struct {...@@ -5148,8 +5147,9 @@ const GetOrCreateComdatGroupOwnerResult = struct {
5148 index: ComdatGroupOwner.Index,5147 index: ComdatGroupOwner.Index,
5149};5148};
51505149
5151pub fn getOrCreateComdatGroupOwner(self: *Elf, off: u32) !GetOrCreateComdatGroupOwnerResult {5150pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateComdatGroupOwnerResult {
5152 const gpa = self.base.allocator;5151 const gpa = self.base.allocator;
5152 const off = try self.strings.insert(gpa, name);
5153 const gop = try self.comdat_groups_table.getOrPut(gpa, off);5153 const gop = try self.comdat_groups_table.getOrPut(gpa, off);
5154 if (!gop.found_existing) {5154 if (!gop.found_existing) {
5155 const index = @as(ComdatGroupOwner.Index, @intCast(self.comdat_groups_owners.items.len));5155 const index = @as(ComdatGroupOwner.Index, @intCast(self.comdat_groups_owners.items.len));
...@@ -5239,6 +5239,30 @@ fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMem...@@ -5239,6 +5239,30 @@ fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMem
5239 return .{ .index = index };5239 return .{ .index = index };
5240}5240}
52415241
5242pub fn getShString(self: Elf, off: u32) [:0]const u8 {
5243 assert(off < self.shstrtab.items.len);
5244 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.shstrtab.items.ptr + off)), 0);
5245}
5246
5247pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {
5248 const off = @as(u32, @intCast(self.shstrtab.items.len));
5249 try self.shstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
5250 self.shstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
5251 return off;
5252}
5253
5254pub fn getDynString(self: Elf, off: u32) [:0]const u8 {
5255 assert(off < self.dynstrtab.items.len);
5256 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.dynstrtab.items.ptr + off)), 0);
5257}
5258
5259pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
5260 const off = @as(u32, @intCast(self.dynstrtab.items.len));
5261 try self.dynstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
5262 self.dynstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
5263 return off;
5264}
5265
5242fn reportUndefined(self: *Elf, undefs: anytype) !void {5266fn reportUndefined(self: *Elf, undefs: anytype) !void {
5243 const gpa = self.base.allocator;5267 const gpa = self.base.allocator;
5244 const max_notes = 4;5268 const max_notes = 4;
...@@ -5340,8 +5364,8 @@ fn formatShdr(...@@ -5340,8 +5364,8 @@ fn formatShdr(
5340 _ = unused_fmt_string;5364 _ = unused_fmt_string;
5341 const shdr = ctx.shdr;5365 const shdr = ctx.shdr;
5342 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{5366 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{
5343 ctx.elf_file.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset,5367 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
5344 shdr.sh_addr, shdr.sh_addralign,5368 shdr.sh_addr, shdr.sh_addralign,
5345 shdr.sh_size,5369 shdr.sh_size,
5346 });5370 });
5347}5371}
...@@ -5516,6 +5540,13 @@ pub const ComdatGroup = struct {...@@ -5516,6 +5540,13 @@ pub const ComdatGroup = struct {
5516pub const SymtabSize = struct {5540pub const SymtabSize = struct {
5517 nlocals: u32 = 0,5541 nlocals: u32 = 0,
5518 nglobals: u32 = 0,5542 nglobals: u32 = 0,
5543 strsize: u32 = 0,
5544
5545 fn add(ss: *SymtabSize, other: SymtabSize) void {
5546 ss.nlocals += other.nlocals;
5547 ss.nglobals += other.nglobals;
5548 ss.strsize += other.strsize;
5549 }
5519};5550};
55205551
5521pub const null_sym = elf.Elf64_Sym{5552pub const null_sym = elf.Elf64_Sym{
...@@ -5621,7 +5652,7 @@ const PltSection = synthetic_sections.PltSection;...@@ -5621,7 +5652,7 @@ const PltSection = synthetic_sections.PltSection;
5621const PltGotSection = synthetic_sections.PltGotSection;5652const PltGotSection = synthetic_sections.PltGotSection;
5622const SharedObject = @import("Elf/SharedObject.zig");5653const SharedObject = @import("Elf/SharedObject.zig");
5623const Symbol = @import("Elf/Symbol.zig");5654const Symbol = @import("Elf/Symbol.zig");
5624const StringTable = @import("strtab.zig").StringTable;5655const StringTable = @import("StringTable.zig");
5625const TypedValue = @import("../TypedValue.zig");5656const TypedValue = @import("../TypedValue.zig");
5626const VerneedSection = synthetic_sections.VerneedSection;5657const VerneedSection = synthetic_sections.VerneedSection;
5627const ZigGotSection = synthetic_sections.ZigGotSection;5658const ZigGotSection = synthetic_sections.ZigGotSection;
src/link/Elf/Atom.zig+5-2
...@@ -42,7 +42,10 @@ next_index: Index = 0,...@@ -42,7 +42,10 @@ next_index: Index = 0,
42pub const Alignment = @import("../../InternPool.zig").Alignment;42pub const Alignment = @import("../../InternPool.zig").Alignment;
4343
44pub fn name(self: Atom, elf_file: *Elf) []const u8 {44pub fn name(self: Atom, elf_file: *Elf) []const u8 {
45 return elf_file.strtab.getAssumeExists(self.name_offset);45 const file_ptr = self.file(elf_file).?;
46 return switch (file_ptr) {
47 inline else => |x| x.getString(self.name_offset),
48 };
46}49}
4750
48pub fn file(self: Atom, elf_file: *Elf) ?File {51pub fn file(self: Atom, elf_file: *Elf) ?File {
...@@ -692,7 +695,7 @@ fn reportUndefined(...@@ -692,7 +695,7 @@ fn reportUndefined(
692) !void {695) !void {
693 const rel_esym = switch (self.file(elf_file).?) {696 const rel_esym = switch (self.file(elf_file).?) {
694 .zig_object => |x| x.elfSym(rel.r_sym()).*,697 .zig_object => |x| x.elfSym(rel.r_sym()).*,
695 .object => |x| x.symtab[rel.r_sym()],698 .object => |x| x.symtab.items[rel.r_sym()],
696 else => unreachable,699 else => unreachable,
697 };700 };
698 const esym = sym.elfSym(elf_file);701 const esym = sym.elfSym(elf_file);
src/link/Elf/LinkerDefined.zig+15-27
...@@ -1,11 +1,13 @@...@@ -1,11 +1,13 @@
1index: File.Index,1index: File.Index,
2symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},2symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
3strtab: std.ArrayListUnmanaged(u8) = .{},
3symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},4symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
45
5output_symtab_size: Elf.SymtabSize = .{},6output_symtab_size: Elf.SymtabSize = .{},
67
7pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {8pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
8 self.symtab.deinit(allocator);9 self.symtab.deinit(allocator);
10 self.strtab.deinit(allocator);
9 self.symbols.deinit(allocator);11 self.symbols.deinit(allocator);
10}12}
1113
...@@ -13,16 +15,17 @@ pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32...@@ -13,16 +15,17 @@ pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32
13 const gpa = elf_file.base.allocator;15 const gpa = elf_file.base.allocator;
14 try self.symtab.ensureUnusedCapacity(gpa, 1);16 try self.symtab.ensureUnusedCapacity(gpa, 1);
15 try self.symbols.ensureUnusedCapacity(gpa, 1);17 try self.symbols.ensureUnusedCapacity(gpa, 1);
18 const name_off = @as(u32, @intCast(self.strtab.items.len));
19 try self.strtab.writer(gpa).print("{s}\x00", .{name});
16 self.symtab.appendAssumeCapacity(.{20 self.symtab.appendAssumeCapacity(.{
17 .st_name = try elf_file.strtab.insert(gpa, name),21 .st_name = name_off,
18 .st_info = elf.STB_GLOBAL << 4,22 .st_info = elf.STB_GLOBAL << 4,
19 .st_other = @intFromEnum(elf.STV.HIDDEN),23 .st_other = @intFromEnum(elf.STV.HIDDEN),
20 .st_shndx = elf.SHN_ABS,24 .st_shndx = elf.SHN_ABS,
21 .st_value = 0,25 .st_value = 0,
22 .st_size = 0,26 .st_size = 0,
23 });27 });
24 const off = try elf_file.strtab.insert(gpa, name);28 const gop = try elf_file.getOrPutGlobal(name);
25 const gop = try elf_file.getOrPutGlobal(off);
26 self.symbols.addOneAssumeCapacity().* = gop.index;29 self.symbols.addOneAssumeCapacity().* = gop.index;
27 return gop.index;30 return gop.index;
28}31}
...@@ -37,7 +40,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -37,7 +40,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
37 const global = elf_file.symbol(index);40 const global = elf_file.symbol(index);
38 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {41 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
39 global.value = 0;42 global.value = 0;
40 global.name_offset = global.name_offset;
41 global.atom_index = 0;43 global.atom_index = 0;
42 global.file_index = self.index;44 global.file_index = self.index;
43 global.esym_index = sym_idx;45 global.esym_index = sym_idx;
...@@ -46,26 +48,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -46,26 +48,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
46 }48 }
47}49}
4850
49pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
50 for (self.globals()) |global_index| {
51 const global = elf_file.symbol(global_index);
52 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
53 global.flags.output_symtab = true;
54 self.output_symtab_size.nlocals += 1;
55 }
56}
57
58pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf, ctx: anytype) void {
59 var ilocal = ctx.ilocal;
60 for (self.globals()) |global_index| {
61 const global = elf_file.symbol(global_index);
62 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
63 if (!global.flags.output_symtab) continue;
64 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
65 ilocal += 1;
66 }
67}
68
69pub fn globals(self: *LinkerDefined) []const Symbol.Index {51pub fn globals(self: *LinkerDefined) []const Symbol.Index {
70 return self.symbols.items;52 return self.symbols.items;
71}53}
...@@ -74,6 +56,11 @@ pub fn asFile(self: *LinkerDefined) File {...@@ -74,6 +56,11 @@ pub fn asFile(self: *LinkerDefined) File {
74 return .{ .linker_defined = self };56 return .{ .linker_defined = self };
75}57}
7658
59pub fn getString(self: LinkerDefined, off: u32) [:0]const u8 {
60 assert(off < self.strtab.items.len);
61 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
62}
63
77pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {64pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
78 return .{ .data = .{65 return .{ .data = .{
79 .self = self,66 .self = self,
...@@ -101,12 +88,13 @@ fn formatSymtab(...@@ -101,12 +88,13 @@ fn formatSymtab(
101 }88 }
102}89}
10390
104const std = @import("std");91const assert = std.debug.assert;
105const elf = std.elf;92const elf = std.elf;
93const mem = std.mem;
94const std = @import("std");
10695
107const Allocator = std.mem.Allocator;96const Allocator = mem.Allocator;
108const Elf = @import("../Elf.zig");97const Elf = @import("../Elf.zig");
109const File = @import("file.zig").File;98const File = @import("file.zig").File;
110const LinkerDefined = @This();99const LinkerDefined = @This();
111// const Object = @import("Object.zig");
112const Symbol = @import("Symbol.zig");100const Symbol = @import("Symbol.zig");
src/link/Elf/Object.zig+51-116
...@@ -5,11 +5,10 @@ index: File.Index,...@@ -5,11 +5,10 @@ index: File.Index,
55
6header: ?elf.Elf64_Ehdr = null,6header: ?elf.Elf64_Ehdr = null,
7shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},7shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
8strings: StringTable(.object_strings) = .{},
9symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},
10strtab: []const u8 = &[0]u8{},
11first_global: ?Symbol.Index = null,
128
9symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
10strtab: std.ArrayListUnmanaged(u8) = .{},
11first_global: ?Symbol.Index = null,
13symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},12symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14atoms: std.ArrayListUnmanaged(Atom.Index) = .{},13atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
15comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},14comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
...@@ -39,7 +38,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -39,7 +38,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
39 allocator.free(self.path);38 allocator.free(self.path);
40 allocator.free(self.data);39 allocator.free(self.data);
41 self.shdrs.deinit(allocator);40 self.shdrs.deinit(allocator);
42 self.strings.deinit(allocator);41 self.symtab.deinit(allocator);
42 self.strtab.deinit(allocator);
43 self.symbols.deinit(allocator);43 self.symbols.deinit(allocator);
44 self.atoms.deinit(allocator);44 self.atoms.deinit(allocator);
45 self.comdat_groups.deinit(allocator);45 self.comdat_groups.deinit(allocator);
...@@ -68,7 +68,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -68,7 +68,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
68 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));68 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
69 }69 }
7070
71 try self.strings.buffer.appendSlice(gpa, self.shdrContents(self.header.?.e_shstrndx));71 try self.strtab.appendSlice(gpa, self.shdrContents(self.header.?.e_shstrndx));
7272
73 const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {73 const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
74 elf.SHT_SYMTAB => break @as(u16, @intCast(i)),74 elf.SHT_SYMTAB => break @as(u16, @intCast(i)),
...@@ -79,10 +79,22 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -79,10 +79,22 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
79 const shdr = shdrs[index];79 const shdr = shdrs[index];
80 self.first_global = shdr.sh_info;80 self.first_global = shdr.sh_info;
8181
82 const symtab = self.shdrContents(index);82 const raw_symtab = self.shdrContents(index);
83 const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym));83 const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym));
84 self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms];84 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
85 self.strtab = self.shdrContents(@as(u16, @intCast(shdr.sh_link)));85
86 const strtab_bias = @as(u32, @intCast(self.strtab.items.len));
87 try self.strtab.appendSlice(gpa, self.shdrContents(@as(u16, @intCast(shdr.sh_link))));
88
89 try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
90 for (symtab) |sym| {
91 const out_sym = self.symtab.addOneAssumeCapacity();
92 out_sym.* = sym;
93 out_sym.st_name = if (sym.st_name == 0 and sym.st_type() == elf.STT_SECTION)
94 shdrs[sym.st_shndx].sh_name
95 else
96 sym.st_name + strtab_bias;
97 }
86 }98 }
8799
88 try self.initAtoms(elf_file);100 try self.initAtoms(elf_file);
...@@ -108,16 +120,16 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -108,16 +120,16 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
108120
109 switch (shdr.sh_type) {121 switch (shdr.sh_type) {
110 elf.SHT_GROUP => {122 elf.SHT_GROUP => {
111 if (shdr.sh_info >= self.symtab.len) {123 if (shdr.sh_info >= self.symtab.items.len) {
112 // TODO convert into an error124 // TODO convert into an error
113 log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()});125 log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()});
114 continue;126 continue;
115 }127 }
116 const group_info_sym = self.symtab[shdr.sh_info];128 const group_info_sym = self.symtab.items[shdr.sh_info];
117 const group_signature = blk: {129 const group_signature = blk: {
118 if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {130 if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {
119 const sym_shdr = shdrs[group_info_sym.st_shndx];131 const sym_shdr = shdrs[group_info_sym.st_shndx];
120 break :blk self.strings.getAssumeExists(sym_shdr.sh_name);132 break :blk self.getString(sym_shdr.sh_name);
121 }133 }
122 break :blk self.getString(group_info_sym.st_name);134 break :blk self.getString(group_info_sym.st_name);
123 };135 };
...@@ -133,11 +145,8 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -133,11 +145,8 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
133 continue;145 continue;
134 }146 }
135147
136 // Note the assumption about a global strtab used here to disambiguate common
137 // COMDAT owners.
138 const gpa = elf_file.base.allocator;148 const gpa = elf_file.base.allocator;
139 const group_signature_off = try elf_file.strtab.insert(gpa, group_signature);149 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature);
140 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature_off);
141 const comdat_group_index = try elf_file.addComdatGroup();150 const comdat_group_index = try elf_file.addComdatGroup();
142 const comdat_group = elf_file.comdatGroup(comdat_group_index);151 const comdat_group = elf_file.comdatGroup(comdat_group_index);
143 comdat_group.* = .{152 comdat_group.* = .{
...@@ -157,10 +166,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -157,10 +166,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
157 => {},166 => {},
158167
159 else => {168 else => {
160 const name = self.strings.getAssumeExists(shdr.sh_name);
161 const shndx = @as(u16, @intCast(i));169 const shndx = @as(u16, @intCast(i));
162 if (self.skipShdr(shndx, elf_file)) continue;170 if (self.skipShdr(shndx, elf_file)) continue;
163 try self.addAtom(shdr, shndx, name, elf_file);171 try self.addAtom(shdr, shndx, elf_file);
164 },172 },
165 }173 }
166 }174 }
...@@ -177,17 +185,11 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -177,17 +185,11 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
177 };185 };
178}186}
179187
180fn addAtom(188fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOfMemory}!void {
181 self: *Object,
182 shdr: ElfShdr,
183 shndx: u16,
184 name: [:0]const u8,
185 elf_file: *Elf,
186) error{OutOfMemory}!void {
187 const atom_index = try elf_file.addAtom();189 const atom_index = try elf_file.addAtom();
188 const atom = elf_file.atom(atom_index).?;190 const atom = elf_file.atom(atom_index).?;
189 atom.atom_index = atom_index;191 atom.atom_index = atom_index;
190 atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name);192 atom.name_offset = shdr.sh_name;
191 atom.file_index = self.index;193 atom.file_index = self.index;
192 atom.input_section_index = shndx;194 atom.input_section_index = shndx;
193 self.atoms.items[shndx] = atom_index;195 self.atoms.items[shndx] = atom_index;
...@@ -205,7 +207,7 @@ fn addAtom(...@@ -205,7 +207,7 @@ fn addAtom(
205207
206fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {208fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
207 const name = blk: {209 const name = blk: {
208 const name = self.strings.getAssumeExists(shdr.sh_name);210 const name = self.getString(shdr.sh_name);
209 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;211 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
210 const sh_name_prefixes: []const [:0]const u8 = &.{212 const sh_name_prefixes: []const [:0]const u8 = &.{
211 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",213 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
...@@ -248,7 +250,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem...@@ -248,7 +250,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem
248250
249fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {251fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
250 const shdr = self.shdrs.items[index];252 const shdr = self.shdrs.items[index];
251 const name = self.strings.getAssumeExists(shdr.sh_name);253 const name = self.getString(shdr.sh_name);
252 const ignore = blk: {254 const ignore = blk: {
253 if (mem.startsWith(u8, name, ".note")) break :blk true;255 if (mem.startsWith(u8, name, ".note")) break :blk true;
254 if (mem.startsWith(u8, name, ".comment")) break :blk true;256 if (mem.startsWith(u8, name, ".comment")) break :blk true;
...@@ -262,33 +264,24 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {...@@ -262,33 +264,24 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
262264
263fn initSymtab(self: *Object, elf_file: *Elf) !void {265fn initSymtab(self: *Object, elf_file: *Elf) !void {
264 const gpa = elf_file.base.allocator;266 const gpa = elf_file.base.allocator;
265 const first_global = self.first_global orelse self.symtab.len;267 const first_global = self.first_global orelse self.symtab.items.len;
266 const shdrs = self.shdrs.items;
267268
268 try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.len);269 try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len);
269270
270 for (self.symtab[0..first_global], 0..) |sym, i| {271 for (self.symtab.items[0..first_global], 0..) |sym, i| {
271 const index = try elf_file.addSymbol();272 const index = try elf_file.addSymbol();
272 self.symbols.appendAssumeCapacity(index);273 self.symbols.appendAssumeCapacity(index);
273 const sym_ptr = elf_file.symbol(index);274 const sym_ptr = elf_file.symbol(index);
274 const name = blk: {
275 if (sym.st_name == 0 and sym.st_type() == elf.STT_SECTION) {
276 const shdr = shdrs[sym.st_shndx];
277 break :blk self.strings.getAssumeExists(shdr.sh_name);
278 }
279 break :blk self.getString(sym.st_name);
280 };
281 sym_ptr.value = sym.st_value;275 sym_ptr.value = sym.st_value;
282 sym_ptr.name_offset = try elf_file.strtab.insert(gpa, name);276 sym_ptr.name_offset = sym.st_name;
283 sym_ptr.esym_index = @as(u32, @intCast(i));277 sym_ptr.esym_index = @as(u32, @intCast(i));
284 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];278 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
285 sym_ptr.file_index = self.index;279 sym_ptr.file_index = self.index;
286 }280 }
287281
288 for (self.symtab[first_global..]) |sym| {282 for (self.symtab.items[first_global..]) |sym| {
289 const name = self.getString(sym.st_name);283 const name = self.getString(sym.st_name);
290 const off = try elf_file.strtab.insert(gpa, name);284 const gop = try elf_file.getOrPutGlobal(name);
291 const gop = try elf_file.getOrPutGlobal(off);
292 self.symbols.addOneAssumeCapacity().* = gop.index;285 self.symbols.addOneAssumeCapacity().* = gop.index;
293 }286 }
294}287}
...@@ -437,7 +430,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {...@@ -437,7 +430,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
437 const first_global = self.first_global orelse return;430 const first_global = self.first_global orelse return;
438 for (self.globals(), 0..) |index, i| {431 for (self.globals(), 0..) |index, i| {
439 const esym_index = @as(Symbol.Index, @intCast(first_global + i));432 const esym_index = @as(Symbol.Index, @intCast(first_global + i));
440 const esym = self.symtab[esym_index];433 const esym = self.symtab.items[esym_index];
441434
442 if (esym.st_shndx == elf.SHN_UNDEF) continue;435 if (esym.st_shndx == elf.SHN_UNDEF) continue;
443436
...@@ -467,7 +460,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -467,7 +460,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
467 const first_global = self.first_global orelse return;460 const first_global = self.first_global orelse return;
468 for (self.globals(), 0..) |index, i| {461 for (self.globals(), 0..) |index, i| {
469 const esym_index = @as(u32, @intCast(first_global + i));462 const esym_index = @as(u32, @intCast(first_global + i));
470 const esym = self.symtab[esym_index];463 const esym = self.symtab.items[esym_index];
471 if (esym.st_shndx != elf.SHN_UNDEF) continue;464 if (esym.st_shndx != elf.SHN_UNDEF) continue;
472465
473 const global = elf_file.symbol(index);466 const global = elf_file.symbol(index);
...@@ -491,20 +484,11 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -491,20 +484,11 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
491 }484 }
492}485}
493486
494pub fn resetGlobals(self: *Object, elf_file: *Elf) void {
495 for (self.globals()) |index| {
496 const global = elf_file.symbol(index);
497 const off = global.name_offset;
498 global.* = .{};
499 global.name_offset = off;
500 }
501}
502
503pub fn markLive(self: *Object, elf_file: *Elf) void {487pub fn markLive(self: *Object, elf_file: *Elf) void {
504 const first_global = self.first_global orelse return;488 const first_global = self.first_global orelse return;
505 for (self.globals(), 0..) |index, i| {489 for (self.globals(), 0..) |index, i| {
506 const sym_idx = first_global + i;490 const sym_idx = first_global + i;
507 const sym = self.symtab[sym_idx];491 const sym = self.symtab.items[sym_idx];
508 if (sym.st_bind() == elf.STB_WEAK) continue;492 if (sym.st_bind() == elf.STB_WEAK) continue;
509493
510 const global = elf_file.symbol(index);494 const global = elf_file.symbol(index);
...@@ -531,7 +515,7 @@ pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {...@@ -531,7 +515,7 @@ pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {
531 const first_global = self.first_global orelse return;515 const first_global = self.first_global orelse return;
532 for (self.globals(), 0..) |index, i| {516 for (self.globals(), 0..) |index, i| {
533 const sym_idx = @as(u32, @intCast(first_global + i));517 const sym_idx = @as(u32, @intCast(first_global + i));
534 const this_sym = self.symtab[sym_idx];518 const this_sym = self.symtab.items[sym_idx];
535 const global = elf_file.symbol(index);519 const global = elf_file.symbol(index);
536 const global_file = global.getFile(elf_file) orelse continue;520 const global_file = global.getFile(elf_file) orelse continue;
537521
...@@ -560,7 +544,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -560,7 +544,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
560 const first_global = self.first_global orelse return;544 const first_global = self.first_global orelse return;
561 for (self.globals(), 0..) |index, i| {545 for (self.globals(), 0..) |index, i| {
562 const sym_idx = @as(u32, @intCast(first_global + i));546 const sym_idx = @as(u32, @intCast(first_global + i));
563 const this_sym = self.symtab[sym_idx];547 const this_sym = self.symtab.items[sym_idx];
564 if (this_sym.st_shndx != elf.SHN_COMMON) continue;548 if (this_sym.st_shndx != elf.SHN_COMMON) continue;
565549
566 const global = elf_file.symbol(index);550 const global = elf_file.symbol(index);
...@@ -584,8 +568,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -584,8 +568,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
584 const name = if (is_tls) ".tls_common" else ".common";568 const name = if (is_tls) ".tls_common" else ".common";
585569
586 const atom = elf_file.atom(atom_index).?;570 const atom = elf_file.atom(atom_index).?;
571 const name_offset = @as(u32, @intCast(self.strtab.items.len));
572 try self.strtab.writer(gpa).print("{s}\x00", .{name});
587 atom.atom_index = atom_index;573 atom.atom_index = atom_index;
588 atom.name_offset = try elf_file.strtab.insert(gpa, name);574 atom.name_offset = name_offset;
589 atom.file_index = self.index;575 atom.file_index = self.index;
590 atom.size = this_sym.st_size;576 atom.size = this_sym.st_size;
591 const alignment = this_sym.st_value;577 const alignment = this_sym.st_value;
...@@ -597,7 +583,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -597,7 +583,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
597 const shdr = try self.shdrs.addOne(gpa);583 const shdr = try self.shdrs.addOne(gpa);
598 const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;584 const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;
599 shdr.* = .{585 shdr.* = .{
600 .sh_name = try self.strings.insert(gpa, name),586 .sh_name = name_offset,
601 .sh_type = elf.SHT_NOBITS,587 .sh_type = elf.SHT_NOBITS,
602 .sh_flags = sh_flags,588 .sh_flags = sh_flags,
603 .sh_addr = 0,589 .sh_addr = 0,
...@@ -665,56 +651,6 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {...@@ -665,56 +651,6 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
665 }651 }
666}652}
667653
668pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
669 for (self.locals()) |local_index| {
670 const local = elf_file.symbol(local_index);
671 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
672 const esym = local.elfSym(elf_file);
673 switch (esym.st_type()) {
674 elf.STT_SECTION, elf.STT_NOTYPE => continue,
675 else => {},
676 }
677 local.flags.output_symtab = true;
678 self.output_symtab_size.nlocals += 1;
679 }
680
681 for (self.globals()) |global_index| {
682 const global = elf_file.symbol(global_index);
683 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
684 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
685 global.flags.output_symtab = true;
686 if (global.isLocal()) {
687 self.output_symtab_size.nlocals += 1;
688 } else {
689 self.output_symtab_size.nglobals += 1;
690 }
691 }
692}
693
694pub fn writeSymtab(self: *Object, elf_file: *Elf, ctx: anytype) void {
695 var ilocal = ctx.ilocal;
696 for (self.locals()) |local_index| {
697 const local = elf_file.symbol(local_index);
698 if (!local.flags.output_symtab) continue;
699 local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
700 ilocal += 1;
701 }
702
703 var iglobal = ctx.iglobal;
704 for (self.globals()) |global_index| {
705 const global = elf_file.symbol(global_index);
706 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
707 if (!global.flags.output_symtab) continue;
708 if (global.isLocal()) {
709 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
710 ilocal += 1;
711 } else {
712 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
713 iglobal += 1;
714 }
715 }
716}
717
718pub fn locals(self: Object) []const Symbol.Index {654pub fn locals(self: Object) []const Symbol.Index {
719 const end = self.first_global orelse self.symbols.items.len;655 const end = self.first_global orelse self.symbols.items.len;
720 return self.symbols.items[0..end];656 return self.symbols.items[0..end];
...@@ -760,11 +696,6 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)...@@ -760,11 +696,6 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)
760 } else return gpa.dupe(u8, data);696 } else return gpa.dupe(u8, data);
761}697}
762698
763fn getString(self: *Object, off: u32) [:0]const u8 {
764 assert(off < self.strtab.len);
765 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
766}
767
768pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 {699pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 {
769 const raw = self.shdrContents(index);700 const raw = self.shdrContents(index);
770 const nmembers = @divExact(raw.len, @sizeOf(u32));701 const nmembers = @divExact(raw.len, @sizeOf(u32));
...@@ -782,6 +713,11 @@ pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela {...@@ -782,6 +713,11 @@ pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela {
782 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];713 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
783}714}
784715
716pub fn getString(self: Object, off: u32) [:0]const u8 {
717 assert(off < self.strtab.items.len);
718 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
719}
720
785pub fn format(721pub fn format(
786 self: *Object,722 self: *Object,
787 comptime unused_fmt_string: []const u8,723 comptime unused_fmt_string: []const u8,
...@@ -991,6 +927,5 @@ const Cie = eh_frame.Cie;...@@ -991,6 +927,5 @@ const Cie = eh_frame.Cie;
991const Elf = @import("../Elf.zig");927const Elf = @import("../Elf.zig");
992const Fde = eh_frame.Fde;928const Fde = eh_frame.Fde;
993const File = @import("file.zig").File;929const File = @import("file.zig").File;
994const StringTable = @import("../strtab.zig").StringTable;
995const Symbol = @import("Symbol.zig");930const Symbol = @import("Symbol.zig");
996const Alignment = Atom.Alignment;931const Alignment = Atom.Alignment;
src/link/Elf/SharedObject.zig+50-62
...@@ -4,19 +4,20 @@ index: File.Index,...@@ -4,19 +4,20 @@ index: File.Index,
44
5header: ?elf.Elf64_Ehdr = null,5header: ?elf.Elf64_Ehdr = null,
6shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},6shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
7symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},7
8strtab: []const u8 = &[0]u8{},8symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
9strtab: std.ArrayListUnmanaged(u8) = .{},
9/// Version symtab contains version strings of the symbols if present.10/// Version symtab contains version strings of the symbols if present.
10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},11versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
11verstrings: std.ArrayListUnmanaged(u32) = .{},12verstrings: std.ArrayListUnmanaged(u32) = .{},
13symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14aliases: ?std.ArrayListUnmanaged(u32) = null,
1215
16dynsym_sect_index: ?u16 = null,
13dynamic_sect_index: ?u16 = null,17dynamic_sect_index: ?u16 = null,
14versym_sect_index: ?u16 = null,18versym_sect_index: ?u16 = null,
15verdef_sect_index: ?u16 = null,19verdef_sect_index: ?u16 = null,
1620
17symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
18aliases: ?std.ArrayListUnmanaged(u32) = null,
19
20needed: bool,21needed: bool,
21alive: bool,22alive: bool,
2223
...@@ -36,6 +37,8 @@ pub fn isSharedObject(path: []const u8) !bool {...@@ -36,6 +37,8 @@ pub fn isSharedObject(path: []const u8) !bool {
36pub fn deinit(self: *SharedObject, allocator: Allocator) void {37pub fn deinit(self: *SharedObject, allocator: Allocator) void {
37 allocator.free(self.path);38 allocator.free(self.path);
38 allocator.free(self.data);39 allocator.free(self.data);
40 self.symtab.deinit(allocator);
41 self.strtab.deinit(allocator);
39 self.versyms.deinit(allocator);42 self.versyms.deinit(allocator);
40 self.verstrings.deinit(allocator);43 self.verstrings.deinit(allocator);
41 self.symbols.deinit(allocator);44 self.symbols.deinit(allocator);
...@@ -51,7 +54,6 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {...@@ -51,7 +54,6 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
51 self.header = try reader.readStruct(elf.Elf64_Ehdr);54 self.header = try reader.readStruct(elf.Elf64_Ehdr);
52 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;55 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
5356
54 var dynsym_index: ?u16 = null;
55 const shdrs = @as(57 const shdrs = @as(
56 [*]align(1) const elf.Elf64_Shdr,58 [*]align(1) const elf.Elf64_Shdr,
57 @ptrCast(self.data.ptr + shoff),59 @ptrCast(self.data.ptr + shoff),
...@@ -61,7 +63,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {...@@ -61,7 +63,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
61 for (shdrs, 0..) |shdr, i| {63 for (shdrs, 0..) |shdr, i| {
62 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));64 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
63 switch (shdr.sh_type) {65 switch (shdr.sh_type) {
64 elf.SHT_DYNSYM => dynsym_index = @as(u16, @intCast(i)),66 elf.SHT_DYNSYM => self.dynsym_sect_index = @as(u16, @intCast(i)),
65 elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)),67 elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)),
66 elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)),68 elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)),
67 elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)),69 elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)),
...@@ -69,20 +71,13 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {...@@ -69,20 +71,13 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
69 }71 }
70 }72 }
7173
72 if (dynsym_index) |index| {
73 const shdr = self.shdrs.items[index];
74 const symtab = self.shdrContents(index);
75 const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym));
76 self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms];
77 self.strtab = self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
78 }
79
80 try self.parseVersions(elf_file);74 try self.parseVersions(elf_file);
81 try self.initSymtab(elf_file);75 try self.initSymtab(elf_file);
82}76}
8377
84fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {78fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
85 const gpa = elf_file.base.allocator;79 const gpa = elf_file.base.allocator;
80 const symtab = self.getSymtabRaw();
8681
87 try self.verstrings.resize(gpa, 2);82 try self.verstrings.resize(gpa, 2);
88 self.verstrings.items[elf.VER_NDX_LOCAL] = 0;83 self.verstrings.items[elf.VER_NDX_LOCAL] = 0;
...@@ -107,7 +102,7 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {...@@ -107,7 +102,7 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
107 }102 }
108 }103 }
109104
110 try self.versyms.ensureTotalCapacityPrecise(gpa, self.symtab.len);105 try self.versyms.ensureTotalCapacityPrecise(gpa, symtab.len);
111106
112 if (self.versym_sect_index) |shndx| {107 if (self.versym_sect_index) |shndx| {
113 const versyms_raw = self.shdrContents(shndx);108 const versyms_raw = self.shdrContents(shndx);
...@@ -120,30 +115,39 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {...@@ -120,30 +115,39 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
120 ver;115 ver;
121 self.versyms.appendAssumeCapacity(normalized_ver);116 self.versyms.appendAssumeCapacity(normalized_ver);
122 }117 }
123 } else for (0..self.symtab.len) |_| {118 } else for (0..symtab.len) |_| {
124 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);119 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
125 }120 }
126}121}
127122
128fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {123fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
129 const gpa = elf_file.base.allocator;124 const gpa = elf_file.base.allocator;
125 const symtab = self.getSymtabRaw();
126 const strtab = self.getStrtabRaw();
130127
131 try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.len);128 try self.strtab.appendSlice(gpa, strtab);
129 try self.symtab.ensureTotalCapacityPrecise(gpa, symtab.len);
130 try self.symbols.ensureTotalCapacityPrecise(gpa, symtab.len);
132131
133 for (self.symtab, 0..) |sym, i| {132 for (symtab, 0..) |sym, i| {
134 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;133 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
135 const name = self.getString(sym.st_name);134 const name = self.getString(sym.st_name);
136 // We need to garble up the name so that we don't pick this symbol135 // We need to garble up the name so that we don't pick this symbol
137 // during symbol resolution. Thank you GNU!136 // during symbol resolution. Thank you GNU!
138 const off = if (hidden) blk: {137 const name_off = if (hidden) blk: {
139 const full_name = try std.fmt.allocPrint(gpa, "{s}@{s}", .{138 const mangled = try std.fmt.allocPrint(gpa, "{s}@{s}", .{
140 name,139 name,
141 self.versionString(self.versyms.items[i]),140 self.versionString(self.versyms.items[i]),
142 });141 });
143 defer gpa.free(full_name);142 defer gpa.free(mangled);
144 break :blk try elf_file.strtab.insert(gpa, full_name);143 const name_off = @as(u32, @intCast(self.strtab.items.len));
145 } else try elf_file.strtab.insert(gpa, name);144 try self.strtab.writer(gpa).print("{s}\x00", .{mangled});
146 const gop = try elf_file.getOrPutGlobal(off);145 break :blk name_off;
146 } else sym.st_name;
147 const out_sym = self.symtab.addOneAssumeCapacity();
148 out_sym.* = sym;
149 out_sym.st_name = name_off;
150 const gop = try elf_file.getOrPutGlobal(self.getString(name_off));
147 self.symbols.addOneAssumeCapacity().* = gop.index;151 self.symbols.addOneAssumeCapacity().* = gop.index;
148 }152 }
149}153}
...@@ -151,7 +155,7 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {...@@ -151,7 +155,7 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
151pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {155pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
152 for (self.globals(), 0..) |index, i| {156 for (self.globals(), 0..) |index, i| {
153 const esym_index = @as(u32, @intCast(i));157 const esym_index = @as(u32, @intCast(i));
154 const this_sym = self.symtab[esym_index];158 const this_sym = self.symtab.items[esym_index];
155159
156 if (this_sym.st_shndx == elf.SHN_UNDEF) continue;160 if (this_sym.st_shndx == elf.SHN_UNDEF) continue;
157161
...@@ -166,18 +170,9 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {...@@ -166,18 +170,9 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
166 }170 }
167}171}
168172
169pub fn resetGlobals(self: *SharedObject, elf_file: *Elf) void {
170 for (self.globals()) |index| {
171 const global = elf_file.symbol(index);
172 const off = global.name_offset;
173 global.* = .{};
174 global.name_offset = off;
175 }
176}
177
178pub fn markLive(self: *SharedObject, elf_file: *Elf) void {173pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
179 for (self.globals(), 0..) |index, i| {174 for (self.globals(), 0..) |index, i| {
180 const sym = self.symtab[i];175 const sym = self.symtab.items[i];
181 if (sym.st_shndx != elf.SHN_UNDEF) continue;176 if (sym.st_shndx != elf.SHN_UNDEF) continue;
182177
183 const global = elf_file.symbol(index);178 const global = elf_file.symbol(index);
...@@ -193,27 +188,6 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {...@@ -193,27 +188,6 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
193 }188 }
194}189}
195190
196pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {
197 for (self.globals()) |global_index| {
198 const global = elf_file.symbol(global_index);
199 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
200 if (global.isLocal()) continue;
201 global.flags.output_symtab = true;
202 self.output_symtab_size.nglobals += 1;
203 }
204}
205
206pub fn writeSymtab(self: *SharedObject, elf_file: *Elf, ctx: anytype) void {
207 var iglobal = ctx.iglobal;
208 for (self.globals()) |global_index| {
209 const global = elf_file.symbol(global_index);
210 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
211 if (!global.flags.output_symtab) continue;
212 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
213 iglobal += 1;
214 }
215}
216
217pub fn globals(self: SharedObject) []const Symbol.Index {191pub fn globals(self: SharedObject) []const Symbol.Index {
218 return self.symbols.items;192 return self.symbols.items;
219}193}
...@@ -223,11 +197,6 @@ pub fn shdrContents(self: SharedObject, index: u16) []const u8 {...@@ -223,11 +197,6 @@ pub fn shdrContents(self: SharedObject, index: u16) []const u8 {
223 return self.data[shdr.sh_offset..][0..shdr.sh_size];197 return self.data[shdr.sh_offset..][0..shdr.sh_size];
224}198}
225199
226pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
227 assert(off < self.strtab.len);
228 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
229}
230
231pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {200pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {
232 const off = self.verstrings.items[index & elf.VERSYM_VERSION];201 const off = self.verstrings.items[index & elf.VERSYM_VERSION];
233 return self.getString(off);202 return self.getString(off);
...@@ -309,6 +278,25 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3...@@ -309,6 +278,25 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3
309 return aliases.items[start..end];278 return aliases.items[start..end];
310}279}
311280
281pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
282 assert(off < self.strtab.items.len);
283 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
284}
285
286pub fn getSymtabRaw(self: SharedObject) []align(1) const elf.Elf64_Sym {
287 const index = self.dynsym_sect_index orelse return &[0]elf.Elf64_Sym{};
288 const raw_symtab = self.shdrContents(index);
289 const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym));
290 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
291 return symtab;
292}
293
294pub fn getStrtabRaw(self: SharedObject) []const u8 {
295 const index = self.dynsym_sect_index orelse return &[0]u8{};
296 const shdr = self.shdrs.items[index];
297 return self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
298}
299
312pub fn format(300pub fn format(
313 self: SharedObject,301 self: SharedObject,
314 comptime unused_fmt_string: []const u8,302 comptime unused_fmt_string: []const u8,
src/link/Elf/Symbol.zig+21-18
...@@ -58,7 +58,11 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {...@@ -58,7 +58,11 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
58}58}
5959
60pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {60pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
61 return elf_file.strtab.getAssumeExists(symbol.name_offset);61 if (symbol.flags.global) return elf_file.strings.getAssumeExists(symbol.name_offset);
62 const file_ptr = symbol.file(elf_file).?;
63 return switch (file_ptr) {
64 inline else => |x| x.getString(symbol.name_offset),
65 };
62}66}
6367
64pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {68pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
...@@ -71,11 +75,10 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {...@@ -71,11 +75,10 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
7175
72pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {76pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
73 const file_ptr = symbol.file(elf_file).?;77 const file_ptr = symbol.file(elf_file).?;
74 switch (file_ptr) {78 return switch (file_ptr) {
75 .zig_object => |x| return x.elfSym(symbol.esym_index).*,79 .zig_object => |x| x.elfSym(symbol.esym_index).*,
76 .linker_defined => |x| return x.symtab.items[symbol.esym_index],80 inline else => |x| x.symtab.items[symbol.esym_index],
77 inline else => |x| return x.symtab[symbol.esym_index],81 };
78 }
79}82}
8083
81pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {84pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
...@@ -201,10 +204,7 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {...@@ -201,10 +204,7 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
201}204}
202205
203pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {206pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
204 const file_ptr = symbol.file(elf_file) orelse {207 const file_ptr = symbol.file(elf_file).?;
205 out.* = Elf.null_sym;
206 return;
207 };
208 const esym = symbol.elfSym(elf_file);208 const esym = symbol.elfSym(elf_file);
209 const st_type = symbol.type(elf_file);209 const st_type = symbol.type(elf_file);
210 const st_bind: u8 = blk: {210 const st_bind: u8 = blk: {
...@@ -232,14 +232,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -232,14 +232,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
232 break :blk symbol.value - elf_file.tlsAddress();232 break :blk symbol.value - elf_file.tlsAddress();
233 break :blk symbol.value;233 break :blk symbol.value;
234 };234 };
235 out.* = .{235 out.st_info = (st_bind << 4) | st_type;
236 .st_name = symbol.name_offset,236 out.st_other = esym.st_other;
237 .st_info = (st_bind << 4) | st_type,237 out.st_shndx = st_shndx;
238 .st_other = esym.st_other,238 out.st_value = st_value;
239 .st_shndx = st_shndx,239 out.st_size = esym.st_size;
240 .st_value = st_value,
241 .st_size = esym.st_size,
242 };
243}240}
244241
245pub fn format(242pub fn format(
...@@ -340,6 +337,12 @@ pub const Flags = packed struct {...@@ -340,6 +337,12 @@ pub const Flags = packed struct {
340 /// Whether this symbol is weak.337 /// Whether this symbol is weak.
341 weak: bool = false,338 weak: bool = false,
342339
340 /// Whether the symbol has its name interned in global symbol
341 /// resolver table.
342 /// This happens for any symbol that is considered a global
343 /// symbol, but is not necessarily an import or export.
344 global: bool = false,
345
343 /// Whether the symbol makes into the output symtab.346 /// Whether the symbol makes into the output symtab.
344 output_symtab: bool = false,347 output_symtab: bool = false,
345348
src/link/Elf/ZigObject.zig+27-75
...@@ -9,6 +9,7 @@ index: File.Index,...@@ -9,6 +9,7 @@ index: File.Index,
99
10local_esyms: std.MultiArrayList(ElfSym) = .{},10local_esyms: std.MultiArrayList(ElfSym) = .{},
11global_esyms: std.MultiArrayList(ElfSym) = .{},11global_esyms: std.MultiArrayList(ElfSym) = .{},
12strtab: std.ArrayListUnmanaged(u8) = .{},
12local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},13local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
13global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},14global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},15globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
...@@ -74,8 +75,9 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -74,8 +75,9 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
74 const gpa = elf_file.base.allocator;75 const gpa = elf_file.base.allocator;
7576
76 try self.atoms.append(gpa, 0); // null input section77 try self.atoms.append(gpa, 0); // null input section
78 try self.strtab.append(gpa, 0);
7779
78 const name_off = try elf_file.strtab.insert(gpa, std.fs.path.stem(self.path));80 const name_off = try self.insertString(gpa, std.fs.path.stem(self.path));
79 const symbol_index = try elf_file.addSymbol();81 const symbol_index = try elf_file.addSymbol();
80 try self.local_symbols.append(gpa, symbol_index);82 try self.local_symbols.append(gpa, symbol_index);
81 const symbol_ptr = elf_file.symbol(symbol_index);83 const symbol_ptr = elf_file.symbol(symbol_index);
...@@ -97,6 +99,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -97,6 +99,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
97pub fn deinit(self: *ZigObject, allocator: Allocator) void {99pub fn deinit(self: *ZigObject, allocator: Allocator) void {
98 self.local_esyms.deinit(allocator);100 self.local_esyms.deinit(allocator);
99 self.global_esyms.deinit(allocator);101 self.global_esyms.deinit(allocator);
102 self.strtab.deinit(allocator);
100 self.local_symbols.deinit(allocator);103 self.local_symbols.deinit(allocator);
101 self.global_symbols.deinit(allocator);104 self.global_symbols.deinit(allocator);
102 self.globals_lookup.deinit(allocator);105 self.globals_lookup.deinit(allocator);
...@@ -379,15 +382,6 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {...@@ -379,15 +382,6 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
379 }382 }
380}383}
381384
382pub fn resetGlobals(self: *ZigObject, elf_file: *Elf) void {
383 for (self.globals()) |index| {
384 const global = elf_file.symbol(index);
385 const off = global.name_offset;
386 global.* = .{};
387 global.name_offset = off;
388 }
389}
390
391pub fn markLive(self: *ZigObject, elf_file: *Elf) void {385pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
392 for (self.globals(), 0..) |index, i| {386 for (self.globals(), 0..) |index, i| {
393 const esym = self.global_esyms.items(.elf_sym)[i];387 const esym = self.global_esyms.items(.elf_sym)[i];
...@@ -404,60 +398,6 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {...@@ -404,60 +398,6 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
404 }398 }
405}399}
406400
407pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) void {
408 for (self.locals()) |local_index| {
409 const local = elf_file.symbol(local_index);
410 const esym = local.elfSym(elf_file);
411 switch (esym.st_type()) {
412 elf.STT_SECTION, elf.STT_NOTYPE => {
413 local.flags.output_symtab = false;
414 continue;
415 },
416 else => {},
417 }
418 local.flags.output_symtab = true;
419 self.output_symtab_size.nlocals += 1;
420 }
421
422 for (self.globals()) |global_index| {
423 const global = elf_file.symbol(global_index);
424 if (global.file(elf_file)) |file| if (file.index() != self.index) {
425 global.flags.output_symtab = false;
426 continue;
427 };
428 global.flags.output_symtab = true;
429 if (global.isLocal()) {
430 self.output_symtab_size.nlocals += 1;
431 } else {
432 self.output_symtab_size.nglobals += 1;
433 }
434 }
435}
436
437pub fn writeSymtab(self: *ZigObject, elf_file: *Elf, ctx: anytype) void {
438 var ilocal = ctx.ilocal;
439 for (self.locals()) |local_index| {
440 const local = elf_file.symbol(local_index);
441 if (!local.flags.output_symtab) continue;
442 local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
443 ilocal += 1;
444 }
445
446 var iglobal = ctx.iglobal;
447 for (self.globals()) |global_index| {
448 const global = elf_file.symbol(global_index);
449 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
450 if (!global.flags.output_symtab) continue;
451 if (global.isLocal()) {
452 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
453 ilocal += 1;
454 } else {
455 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
456 iglobal += 1;
457 }
458 }
459}
460
461pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {401pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {
462 const is_global = index & global_symbol_bit != 0;402 const is_global = index & global_symbol_bit != 0;
463 const actual_index = index & symbol_mask;403 const actual_index = index & symbol_mask;
...@@ -727,7 +667,7 @@ fn updateDeclCode(...@@ -727,7 +667,7 @@ fn updateDeclCode(
727 sym.output_section_index = shdr_index;667 sym.output_section_index = shdr_index;
728 atom_ptr.output_section_index = shdr_index;668 atom_ptr.output_section_index = shdr_index;
729669
730 sym.name_offset = try elf_file.strtab.insert(gpa, decl_name);670 sym.name_offset = try self.insertString(gpa, decl_name);
731 atom_ptr.flags.alive = true;671 atom_ptr.flags.alive = true;
732 atom_ptr.name_offset = sym.name_offset;672 atom_ptr.name_offset = sym.name_offset;
733 esym.st_name = sym.name_offset;673 esym.st_name = sym.name_offset;
...@@ -967,7 +907,7 @@ fn updateLazySymbol(...@@ -967,7 +907,7 @@ fn updateLazySymbol(
967 sym.ty.fmt(mod),907 sym.ty.fmt(mod),
968 });908 });
969 defer gpa.free(name);909 defer gpa.free(name);
970 break :blk try elf_file.strtab.insert(gpa, name);910 break :blk try self.insertString(gpa, name);
971 };911 };
972912
973 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|913 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
...@@ -1100,7 +1040,7 @@ fn lowerConst(...@@ -1100,7 +1040,7 @@ fn lowerConst(
11001040
1101 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;1041 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
1102 const local_sym = elf_file.symbol(sym_index);1042 const local_sym = elf_file.symbol(sym_index);
1103 const name_str_index = try elf_file.strtab.insert(gpa, name);1043 const name_str_index = try self.insertString(gpa, name);
1104 local_sym.name_offset = name_str_index;1044 local_sym.name_offset = name_str_index;
1105 local_sym.output_section_index = output_section_index;1045 local_sym.output_section_index = output_section_index;
1106 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];1046 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
...@@ -1195,8 +1135,8 @@ pub fn updateExports(...@@ -1195,8 +1135,8 @@ pub fn updateExports(
1195 };1135 };
1196 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));1136 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
1197 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);1137 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
1198 const name_off = try elf_file.strtab.insert(gpa, exp_name);1138 const name_off = try self.insertString(gpa, exp_name);
1199 const global_esym_index = if (metadata.@"export"(self, elf_file, exp_name)) |exp_index|1139 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
1200 exp_index.*1140 exp_index.*
1201 else blk: {1141 else blk: {
1202 const global_esym_index = try self.addGlobalEsym(gpa);1142 const global_esym_index = try self.addGlobalEsym(gpa);
...@@ -1205,7 +1145,7 @@ pub fn updateExports(...@@ -1205,7 +1145,7 @@ pub fn updateExports(
1205 global_esym.st_name = name_off;1145 global_esym.st_name = name_off;
1206 lookup_gop.value_ptr.* = global_esym_index;1146 lookup_gop.value_ptr.* = global_esym_index;
1207 try metadata.exports.append(gpa, global_esym_index);1147 try metadata.exports.append(gpa, global_esym_index);
1208 const gop = try elf_file.getOrPutGlobal(name_off);1148 const gop = try elf_file.getOrPutGlobal(exp_name);
1209 try self.global_symbols.append(gpa, gop.index);1149 try self.global_symbols.append(gpa, gop.index);
1210 break :blk global_esym_index;1150 break :blk global_esym_index;
1211 };1151 };
...@@ -1248,7 +1188,7 @@ pub fn deleteDeclExport(...@@ -1248,7 +1188,7 @@ pub fn deleteDeclExport(
1248 const metadata = self.decls.getPtr(decl_index) orelse return;1188 const metadata = self.decls.getPtr(decl_index) orelse return;
1249 const mod = elf_file.base.options.module.?;1189 const mod = elf_file.base.options.module.?;
1250 const exp_name = mod.intern_pool.stringToSlice(name);1190 const exp_name = mod.intern_pool.stringToSlice(name);
1251 const esym_index = metadata.@"export"(self, elf_file, exp_name) orelse return;1191 const esym_index = metadata.@"export"(self, exp_name) orelse return;
1252 log.debug("deleting export '{s}'", .{exp_name});1192 log.debug("deleting export '{s}'", .{exp_name});
1253 const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];1193 const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];
1254 _ = self.globals_lookup.remove(esym.st_name);1194 _ = self.globals_lookup.remove(esym.st_name);
...@@ -1265,19 +1205,31 @@ pub fn deleteDeclExport(...@@ -1265,19 +1205,31 @@ pub fn deleteDeclExport(
1265pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {1205pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
1266 _ = lib_name;1206 _ = lib_name;
1267 const gpa = elf_file.base.allocator;1207 const gpa = elf_file.base.allocator;
1268 const off = try elf_file.strtab.insert(gpa, name);1208 const off = try self.insertString(gpa, name);
1269 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);1209 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
1270 if (!lookup_gop.found_existing) {1210 if (!lookup_gop.found_existing) {
1271 const esym_index = try self.addGlobalEsym(gpa);1211 const esym_index = try self.addGlobalEsym(gpa);
1272 const esym = self.elfSym(esym_index);1212 const esym = self.elfSym(esym_index);
1273 esym.st_name = off;1213 esym.st_name = off;
1274 lookup_gop.value_ptr.* = esym_index;1214 lookup_gop.value_ptr.* = esym_index;
1275 const gop = try elf_file.getOrPutGlobal(off);1215 const gop = try elf_file.getOrPutGlobal(name);
1276 try self.global_symbols.append(gpa, gop.index);1216 try self.global_symbols.append(gpa, gop.index);
1277 }1217 }
1278 return lookup_gop.value_ptr.*;1218 return lookup_gop.value_ptr.*;
1279}1219}
12801220
1221pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
1222 assert(off < self.strtab.items.len);
1223 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
1224}
1225
1226pub fn insertString(self: *ZigObject, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 {
1227 const off = @as(u32, @intCast(self.strtab.items.len));
1228 try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);
1229 self.strtab.writer(allocator).print("{s}\x00", .{name}) catch unreachable;
1230 return off;
1231}
1232
1281pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {1233pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
1282 return .{ .data = .{1234 return .{ .data = .{
1283 .self = self,1235 .self = self,
...@@ -1350,9 +1302,9 @@ const DeclMetadata = struct {...@@ -1350,9 +1302,9 @@ const DeclMetadata = struct {
1350 /// A list of all exports aliases of this Decl.1302 /// A list of all exports aliases of this Decl.
1351 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},1303 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
13521304
1353 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, elf_file: *Elf, name: []const u8) ?*u32 {1305 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
1354 for (m.exports.items) |*exp| {1306 for (m.exports.items) |*exp| {
1355 const exp_name = elf_file.strtab.getAssumeExists(zig_object.elfSym(exp.*).st_name);1307 const exp_name = zig_object.getString(zig_object.elfSym(exp.*).st_name);
1356 if (mem.eql(u8, name, exp_name)) return exp;1308 if (mem.eql(u8, name, exp_name)) return exp;
1357 }1309 }
1358 return null;1310 return null;
src/link/Elf/eh_frame.zig+1-1
...@@ -43,7 +43,7 @@ pub const Fde = struct {...@@ -43,7 +43,7 @@ pub const Fde = struct {
43 pub fn atom(fde: Fde, elf_file: *Elf) *Atom {43 pub fn atom(fde: Fde, elf_file: *Elf) *Atom {
44 const object = elf_file.file(fde.file_index).?.object;44 const object = elf_file.file(fde.file_index).?.object;
45 const rel = fde.relocs(elf_file)[0];45 const rel = fde.relocs(elf_file)[0];
46 const sym = object.symtab[rel.r_sym()];46 const sym = object.symtab.items[rel.r_sym()];
47 const atom_index = object.atoms.items[sym.st_shndx];47 const atom_index = object.atoms.items[sym.st_shndx];
48 return elf_file.atom(atom_index).?;48 return elf_file.atom(atom_index).?;
49 }49 }
src/link/Elf/file.zig+77-8
...@@ -68,9 +68,12 @@ pub const File = union(enum) {...@@ -68,9 +68,12 @@ pub const File = union(enum) {
68 }68 }
6969
70 pub fn resetGlobals(file: File, elf_file: *Elf) void {70 pub fn resetGlobals(file: File, elf_file: *Elf) void {
71 switch (file) {71 for (file.globals()) |global_index| {
72 .linker_defined => unreachable,72 const global = elf_file.symbol(global_index);
73 inline else => |x| x.resetGlobals(elf_file),73 const name_offset = global.name_offset;
74 global.* = .{};
75 global.name_offset = name_offset;
76 global.flags.global = true;
74 }77 }
75 }78 }
7679
...@@ -83,15 +86,14 @@ pub const File = union(enum) {...@@ -83,15 +86,14 @@ pub const File = union(enum) {
8386
84 pub fn markLive(file: File, elf_file: *Elf) void {87 pub fn markLive(file: File, elf_file: *Elf) void {
85 switch (file) {88 switch (file) {
86 .linker_defined => unreachable,89 .linker_defined => {},
87 inline else => |x| x.markLive(elf_file),90 inline else => |x| x.markLive(elf_file),
88 }91 }
89 }92 }
9093
91 pub fn atoms(file: File) []const Atom.Index {94 pub fn atoms(file: File) []const Atom.Index {
92 return switch (file) {95 return switch (file) {
93 .linker_defined => unreachable,96 .linker_defined, .shared_object => &[0]Atom.Index{},
94 .shared_object => unreachable,
95 .zig_object => |x| x.atoms.items,97 .zig_object => |x| x.atoms.items,
96 .object => |x| x.atoms.items,98 .object => |x| x.atoms.items,
97 };99 };
...@@ -99,8 +101,7 @@ pub const File = union(enum) {...@@ -99,8 +101,7 @@ pub const File = union(enum) {
99101
100 pub fn locals(file: File) []const Symbol.Index {102 pub fn locals(file: File) []const Symbol.Index {
101 return switch (file) {103 return switch (file) {
102 .linker_defined => unreachable,104 .linker_defined, .shared_object => &[0]Symbol.Index{},
103 .shared_object => unreachable,
104 inline else => |x| x.locals(),105 inline else => |x| x.locals(),
105 };106 };
106 }107 }
...@@ -111,6 +112,74 @@ pub const File = union(enum) {...@@ -111,6 +112,74 @@ pub const File = union(enum) {
111 };112 };
112 }113 }
113114
115 pub fn updateSymtabSize(file: File, elf_file: *Elf) void {
116 const output_symtab_size = switch (file) {
117 inline else => |x| &x.output_symtab_size,
118 };
119 for (file.locals()) |local_index| {
120 const local = elf_file.symbol(local_index);
121 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
122 const esym = local.elfSym(elf_file);
123 switch (esym.st_type()) {
124 elf.STT_SECTION, elf.STT_NOTYPE => continue,
125 else => {},
126 }
127 local.flags.output_symtab = true;
128 output_symtab_size.nlocals += 1;
129 output_symtab_size.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
130 }
131
132 for (file.globals()) |global_index| {
133 const global = elf_file.symbol(global_index);
134 const file_ptr = global.file(elf_file) orelse continue;
135 if (file_ptr.index() != file.index()) continue;
136 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
137 global.flags.output_symtab = true;
138 if (global.isLocal()) {
139 output_symtab_size.nlocals += 1;
140 } else {
141 output_symtab_size.nglobals += 1;
142 }
143 output_symtab_size.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
144 }
145 }
146
147 pub fn writeSymtab(file: File, elf_file: *Elf, ctx: anytype) void {
148 var ilocal = ctx.ilocal;
149 for (file.locals()) |local_index| {
150 const local = elf_file.symbol(local_index);
151 if (!local.flags.output_symtab) continue;
152 const out_sym = &elf_file.symtab.items[ilocal];
153 out_sym.st_name = @intCast(elf_file.strtab.items.len);
154 elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));
155 elf_file.strtab.appendAssumeCapacity(0);
156 local.setOutputSym(elf_file, out_sym);
157 ilocal += 1;
158 }
159
160 var iglobal = ctx.iglobal;
161 for (file.globals()) |global_index| {
162 const global = elf_file.symbol(global_index);
163 const file_ptr = global.file(elf_file) orelse continue;
164 if (file_ptr.index() != file.index()) continue;
165 if (!global.flags.output_symtab) continue;
166 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
167 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
168 elf_file.strtab.appendAssumeCapacity(0);
169 if (global.isLocal()) {
170 const out_sym = &elf_file.symtab.items[ilocal];
171 out_sym.st_name = st_name;
172 global.setOutputSym(elf_file, out_sym);
173 ilocal += 1;
174 } else {
175 const out_sym = &elf_file.symtab.items[iglobal];
176 out_sym.st_name = st_name;
177 global.setOutputSym(elf_file, out_sym);
178 iglobal += 1;
179 }
180 }
181 }
182
114 pub const Index = u32;183 pub const Index = u32;
115184
116 pub const Entry = union(enum) {185 pub const Entry = union(enum) {
src/link/Elf/synthetic_sections.zig+39-67
...@@ -9,7 +9,7 @@ pub const DynamicSection = struct {...@@ -9,7 +9,7 @@ pub const DynamicSection = struct {
99
10 pub fn addNeeded(dt: *DynamicSection, shared: *SharedObject, elf_file: *Elf) !void {10 pub fn addNeeded(dt: *DynamicSection, shared: *SharedObject, elf_file: *Elf) !void {
11 const gpa = elf_file.base.allocator;11 const gpa = elf_file.base.allocator;
12 const off = try elf_file.dynstrtab.insert(gpa, shared.soname());12 const off = try elf_file.insertDynString(shared.soname());
13 try dt.needed.append(gpa, off);13 try dt.needed.append(gpa, off);
14 }14 }
1515
...@@ -22,11 +22,11 @@ pub const DynamicSection = struct {...@@ -22,11 +22,11 @@ pub const DynamicSection = struct {
22 if (i > 0) try rpath.append(':');22 if (i > 0) try rpath.append(':');
23 try rpath.appendSlice(path);23 try rpath.appendSlice(path);
24 }24 }
25 dt.rpath = try elf_file.dynstrtab.insert(gpa, rpath.items);25 dt.rpath = try elf_file.insertDynString(rpath.items);
26 }26 }
2727
28 pub fn setSoname(dt: *DynamicSection, soname: []const u8, elf_file: *Elf) !void {28 pub fn setSoname(dt: *DynamicSection, soname: []const u8, elf_file: *Elf) !void {
29 dt.soname = try elf_file.dynstrtab.insert(elf_file.base.allocator, soname);29 dt.soname = try elf_file.insertDynString(soname);
30 }30 }
3131
32 fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 {32 fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 {
...@@ -359,31 +359,24 @@ pub const ZigGotSection = struct {...@@ -359,31 +359,24 @@ pub const ZigGotSection = struct {
359 }359 }
360360
361 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {361 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
362 _ = elf_file;
363 zig_got.output_symtab_size.nlocals = @as(u32, @intCast(zig_got.entries.items.len));362 zig_got.output_symtab_size.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
364 }
365
366 pub fn updateStrtab(zig_got: ZigGotSection, elf_file: *Elf) !void {
367 const gpa = elf_file.base.allocator;
368 for (zig_got.entries.items) |entry| {363 for (zig_got.entries.items) |entry| {
369 const symbol_name = elf_file.symbol(entry).name(elf_file);364 const name = elf_file.symbol(entry).name(elf_file);
370 const name = try std.fmt.allocPrint(gpa, "{s}$ziggot", .{symbol_name});365 zig_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
371 defer gpa.free(name);
372 _ = try elf_file.strtab.insert(gpa, name);
373 }366 }
374 }367 }
375368
376 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) !void {369 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) void {
377 const gpa = elf_file.base.allocator;
378 for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {370 for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {
379 const symbol = elf_file.symbol(entry);371 const symbol = elf_file.symbol(entry);
380 const symbol_name = symbol.name(elf_file);372 const symbol_name = symbol.name(elf_file);
381 const name = try std.fmt.allocPrint(gpa, "{s}$ziggot", .{symbol_name});373 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
382 defer gpa.free(name);374 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
383 const st_name = try elf_file.strtab.insert(gpa, name);375 elf_file.strtab.appendSliceAssumeCapacity("$ziggot");
376 elf_file.strtab.appendAssumeCapacity(0);
384 const st_value = zig_got.entryAddress(@intCast(index), elf_file);377 const st_value = zig_got.entryAddress(@intCast(index), elf_file);
385 const st_size = elf_file.archPtrWidthBytes();378 const st_size = elf_file.archPtrWidthBytes();
386 ctx.symtab[ilocal] = .{379 elf_file.symtab.items[ilocal] = .{
387 .st_name = st_name,380 .st_name = st_name,
388 .st_info = elf.STT_OBJECT,381 .st_info = elf.STT_OBJECT,
389 .st_other = 0,382 .st_other = 0,
...@@ -767,25 +760,17 @@ pub const GotSection = struct {...@@ -767,25 +760,17 @@ pub const GotSection = struct {
767 }760 }
768761
769 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {762 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
770 _ = elf_file;
771 got.output_symtab_size.nlocals = @as(u32, @intCast(got.entries.items.len));763 got.output_symtab_size.nlocals = @as(u32, @intCast(got.entries.items.len));
772 }
773
774 pub fn updateStrtab(got: GotSection, elf_file: *Elf) !void {
775 const gpa = elf_file.base.allocator;
776 for (got.entries.items) |entry| {764 for (got.entries.items) |entry| {
777 const symbol_name = switch (entry.tag) {765 const symbol_name = switch (entry.tag) {
778 .tlsld => "",766 .tlsld => "",
779 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),767 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
780 };768 };
781 const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) });769 got.output_symtab_size.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
782 defer gpa.free(name);
783 _ = try elf_file.strtab.insert(gpa, name);
784 }770 }
785 }771 }
786772
787 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) !void {773 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) void {
788 const gpa = elf_file.base.allocator;
789 for (got.entries.items, ctx.ilocal..) |entry, ilocal| {774 for (got.entries.items, ctx.ilocal..) |entry, ilocal| {
790 const symbol = switch (entry.tag) {775 const symbol = switch (entry.tag) {
791 .tlsld => null,776 .tlsld => null,
...@@ -795,12 +780,14 @@ pub const GotSection = struct {...@@ -795,12 +780,14 @@ pub const GotSection = struct {
795 .tlsld => "",780 .tlsld => "",
796 inline else => symbol.?.name(elf_file),781 inline else => symbol.?.name(elf_file),
797 };782 };
798 const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) });783 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
799 defer gpa.free(name);784 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
800 const st_name = try elf_file.strtab.insert(gpa, name);785 elf_file.strtab.appendAssumeCapacity('$');
786 elf_file.strtab.appendSliceAssumeCapacity(@tagName(entry.tag));
787 elf_file.strtab.appendAssumeCapacity(0);
801 const st_value = entry.address(elf_file);788 const st_value = entry.address(elf_file);
802 const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes();789 const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes();
803 ctx.symtab[ilocal] = .{790 elf_file.symtab.items[ilocal] = .{
804 .st_name = st_name,791 .st_name = st_name,
805 .st_info = elf.STT_OBJECT,792 .st_info = elf.STT_OBJECT,
806 .st_other = 0,793 .st_other = 0,
...@@ -922,30 +909,22 @@ pub const PltSection = struct {...@@ -922,30 +909,22 @@ pub const PltSection = struct {
922 }909 }
923910
924 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {911 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
925 _ = elf_file;
926 plt.output_symtab_size.nlocals = @as(u32, @intCast(plt.symbols.items.len));912 plt.output_symtab_size.nlocals = @as(u32, @intCast(plt.symbols.items.len));
927 }
928
929 pub fn updateStrtab(plt: PltSection, elf_file: *Elf) !void {
930 const gpa = elf_file.base.allocator;
931 for (plt.symbols.items) |sym_index| {913 for (plt.symbols.items) |sym_index| {
932 const sym = elf_file.symbol(sym_index);914 const name = elf_file.symbol(sym_index).name(elf_file);
933 const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)});915 plt.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
934 defer gpa.free(name);
935 _ = try elf_file.strtab.insert(gpa, name);
936 }916 }
937 }917 }
938918
939 pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) !void {919 pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) void {
940 const gpa = elf_file.base.allocator;
941
942 var ilocal = ctx.ilocal;920 var ilocal = ctx.ilocal;
943 for (plt.symbols.items) |sym_index| {921 for (plt.symbols.items) |sym_index| {
944 const sym = elf_file.symbol(sym_index);922 const sym = elf_file.symbol(sym_index);
945 const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)});923 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
946 defer gpa.free(name);924 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
947 const st_name = try elf_file.strtab.insert(gpa, name);925 elf_file.strtab.appendSliceAssumeCapacity("$plt");
948 ctx.symtab[ilocal] = .{926 elf_file.strtab.appendAssumeCapacity(0);
927 elf_file.symtab.items[ilocal] = .{
949 .st_name = st_name,928 .st_name = st_name,
950 .st_info = elf.STT_FUNC,929 .st_info = elf.STT_FUNC,
951 .st_other = 0,930 .st_other = 0,
...@@ -1029,29 +1008,22 @@ pub const PltGotSection = struct {...@@ -1029,29 +1008,22 @@ pub const PltGotSection = struct {
1029 }1008 }
10301009
1031 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {1010 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
1032 _ = elf_file;
1033 plt_got.output_symtab_size.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));1011 plt_got.output_symtab_size.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));
1034 }
1035
1036 pub fn updateStrtab(plt_got: PltGotSection, elf_file: *Elf) !void {
1037 const gpa = elf_file.base.allocator;
1038 for (plt_got.symbols.items) |sym_index| {1012 for (plt_got.symbols.items) |sym_index| {
1039 const sym = elf_file.symbol(sym_index);1013 const name = elf_file.symbol(sym_index).name(elf_file);
1040 const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)});1014 plt_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
1041 defer gpa.free(name);
1042 _ = try elf_file.strtab.insert(gpa, name);
1043 }1015 }
1044 }1016 }
10451017
1046 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) !void {1018 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) void {
1047 const gpa = elf_file.base.allocator;
1048 var ilocal = ctx.ilocal;1019 var ilocal = ctx.ilocal;
1049 for (plt_got.symbols.items) |sym_index| {1020 for (plt_got.symbols.items) |sym_index| {
1050 const sym = elf_file.symbol(sym_index);1021 const sym = elf_file.symbol(sym_index);
1051 const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)});1022 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
1052 defer gpa.free(name);1023 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
1053 const st_name = try elf_file.strtab.insert(gpa, name);1024 elf_file.strtab.appendSliceAssumeCapacity("$pltgot");
1054 ctx.symtab[ilocal] = .{1025 elf_file.strtab.appendAssumeCapacity(0);
1026 elf_file.symtab.items[ilocal] = .{
1055 .st_name = st_name,1027 .st_name = st_name,
1056 .st_info = elf.STT_FUNC,1028 .st_info = elf.STT_FUNC,
1057 .st_other = 0,1029 .st_other = 0,
...@@ -1166,7 +1138,7 @@ pub const DynsymSection = struct {...@@ -1166,7 +1138,7 @@ pub const DynsymSection = struct {
1166 new_extra.dynamic = index;1138 new_extra.dynamic = index;
1167 sym.setExtra(new_extra, elf_file);1139 sym.setExtra(new_extra, elf_file);
1168 } else try sym.addExtra(.{ .dynamic = index }, elf_file);1140 } else try sym.addExtra(.{ .dynamic = index }, elf_file);
1169 const off = try elf_file.dynstrtab.insert(gpa, sym.name(elf_file));1141 const off = try elf_file.insertDynString(sym.name(elf_file));
1170 try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });1142 try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });
1171 }1143 }
11721144
...@@ -1251,7 +1223,7 @@ pub const HashSection = struct {...@@ -1251,7 +1223,7 @@ pub const HashSection = struct {
1251 @memset(chains, 0);1223 @memset(chains, 0);
12521224
1253 for (elf_file.dynsym.entries.items, 1..) |entry, i| {1225 for (elf_file.dynsym.entries.items, 1..) |entry, i| {
1254 const name = elf_file.dynstrtab.getAssumeExists(entry.off);1226 const name = elf_file.getDynString(entry.off);
1255 const hash = hasher(name) % buckets.len;1227 const hash = hasher(name) % buckets.len;
1256 chains[@as(u32, @intCast(i))] = buckets[hash];1228 chains[@as(u32, @intCast(i))] = buckets[hash];
1257 buckets[hash] = @as(u32, @intCast(i));1229 buckets[hash] = @as(u32, @intCast(i));
...@@ -1490,7 +1462,7 @@ pub const VerneedSection = struct {...@@ -1490,7 +1462,7 @@ pub const VerneedSection = struct {
1490 sym.* = .{1462 sym.* = .{
1491 .vn_version = 1,1463 .vn_version = 1,
1492 .vn_cnt = 0,1464 .vn_cnt = 0,
1493 .vn_file = try elf_file.dynstrtab.insert(gpa, soname),1465 .vn_file = try elf_file.insertDynString(soname),
1494 .vn_aux = 0,1466 .vn_aux = 0,
1495 .vn_next = 0,1467 .vn_next = 0,
1496 };1468 };
...@@ -1509,7 +1481,7 @@ pub const VerneedSection = struct {...@@ -1509,7 +1481,7 @@ pub const VerneedSection = struct {
1509 .vna_hash = HashSection.hasher(version),1481 .vna_hash = HashSection.hasher(version),
1510 .vna_flags = 0,1482 .vna_flags = 0,
1511 .vna_other = vern.index,1483 .vna_other = vern.index,
1512 .vna_name = try elf_file.dynstrtab.insert(gpa, version),1484 .vna_name = try elf_file.insertDynString(version),
1513 .vna_next = 0,1485 .vna_next = 0,
1514 };1486 };
1515 verneed_sym.vn_cnt += 1;1487 verneed_sym.vn_cnt += 1;
src/link/MachO.zig+2-2
...@@ -58,7 +58,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},...@@ -58,7 +58,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},
58dyld_stub_binder_index: ?u32 = null,58dyld_stub_binder_index: ?u32 = null,
59dyld_private_atom_index: ?Atom.Index = null,59dyld_private_atom_index: ?Atom.Index = null,
6060
61strtab: StringTable(.strtab) = .{},61strtab: StringTable = .{},
6262
63got_table: TableSection(SymbolWithLoc) = .{},63got_table: TableSection(SymbolWithLoc) = .{},
64stub_table: TableSection(SymbolWithLoc) = .{},64stub_table: TableSection(SymbolWithLoc) = .{},
...@@ -5643,7 +5643,7 @@ const Module = @import("../Module.zig");...@@ -5643,7 +5643,7 @@ const Module = @import("../Module.zig");
5643const InternPool = @import("../InternPool.zig");5643const InternPool = @import("../InternPool.zig");
5644const Platform = load_commands.Platform;5644const Platform = load_commands.Platform;
5645const Relocation = @import("MachO/Relocation.zig");5645const Relocation = @import("MachO/Relocation.zig");
5646const StringTable = @import("strtab.zig").StringTable;5646const StringTable = @import("StringTable.zig");
5647const TableSection = @import("table_section.zig").TableSection;5647const TableSection = @import("table_section.zig").TableSection;
5648const Trie = @import("MachO/Trie.zig");5648const Trie = @import("MachO/Trie.zig");
5649const Type = @import("../type.zig").Type;5649const Type = @import("../type.zig").Type;
src/link/MachO/DebugSymbols.zig+2-2
...@@ -22,7 +22,7 @@ debug_aranges_section_dirty: bool = false,...@@ -22,7 +22,7 @@ debug_aranges_section_dirty: bool = false,
22debug_info_header_dirty: bool = false,22debug_info_header_dirty: bool = false,
23debug_line_header_dirty: bool = false,23debug_line_header_dirty: bool = false,
2424
25strtab: StringTable(.strtab) = .{},25strtab: StringTable = .{},
26relocs: std.ArrayListUnmanaged(Reloc) = .{},26relocs: std.ArrayListUnmanaged(Reloc) = .{},
2727
28pub const Reloc = struct {28pub const Reloc = struct {
...@@ -567,5 +567,5 @@ const Allocator = mem.Allocator;...@@ -567,5 +567,5 @@ const Allocator = mem.Allocator;
567const Dwarf = @import("../Dwarf.zig");567const Dwarf = @import("../Dwarf.zig");
568const MachO = @import("../MachO.zig");568const MachO = @import("../MachO.zig");
569const Module = @import("../../Module.zig");569const Module = @import("../../Module.zig");
570const StringTable = @import("../strtab.zig").StringTable;570const StringTable = @import("../StringTable.zig");
571const Type = @import("../../type.zig").Type;571const Type = @import("../../type.zig").Type;
src/link/MachO/zld.zig-1
...@@ -1227,7 +1227,6 @@ const LibStub = @import("../tapi.zig").LibStub;...@@ -1227,7 +1227,6 @@ const LibStub = @import("../tapi.zig").LibStub;
1227const Object = @import("Object.zig");1227const Object = @import("Object.zig");
1228const Platform = load_commands.Platform;1228const Platform = load_commands.Platform;
1229const Section = MachO.Section;1229const Section = MachO.Section;
1230const StringTable = @import("../strtab.zig").StringTable;
1231const SymbolWithLoc = MachO.SymbolWithLoc;1230const SymbolWithLoc = MachO.SymbolWithLoc;
1232const TableSection = @import("../table_section.zig").TableSection;1231const TableSection = @import("../table_section.zig").TableSection;
1233const Trie = @import("Trie.zig");1232const Trie = @import("Trie.zig");
src/link/strtab.zig deleted-121
...@@ -1,121 +0,0 @@
1const std = @import("std");
2const mem = std.mem;
3
4const Allocator = mem.Allocator;
5const StringIndexAdapter = std.hash_map.StringIndexAdapter;
6const StringIndexContext = std.hash_map.StringIndexContext;
7
8pub fn StringTable(comptime log_scope: @Type(.EnumLiteral)) type {
9 return struct {
10 const Self = @This();
11
12 const log = std.log.scoped(log_scope);
13
14 buffer: std.ArrayListUnmanaged(u8) = .{},
15 table: std.HashMapUnmanaged(u32, bool, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
16
17 pub fn deinit(self: *Self, gpa: Allocator) void {
18 self.buffer.deinit(gpa);
19 self.table.deinit(gpa);
20 }
21
22 pub fn toOwnedSlice(self: *Self, gpa: Allocator) []const u8 {
23 const result = self.buffer.toOwnedSlice(gpa);
24 self.table.clearRetainingCapacity();
25 return result;
26 }
27
28 pub const PrunedResult = struct {
29 buffer: []const u8,
30 idx_map: std.AutoHashMap(u32, u32),
31 };
32
33 pub fn toPrunedResult(self: *Self, gpa: Allocator) !PrunedResult {
34 var buffer = std.ArrayList(u8).init(gpa);
35 defer buffer.deinit();
36 try buffer.ensureTotalCapacity(self.buffer.items.len);
37 buffer.appendAssumeCapacity(0);
38
39 var idx_map = std.AutoHashMap(u32, u32).init(gpa);
40 errdefer idx_map.deinit();
41 try idx_map.ensureTotalCapacity(self.table.count());
42
43 var it = self.table.iterator();
44 while (it.next()) |entry| {
45 const off = entry.key_ptr.*;
46 const save = entry.value_ptr.*;
47 if (!save) continue;
48 const new_off = @as(u32, @intCast(buffer.items.len));
49 buffer.appendSliceAssumeCapacity(self.getAssumeExists(off));
50 idx_map.putAssumeCapacityNoClobber(off, new_off);
51 }
52
53 self.buffer.clearRetainingCapacity();
54 self.table.clearRetainingCapacity();
55
56 return PrunedResult{
57 .buffer = buffer.toOwnedSlice(),
58 .idx_map = idx_map,
59 };
60 }
61
62 pub fn insert(self: *Self, gpa: Allocator, string: []const u8) !u32 {
63 const gop = try self.table.getOrPutContextAdapted(gpa, @as([]const u8, string), StringIndexAdapter{
64 .bytes = &self.buffer,
65 }, StringIndexContext{
66 .bytes = &self.buffer,
67 });
68 if (gop.found_existing) {
69 const off = gop.key_ptr.*;
70 gop.value_ptr.* = true;
71 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
72 return off;
73 }
74
75 try self.buffer.ensureUnusedCapacity(gpa, string.len + 1);
76 const new_off = @as(u32, @intCast(self.buffer.items.len));
77
78 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, new_off });
79
80 self.buffer.appendSliceAssumeCapacity(string);
81 self.buffer.appendAssumeCapacity(0);
82
83 gop.key_ptr.* = new_off;
84 gop.value_ptr.* = true;
85
86 return new_off;
87 }
88
89 pub fn delete(self: *Self, string: []const u8) void {
90 const value_ptr = self.table.getPtrAdapted(@as([]const u8, string), StringIndexAdapter{
91 .bytes = &self.buffer,
92 }) orelse return;
93 value_ptr.* = false;
94 log.debug("marked '{s}' for deletion", .{string});
95 }
96
97 pub fn getOffset(self: *Self, string: []const u8) ?u32 {
98 return self.table.getKeyAdapted(string, StringIndexAdapter{
99 .bytes = &self.buffer,
100 });
101 }
102
103 pub fn get(self: Self, off: u32) ?[:0]const u8 {
104 log.debug("getting string at 0x{x}", .{off});
105 if (off >= self.buffer.items.len) return null;
106 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.buffer.items.ptr + off)), 0);
107 }
108
109 pub fn getAssumeExists(self: Self, off: u32) [:0]const u8 {
110 return self.get(off) orelse unreachable;
111 }
112
113 pub fn items(self: Self) []const u8 {
114 return self.buffer.items;
115 }
116
117 pub fn len(self: Self) usize {
118 return self.buffer.items.len;
119 }
120 };
121}