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
624624 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
625625 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
626626 "${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"
627 "${CMAKE_SOURCE_DIR}/src/link/strtab.zig"
627 "${CMAKE_SOURCE_DIR}/src/link/StringTable.zig"
628628 "${CMAKE_SOURCE_DIR}/src/link/tapi.zig"
629629 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"
630630 "${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) = .{},
3333locals_free_list: std.ArrayListUnmanaged(u32) = .{},
3434globals_free_list: std.ArrayListUnmanaged(u32) = .{},
3535
36strtab: StringTable(.strtab) = .{},
36strtab: StringTable = .{},
3737strtab_offset: ?u32 = null,
3838
39temp_strtab: StringTable(.temp_strtab) = .{},
39temp_strtab: StringTable = .{},
4040
4141got_table: TableSection(SymbolWithLoc) = .{},
4242
......@@ -418,7 +418,7 @@ fn populateMissingMetadata(self: *Coff) !void {
418418 }
419419
420420 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));
422422 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here
423423 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });
424424 }
......@@ -2142,7 +2142,7 @@ fn writeStrtab(self: *Coff) !void {
21422142 if (self.strtab_offset == null) return;
21432143
21442144 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
21472147 if (needed_size > allocated_size) {
21482148 self.strtab_offset = null;
......@@ -2154,10 +2154,10 @@ fn writeStrtab(self: *Coff) !void {
21542154 var buffer = std.ArrayList(u8).init(self.base.allocator);
21552155 defer buffer.deinit();
21562156 try buffer.ensureTotalCapacityPrecise(needed_size);
2157 buffer.appendSliceAssumeCapacity(self.strtab.items());
2157 buffer.appendSliceAssumeCapacity(self.strtab.buffer.items);
21582158 // Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead
21592159 // 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
21622162 try self.base.file.?.pwriteAll(buffer.items, self.strtab_offset.?);
21632163}
......@@ -2325,7 +2325,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
23252325 const end = start + padToIdeal(size);
23262326
23272327 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));
23292329 const increased_size = padToIdeal(tight_size);
23302330 const test_end = off + increased_size;
23312331 if (end > off and start < test_end) {
......@@ -2666,7 +2666,7 @@ const InternPool = @import("../InternPool.zig");
26662666const Object = @import("Coff/Object.zig");
26672667const Relocation = @import("Coff/Relocation.zig");
26682668const TableSection = @import("table_section.zig").TableSection;
2669const StringTable = @import("strtab.zig").StringTable;
2669const StringTable = @import("StringTable.zig");
26702670const Type = @import("../type.zig").Type;
26712671const TypedValue = @import("../TypedValue.zig");
26722672
src/link/Dwarf.zig+2-2
......@@ -23,7 +23,7 @@ abbrev_table_offset: ?u64 = null,
2323
2424/// TODO replace with InternPool
2525/// Table of debug symbol names.
26strtab: StringTable(.strtab) = .{},
26strtab: StringTable = .{},
2727
2828/// Quick lookup array of all defined source files referenced by at least one Decl.
2929/// They will end up in the DWARF debug_line header as two lists:
......@@ -2760,6 +2760,6 @@ const LinkFn = File.LinkFn;
27602760const LinkerLoad = @import("../codegen.zig").LinkerLoad;
27612761const Module = @import("../Module.zig");
27622762const InternPool = @import("../InternPool.zig");
2763const StringTable = @import("strtab.zig").StringTable;
2763const StringTable = @import("StringTable.zig");
27642764const Type = @import("../type.zig").Type;
27652765const Value = @import("../value.zig").Value;
src/link/Elf.zig+138-107
......@@ -66,13 +66,15 @@ page_size: u32,
6666default_sym_version: elf.Elf64_Versym,
6767
6868/// .shstrtab buffer
69shstrtab: StringTable(.strtab) = .{},
69shstrtab: std.ArrayListUnmanaged(u8) = .{},
70/// .symtab buffer
71symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
7072/// .strtab buffer
71strtab: StringTable(.strtab) = .{},
73strtab: std.ArrayListUnmanaged(u8) = .{},
7274/// Dynamic symbol table. Only populated and emitted when linking dynamically.
7375dynsym: DynsymSection = .{},
7476/// .dynstrtab buffer
75dynstrtab: StringTable(.dynstrtab) = .{},
77dynstrtab: std.ArrayListUnmanaged(u8) = .{},
7678/// Version symbol table. Only populated and emitted when linking dynamically.
7779versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
7880/// .verneed section
......@@ -156,9 +158,10 @@ start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
156158/// An array of symbols parsed across all input files.
157159symbols: std.ArrayListUnmanaged(Symbol) = .{},
158160symbols_extra: std.ArrayListUnmanaged(u32) = .{},
159resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
160161symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
161162
163resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
164
162165has_text_reloc: bool = false,
163166num_ifunc_dynrelocs: usize = 0,
164167
......@@ -175,6 +178,10 @@ comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
175178comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
176179comdat_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
178185/// When allocating, the ideal_capacity is calculated by
179186/// actual_capacity + (actual_capacity / ideal_factor)
180187const ideal_factor = 3;
......@@ -227,13 +234,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
227234 // Append null file at index 0
228235 try self.files.append(allocator, .null);
229236 // Append null byte to string tables
230 try self.shstrtab.buffer.append(allocator, 0);
231 try self.strtab.buffer.append(allocator, 0);
237 try self.shstrtab.append(allocator, 0);
238 try self.strtab.append(allocator, 0);
232239 // There must always be a null shdr in index 0
233240 _ = try self.addSection(.{ .name = "" });
241 // Append null symbol in output symtab
242 try self.symtab.append(allocator, null_sym);
234243
235244 if (!is_obj_or_ar) {
236 try self.dynstrtab.buffer.append(allocator, 0);
245 try self.dynstrtab.append(allocator, 0);
237246
238247 // Initialize PT_PHDR program header
239248 const p_align: u16 = switch (self.ptr_width) {
......@@ -347,6 +356,7 @@ pub fn deinit(self: *Elf) void {
347356 }
348357 self.output_sections.deinit(gpa);
349358 self.shstrtab.deinit(gpa);
359 self.symtab.deinit(gpa);
350360 self.strtab.deinit(gpa);
351361 self.symbols.deinit(gpa);
352362 self.symbols_extra.deinit(gpa);
......@@ -364,6 +374,7 @@ pub fn deinit(self: *Elf) void {
364374 self.comdat_groups.deinit(gpa);
365375 self.comdat_groups_owners.deinit(gpa);
366376 self.comdat_groups_table.deinit(gpa);
377 self.strings.deinit(gpa);
367378
368379 self.got.deinit(gpa);
369380 self.plt.deinit(gpa);
......@@ -747,7 +758,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
747758 const new_offset = self.findFreeSpace(needed_size, self.page_size);
748759
749760 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
750 self.shstrtab.getAssumeExists(shdr.sh_name),
761 self.getShString(shdr.sh_name),
751762 new_offset,
752763 new_offset + existing_size,
753764 });
......@@ -796,7 +807,7 @@ pub fn growNonAllocSection(
796807 const new_offset = self.findFreeSpace(needed_size, min_alignment);
797808
798809 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
799 self.shstrtab.getAssumeExists(shdr.sh_name),
810 self.getShString(shdr.sh_name),
800811 new_offset,
801812 new_offset + existing_size,
802813 });
......@@ -1696,7 +1707,7 @@ fn accessLibPath(
16961707/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
16971708fn resolveSymbols(self: *Elf) void {
16981709 // 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);
17001711 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
17011712 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
17021713 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
......@@ -1705,7 +1716,7 @@ fn resolveSymbols(self: *Elf) void {
17051716 self.markLive();
17061717
17071718 // 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);
17091720 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
17101721 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
17111722
......@@ -1767,7 +1778,7 @@ fn resolveSymbols(self: *Elf) void {
17671778/// This routine will prune unneeded objects extracted from archives and
17681779/// unneeded shared objects.
17691780fn 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);
17711782 for (self.objects.items) |index| {
17721783 const file_ptr = self.file(index).?;
17731784 if (file_ptr.isAlive()) file_ptr.markLive(self);
......@@ -3358,7 +3369,7 @@ fn sortInitFini(self: *Elf) !void {
33583369 elf.SHT_FINI_ARRAY,
33593370 => is_init_fini = true,
33603371 else => {
3361 const name = self.shstrtab.getAssumeExists(shdr.sh_name);
3372 const name = self.getShString(shdr.sh_name);
33623373 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;
33633374 },
33643375 }
......@@ -3520,7 +3531,7 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
35203531
35213532fn shdrRank(self: *Elf, shndx: u16) u8 {
35223533 const shdr = self.shdrs.items[shndx];
3523 const name = self.shstrtab.getAssumeExists(shdr.sh_name);
3534 const name = self.getShString(shdr.sh_name);
35243535 const flags = shdr.sh_flags;
35253536
35263537 switch (shdr.sh_type) {
......@@ -3801,7 +3812,7 @@ fn updateSectionSizes(self: *Elf) !void {
38013812 }
38023813
38033814 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;
38053816 }
38063817
38073818 if (self.versym_section_index) |index| {
......@@ -3816,26 +3827,8 @@ fn updateSectionSizes(self: *Elf) !void {
38163827 try self.updateSymtabSize();
38173828 }
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
38373830 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;
38393832 }
38403833}
38413834
......@@ -4074,7 +4067,7 @@ fn allocateNonAllocSections(self: *Elf) !void {
40744067
40754068 if (self.isDebugSection(@intCast(shndx))) {
40764069 log.debug("moving {s} from 0x{x} to 0x{x}", .{
4077 self.shstrtab.getAssumeExists(shdr.sh_name),
4070 self.getShString(shdr.sh_name),
40784071 shdr.sh_offset,
40794072 new_offset,
40804073 });
......@@ -4187,7 +4180,7 @@ fn writeAtoms(self: *Elf) !void {
41874180
41884181 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
41924185 // TODO really, really handle debug section separately
41934186 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
......@@ -4256,60 +4249,61 @@ fn updateSymtabSize(self: *Elf) !void {
42564249 var sizes = SymtabSize{};
42574250
42584251 if (self.zigObjectPtr()) |zig_object| {
4259 zig_object.updateSymtabSize(self);
4260 sizes.nlocals += zig_object.output_symtab_size.nlocals;
4261 sizes.nglobals += zig_object.output_symtab_size.nglobals;
4252 zig_object.asFile().updateSymtabSize(self);
4253 sizes.add(zig_object.output_symtab_size);
42624254 }
42634255
42644256 for (self.objects.items) |index| {
4265 const object = self.file(index).?.object;
4266 object.updateSymtabSize(self);
4267 sizes.nlocals += object.output_symtab_size.nlocals;
4268 sizes.nglobals += object.output_symtab_size.nglobals;
4257 const file_ptr = self.file(index).?;
4258 file_ptr.updateSymtabSize(self);
4259 sizes.add(file_ptr.object.output_symtab_size);
42694260 }
42704261
42714262 for (self.shared_objects.items) |index| {
4272 const shared_object = self.file(index).?.shared_object;
4273 shared_object.updateSymtabSize(self);
4274 sizes.nglobals += shared_object.output_symtab_size.nglobals;
4263 const file_ptr = self.file(index).?;
4264 file_ptr.updateSymtabSize(self);
4265 sizes.add(file_ptr.shared_object.output_symtab_size);
42754266 }
42764267
42774268 if (self.zig_got_section_index) |_| {
42784269 self.zig_got.updateSymtabSize(self);
4279 sizes.nlocals += self.zig_got.output_symtab_size.nlocals;
4270 sizes.add(self.zig_got.output_symtab_size);
42804271 }
42814272
42824273 if (self.got_section_index) |_| {
42834274 self.got.updateSymtabSize(self);
4284 sizes.nlocals += self.got.output_symtab_size.nlocals;
4275 sizes.add(self.got.output_symtab_size);
42854276 }
42864277
42874278 if (self.plt_section_index) |_| {
42884279 self.plt.updateSymtabSize(self);
4289 sizes.nlocals += self.plt.output_symtab_size.nlocals;
4280 sizes.add(self.plt.output_symtab_size);
42904281 }
42914282
42924283 if (self.plt_got_section_index) |_| {
42934284 self.plt_got.updateSymtabSize(self);
4294 sizes.nlocals += self.plt_got.output_symtab_size.nlocals;
4285 sizes.add(self.plt_got.output_symtab_size);
42954286 }
42964287
42974288 if (self.linker_defined_index) |index| {
4298 const linker_defined = self.file(index).?.linker_defined;
4299 linker_defined.updateSymtabSize(self);
4300 sizes.nlocals += linker_defined.output_symtab_size.nlocals;
4289 const file_ptr = self.file(index).?;
4290 file_ptr.updateSymtabSize(self);
4291 sizes.add(file_ptr.linker_defined.output_symtab_size);
43014292 }
43024293
4303 const shdr = &self.shdrs.items[self.symtab_section_index.?];
4304 shdr.sh_info = sizes.nlocals + 1;
4305 shdr.sh_link = self.strtab_section_index.?;
4294 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
4295 symtab_shdr.sh_info = sizes.nlocals + 1;
4296 symtab_shdr.sh_link = self.strtab_section_index.?;
43064297
43074298 const sym_size: u64 = switch (self.ptr_width) {
43084299 .p32 => @sizeOf(elf.Elf32_Sym),
43094300 .p64 => @sizeOf(elf.Elf64_Sym),
43104301 };
43114302 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;
43134307}
43144308
43154309fn writeSyntheticSections(self: *Elf) !void {
......@@ -4370,7 +4364,7 @@ fn writeSyntheticSections(self: *Elf) !void {
43704364
43714365 if (self.dynstrtab_section_index) |shndx| {
43724366 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);
43744368 }
43754369
43764370 if (self.eh_frame_section_index) |shndx| {
......@@ -4440,12 +4434,7 @@ fn writeSyntheticSections(self: *Elf) !void {
44404434
44414435 if (self.shstrtab_section_index) |index| {
44424436 const shdr = self.shdrs.items[index];
4443 try self.base.file.?.pwriteAll(self.shstrtab.buffer.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);
4437 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
44494438 }
44504439
44514440 if (self.symtab_section_index) |_| {
......@@ -4455,77 +4444,83 @@ fn writeSyntheticSections(self: *Elf) !void {
44554444
44564445fn writeSymtab(self: *Elf) !void {
44574446 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.?];
44594449 const sym_size: u64 = switch (self.ptr_width) {
44604450 .p32 => @sizeOf(elf.Elf32_Sym),
44614451 .p64 => @sizeOf(elf.Elf64_Sym),
44624452 };
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);
4468 defer gpa.free(symtab);
4469 symtab[0] = null_sym;
4460 const Ctx = struct {
4461 ilocal: usize,
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 = .{
44724470 .ilocal = 1,
4473 .iglobal = shdr.sh_info,
4474 .symtab = symtab,
4471 .iglobal = symtab_shdr.sh_info,
44754472 };
44764473
44774474 if (self.zigObjectPtr()) |zig_object| {
4478 zig_object.writeSymtab(self, ctx);
4479 ctx.ilocal += zig_object.output_symtab_size.nlocals;
4480 ctx.iglobal += zig_object.output_symtab_size.nglobals;
4475 zig_object.asFile().writeSymtab(self, ctx);
4476 ctx.incr(zig_object.output_symtab_size);
44814477 }
44824478
44834479 for (self.objects.items) |index| {
4484 const object = self.file(index).?.object;
4485 object.writeSymtab(self, ctx);
4486 ctx.ilocal += object.output_symtab_size.nlocals;
4487 ctx.iglobal += object.output_symtab_size.nglobals;
4480 const file_ptr = self.file(index).?;
4481 file_ptr.writeSymtab(self, ctx);
4482 ctx.incr(file_ptr.object.output_symtab_size);
44884483 }
44894484
44904485 for (self.shared_objects.items) |index| {
4491 const shared_object = self.file(index).?.shared_object;
4492 shared_object.writeSymtab(self, ctx);
4493 ctx.iglobal += shared_object.output_symtab_size.nglobals;
4486 const file_ptr = self.file(index).?;
4487 file_ptr.writeSymtab(self, ctx);
4488 ctx.incr(file_ptr.shared_object.output_symtab_size);
44944489 }
44954490
44964491 if (self.zig_got_section_index) |_| {
4497 try self.zig_got.writeSymtab(self, ctx);
4498 ctx.ilocal += self.zig_got.output_symtab_size.nlocals;
4492 self.zig_got.writeSymtab(self, ctx);
4493 ctx.incr(self.zig_got.output_symtab_size);
44994494 }
45004495
45014496 if (self.got_section_index) |_| {
4502 try self.got.writeSymtab(self, ctx);
4503 ctx.ilocal += self.got.output_symtab_size.nlocals;
4497 self.got.writeSymtab(self, ctx);
4498 ctx.incr(self.got.output_symtab_size);
45044499 }
45054500
45064501 if (self.plt_section_index) |_| {
4507 try self.plt.writeSymtab(self, ctx);
4508 ctx.ilocal += self.plt.output_symtab_size.nlocals;
4502 self.plt.writeSymtab(self, ctx);
4503 ctx.incr(self.plt.output_symtab_size);
45094504 }
45104505
45114506 if (self.plt_got_section_index) |_| {
4512 try self.plt_got.writeSymtab(self, ctx);
4513 ctx.ilocal += self.plt_got.output_symtab_size.nlocals;
4507 self.plt_got.writeSymtab(self, ctx);
4508 ctx.incr(self.plt_got.output_symtab_size);
45144509 }
45154510
45164511 if (self.linker_defined_index) |index| {
4517 const linker_defined = self.file(index).?.linker_defined;
4518 linker_defined.writeSymtab(self, ctx);
4519 ctx.ilocal += linker_defined.output_symtab_size.nlocals;
4512 const file_ptr = self.file(index).?;
4513 file_ptr.writeSymtab(self, ctx);
4514 ctx.incr(file_ptr.linker_defined.output_symtab_size);
45204515 }
45214516
45224517 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
45234518 switch (self.ptr_width) {
45244519 .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);
45264521 defer gpa.free(buf);
45274522
4528 for (buf, symtab) |*out, sym| {
4523 for (buf, self.symtab.items) |*out, sym| {
45294524 out.* = .{
45304525 .st_name = sym.st_name,
45314526 .st_info = sym.st_info,
......@@ -4536,15 +4531,17 @@ fn writeSymtab(self: *Elf) !void {
45364531 };
45374532 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
45384533 }
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);
45404535 },
45414536 .p64 => {
45424537 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);
45444539 }
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);
45464541 },
45474542 }
4543
4544 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
45484545}
45494546
45504547/// 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 {
49254922 const index = @as(u16, @intCast(self.shdrs.items.len));
49264923 const shdr = try self.shdrs.addOne(gpa);
49274924 shdr.* = .{
4928 .sh_name = try self.shstrtab.insert(gpa, opts.name),
4925 .sh_name = try self.insertShString(opts.name),
49294926 .sh_type = opts.type,
49304927 .sh_flags = opts.flags,
49314928 .sh_addr = 0,
......@@ -4941,7 +4938,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
49414938
49424939pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {
49434940 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);
49454942 if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));
49464943 } else return null;
49474944}
......@@ -5114,13 +5111,15 @@ const GetOrPutGlobalResult = struct {
51145111 index: Symbol.Index,
51155112};
51165113
5117pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {
5114pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
51185115 const gpa = self.base.allocator;
5116 const name_off = try self.strings.insert(gpa, name);
51195117 const gop = try self.resolver.getOrPut(gpa, name_off);
51205118 if (!gop.found_existing) {
51215119 const index = try self.addSymbol();
51225120 const global = self.symbol(index);
51235121 global.name_offset = name_off;
5122 global.flags.global = true;
51245123 gop.value_ptr.* = index;
51255124 }
51265125 return .{
......@@ -5130,7 +5129,7 @@ pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {
51305129}
51315130
51325131pub 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;
51345133 return self.resolver.get(name_off);
51355134}
51365135
......@@ -5148,8 +5147,9 @@ const GetOrCreateComdatGroupOwnerResult = struct {
51485147 index: ComdatGroupOwner.Index,
51495148};
51505149
5151pub fn getOrCreateComdatGroupOwner(self: *Elf, off: u32) !GetOrCreateComdatGroupOwnerResult {
5150pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateComdatGroupOwnerResult {
51525151 const gpa = self.base.allocator;
5152 const off = try self.strings.insert(gpa, name);
51535153 const gop = try self.comdat_groups_table.getOrPut(gpa, off);
51545154 if (!gop.found_existing) {
51555155 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
52395239 return .{ .index = index };
52405240}
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
52425266fn reportUndefined(self: *Elf, undefs: anytype) !void {
52435267 const gpa = self.base.allocator;
52445268 const max_notes = 4;
......@@ -5340,8 +5364,8 @@ fn formatShdr(
53405364 _ = unused_fmt_string;
53415365 const shdr = ctx.shdr;
53425366 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{
5343 ctx.elf_file.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset,
5344 shdr.sh_addr, shdr.sh_addralign,
5367 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
5368 shdr.sh_addr, shdr.sh_addralign,
53455369 shdr.sh_size,
53465370 });
53475371}
......@@ -5516,6 +5540,13 @@ pub const ComdatGroup = struct {
55165540pub const SymtabSize = struct {
55175541 nlocals: u32 = 0,
55185542 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 }
55195550};
55205551
55215552pub const null_sym = elf.Elf64_Sym{
......@@ -5621,7 +5652,7 @@ const PltSection = synthetic_sections.PltSection;
56215652const PltGotSection = synthetic_sections.PltGotSection;
56225653const SharedObject = @import("Elf/SharedObject.zig");
56235654const Symbol = @import("Elf/Symbol.zig");
5624const StringTable = @import("strtab.zig").StringTable;
5655const StringTable = @import("StringTable.zig");
56255656const TypedValue = @import("../TypedValue.zig");
56265657const VerneedSection = synthetic_sections.VerneedSection;
56275658const ZigGotSection = synthetic_sections.ZigGotSection;
src/link/Elf/Atom.zig+5-2
......@@ -42,7 +42,10 @@ next_index: Index = 0,
4242pub const Alignment = @import("../../InternPool.zig").Alignment;
4343
4444pub 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 };
4649}
4750
4851pub fn file(self: Atom, elf_file: *Elf) ?File {
......@@ -692,7 +695,7 @@ fn reportUndefined(
692695) !void {
693696 const rel_esym = switch (self.file(elf_file).?) {
694697 .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()],
696699 else => unreachable,
697700 };
698701 const esym = sym.elfSym(elf_file);
src/link/Elf/LinkerDefined.zig+15-27
......@@ -1,11 +1,13 @@
11index: File.Index,
22symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
3strtab: std.ArrayListUnmanaged(u8) = .{},
34symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
45
56output_symtab_size: Elf.SymtabSize = .{},
67
78pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
89 self.symtab.deinit(allocator);
10 self.strtab.deinit(allocator);
911 self.symbols.deinit(allocator);
1012}
1113
......@@ -13,16 +15,17 @@ pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32
1315 const gpa = elf_file.base.allocator;
1416 try self.symtab.ensureUnusedCapacity(gpa, 1);
1517 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});
1620 self.symtab.appendAssumeCapacity(.{
17 .st_name = try elf_file.strtab.insert(gpa, name),
21 .st_name = name_off,
1822 .st_info = elf.STB_GLOBAL << 4,
1923 .st_other = @intFromEnum(elf.STV.HIDDEN),
2024 .st_shndx = elf.SHN_ABS,
2125 .st_value = 0,
2226 .st_size = 0,
2327 });
24 const off = try elf_file.strtab.insert(gpa, name);
25 const gop = try elf_file.getOrPutGlobal(off);
28 const gop = try elf_file.getOrPutGlobal(name);
2629 self.symbols.addOneAssumeCapacity().* = gop.index;
2730 return gop.index;
2831}
......@@ -37,7 +40,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
3740 const global = elf_file.symbol(index);
3841 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
3942 global.value = 0;
40 global.name_offset = global.name_offset;
4143 global.atom_index = 0;
4244 global.file_index = self.index;
4345 global.esym_index = sym_idx;
......@@ -46,26 +48,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
4648 }
4749}
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
6951pub fn globals(self: *LinkerDefined) []const Symbol.Index {
7052 return self.symbols.items;
7153}
......@@ -74,6 +56,11 @@ pub fn asFile(self: *LinkerDefined) File {
7456 return .{ .linker_defined = self };
7557}
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
7764pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
7865 return .{ .data = .{
7966 .self = self,
......@@ -101,12 +88,13 @@ fn formatSymtab(
10188 }
10289}
10390
104const std = @import("std");
91const assert = std.debug.assert;
10592const elf = std.elf;
93const mem = std.mem;
94const std = @import("std");
10695
107const Allocator = std.mem.Allocator;
96const Allocator = mem.Allocator;
10897const Elf = @import("../Elf.zig");
10998const File = @import("file.zig").File;
11099const LinkerDefined = @This();
111// const Object = @import("Object.zig");
112100const Symbol = @import("Symbol.zig");
src/link/Elf/Object.zig+51-116
......@@ -5,11 +5,10 @@ index: File.Index,
55
66header: ?elf.Elf64_Ehdr = null,
77shdrs: 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,
1312symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1413atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
1514comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
......@@ -39,7 +38,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
3938 allocator.free(self.path);
4039 allocator.free(self.data);
4140 self.shdrs.deinit(allocator);
42 self.strings.deinit(allocator);
41 self.symtab.deinit(allocator);
42 self.strtab.deinit(allocator);
4343 self.symbols.deinit(allocator);
4444 self.atoms.deinit(allocator);
4545 self.comdat_groups.deinit(allocator);
......@@ -68,7 +68,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
6868 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
6969 }
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
7373 const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
7474 elf.SHT_SYMTAB => break @as(u16, @intCast(i)),
......@@ -79,10 +79,22 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
7979 const shdr = shdrs[index];
8080 self.first_global = shdr.sh_info;
8181
82 const symtab = self.shdrContents(index);
83 const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym));
84 self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms];
85 self.strtab = self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
82 const raw_symtab = self.shdrContents(index);
83 const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym));
84 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
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 }
8698 }
8799
88100 try self.initAtoms(elf_file);
......@@ -108,16 +120,16 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
108120
109121 switch (shdr.sh_type) {
110122 elf.SHT_GROUP => {
111 if (shdr.sh_info >= self.symtab.len) {
123 if (shdr.sh_info >= self.symtab.items.len) {
112124 // TODO convert into an error
113125 log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()});
114126 continue;
115127 }
116 const group_info_sym = self.symtab[shdr.sh_info];
128 const group_info_sym = self.symtab.items[shdr.sh_info];
117129 const group_signature = blk: {
118130 if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {
119131 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);
121133 }
122134 break :blk self.getString(group_info_sym.st_name);
123135 };
......@@ -133,11 +145,8 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
133145 continue;
134146 }
135147
136 // Note the assumption about a global strtab used here to disambiguate common
137 // COMDAT owners.
138148 const gpa = elf_file.base.allocator;
139 const group_signature_off = try elf_file.strtab.insert(gpa, group_signature);
140 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature_off);
149 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature);
141150 const comdat_group_index = try elf_file.addComdatGroup();
142151 const comdat_group = elf_file.comdatGroup(comdat_group_index);
143152 comdat_group.* = .{
......@@ -157,10 +166,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
157166 => {},
158167
159168 else => {
160 const name = self.strings.getAssumeExists(shdr.sh_name);
161169 const shndx = @as(u16, @intCast(i));
162170 if (self.skipShdr(shndx, elf_file)) continue;
163 try self.addAtom(shdr, shndx, name, elf_file);
171 try self.addAtom(shdr, shndx, elf_file);
164172 },
165173 }
166174 }
......@@ -177,17 +185,11 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
177185 };
178186}
179187
180fn addAtom(
181 self: *Object,
182 shdr: ElfShdr,
183 shndx: u16,
184 name: [:0]const u8,
185 elf_file: *Elf,
186) error{OutOfMemory}!void {
188fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOfMemory}!void {
187189 const atom_index = try elf_file.addAtom();
188190 const atom = elf_file.atom(atom_index).?;
189191 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;
191193 atom.file_index = self.index;
192194 atom.input_section_index = shndx;
193195 self.atoms.items[shndx] = atom_index;
......@@ -205,7 +207,7 @@ fn addAtom(
205207
206208fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
207209 const name = blk: {
208 const name = self.strings.getAssumeExists(shdr.sh_name);
210 const name = self.getString(shdr.sh_name);
209211 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
210212 const sh_name_prefixes: []const [:0]const u8 = &.{
211213 ".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
248250
249251fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
250252 const shdr = self.shdrs.items[index];
251 const name = self.strings.getAssumeExists(shdr.sh_name);
253 const name = self.getString(shdr.sh_name);
252254 const ignore = blk: {
253255 if (mem.startsWith(u8, name, ".note")) break :blk true;
254256 if (mem.startsWith(u8, name, ".comment")) break :blk true;
......@@ -262,33 +264,24 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
262264
263265fn initSymtab(self: *Object, elf_file: *Elf) !void {
264266 const gpa = elf_file.base.allocator;
265 const first_global = self.first_global orelse self.symtab.len;
266 const shdrs = self.shdrs.items;
267 const first_global = self.first_global orelse self.symtab.items.len;
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| {
271272 const index = try elf_file.addSymbol();
272273 self.symbols.appendAssumeCapacity(index);
273274 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 };
281275 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;
283277 sym_ptr.esym_index = @as(u32, @intCast(i));
284278 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
285279 sym_ptr.file_index = self.index;
286280 }
287281
288 for (self.symtab[first_global..]) |sym| {
282 for (self.symtab.items[first_global..]) |sym| {
289283 const name = self.getString(sym.st_name);
290 const off = try elf_file.strtab.insert(gpa, name);
291 const gop = try elf_file.getOrPutGlobal(off);
284 const gop = try elf_file.getOrPutGlobal(name);
292285 self.symbols.addOneAssumeCapacity().* = gop.index;
293286 }
294287}
......@@ -437,7 +430,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
437430 const first_global = self.first_global orelse return;
438431 for (self.globals(), 0..) |index, i| {
439432 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
442435 if (esym.st_shndx == elf.SHN_UNDEF) continue;
443436
......@@ -467,7 +460,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
467460 const first_global = self.first_global orelse return;
468461 for (self.globals(), 0..) |index, i| {
469462 const esym_index = @as(u32, @intCast(first_global + i));
470 const esym = self.symtab[esym_index];
463 const esym = self.symtab.items[esym_index];
471464 if (esym.st_shndx != elf.SHN_UNDEF) continue;
472465
473466 const global = elf_file.symbol(index);
......@@ -491,20 +484,11 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
491484 }
492485}
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
503487pub fn markLive(self: *Object, elf_file: *Elf) void {
504488 const first_global = self.first_global orelse return;
505489 for (self.globals(), 0..) |index, i| {
506490 const sym_idx = first_global + i;
507 const sym = self.symtab[sym_idx];
491 const sym = self.symtab.items[sym_idx];
508492 if (sym.st_bind() == elf.STB_WEAK) continue;
509493
510494 const global = elf_file.symbol(index);
......@@ -531,7 +515,7 @@ pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {
531515 const first_global = self.first_global orelse return;
532516 for (self.globals(), 0..) |index, i| {
533517 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];
535519 const global = elf_file.symbol(index);
536520 const global_file = global.getFile(elf_file) orelse continue;
537521
......@@ -560,7 +544,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
560544 const first_global = self.first_global orelse return;
561545 for (self.globals(), 0..) |index, i| {
562546 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];
564548 if (this_sym.st_shndx != elf.SHN_COMMON) continue;
565549
566550 const global = elf_file.symbol(index);
......@@ -584,8 +568,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
584568 const name = if (is_tls) ".tls_common" else ".common";
585569
586570 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});
587573 atom.atom_index = atom_index;
588 atom.name_offset = try elf_file.strtab.insert(gpa, name);
574 atom.name_offset = name_offset;
589575 atom.file_index = self.index;
590576 atom.size = this_sym.st_size;
591577 const alignment = this_sym.st_value;
......@@ -597,7 +583,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
597583 const shdr = try self.shdrs.addOne(gpa);
598584 const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;
599585 shdr.* = .{
600 .sh_name = try self.strings.insert(gpa, name),
586 .sh_name = name_offset,
601587 .sh_type = elf.SHT_NOBITS,
602588 .sh_flags = sh_flags,
603589 .sh_addr = 0,
......@@ -665,56 +651,6 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
665651 }
666652}
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
718654pub fn locals(self: Object) []const Symbol.Index {
719655 const end = self.first_global orelse self.symbols.items.len;
720656 return self.symbols.items[0..end];
......@@ -760,11 +696,6 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)
760696 } else return gpa.dupe(u8, data);
761697}
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
768699pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 {
769700 const raw = self.shdrContents(index);
770701 const nmembers = @divExact(raw.len, @sizeOf(u32));
......@@ -782,6 +713,11 @@ pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela {
782713 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
783714}
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
785721pub fn format(
786722 self: *Object,
787723 comptime unused_fmt_string: []const u8,
......@@ -991,6 +927,5 @@ const Cie = eh_frame.Cie;
991927const Elf = @import("../Elf.zig");
992928const Fde = eh_frame.Fde;
993929const File = @import("file.zig").File;
994const StringTable = @import("../strtab.zig").StringTable;
995930const Symbol = @import("Symbol.zig");
996931const Alignment = Atom.Alignment;
src/link/Elf/SharedObject.zig+50-62
......@@ -4,19 +4,20 @@ index: File.Index,
44
55header: ?elf.Elf64_Ehdr = null,
66shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
7symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},
8strtab: []const u8 = &[0]u8{},
7
8symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
9strtab: std.ArrayListUnmanaged(u8) = .{},
910/// Version symtab contains version strings of the symbols if present.
1011versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
1112verstrings: std.ArrayListUnmanaged(u32) = .{},
13symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14aliases: ?std.ArrayListUnmanaged(u32) = null,
1215
16dynsym_sect_index: ?u16 = null,
1317dynamic_sect_index: ?u16 = null,
1418versym_sect_index: ?u16 = null,
1519verdef_sect_index: ?u16 = null,
1620
17symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
18aliases: ?std.ArrayListUnmanaged(u32) = null,
19
2021needed: bool,
2122alive: bool,
2223
......@@ -36,6 +37,8 @@ pub fn isSharedObject(path: []const u8) !bool {
3637pub fn deinit(self: *SharedObject, allocator: Allocator) void {
3738 allocator.free(self.path);
3839 allocator.free(self.data);
40 self.symtab.deinit(allocator);
41 self.strtab.deinit(allocator);
3942 self.versyms.deinit(allocator);
4043 self.verstrings.deinit(allocator);
4144 self.symbols.deinit(allocator);
......@@ -51,7 +54,6 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
5154 self.header = try reader.readStruct(elf.Elf64_Ehdr);
5255 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
5356
54 var dynsym_index: ?u16 = null;
5557 const shdrs = @as(
5658 [*]align(1) const elf.Elf64_Shdr,
5759 @ptrCast(self.data.ptr + shoff),
......@@ -61,7 +63,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
6163 for (shdrs, 0..) |shdr, i| {
6264 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
6365 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)),
6567 elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)),
6668 elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)),
6769 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 {
6971 }
7072 }
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
8074 try self.parseVersions(elf_file);
8175 try self.initSymtab(elf_file);
8276}
8377
8478fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
8579 const gpa = elf_file.base.allocator;
80 const symtab = self.getSymtabRaw();
8681
8782 try self.verstrings.resize(gpa, 2);
8883 self.verstrings.items[elf.VER_NDX_LOCAL] = 0;
......@@ -107,7 +102,7 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
107102 }
108103 }
109104
110 try self.versyms.ensureTotalCapacityPrecise(gpa, self.symtab.len);
105 try self.versyms.ensureTotalCapacityPrecise(gpa, symtab.len);
111106
112107 if (self.versym_sect_index) |shndx| {
113108 const versyms_raw = self.shdrContents(shndx);
......@@ -120,30 +115,39 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
120115 ver;
121116 self.versyms.appendAssumeCapacity(normalized_ver);
122117 }
123 } else for (0..self.symtab.len) |_| {
118 } else for (0..symtab.len) |_| {
124119 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
125120 }
126121}
127122
128123fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
129124 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| {
134133 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
135134 const name = self.getString(sym.st_name);
136135 // We need to garble up the name so that we don't pick this symbol
137136 // during symbol resolution. Thank you GNU!
138 const off = if (hidden) blk: {
139 const full_name = try std.fmt.allocPrint(gpa, "{s}@{s}", .{
137 const name_off = if (hidden) blk: {
138 const mangled = try std.fmt.allocPrint(gpa, "{s}@{s}", .{
140139 name,
141140 self.versionString(self.versyms.items[i]),
142141 });
143 defer gpa.free(full_name);
144 break :blk try elf_file.strtab.insert(gpa, full_name);
145 } else try elf_file.strtab.insert(gpa, name);
146 const gop = try elf_file.getOrPutGlobal(off);
142 defer gpa.free(mangled);
143 const name_off = @as(u32, @intCast(self.strtab.items.len));
144 try self.strtab.writer(gpa).print("{s}\x00", .{mangled});
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));
147151 self.symbols.addOneAssumeCapacity().* = gop.index;
148152 }
149153}
......@@ -151,7 +155,7 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
151155pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
152156 for (self.globals(), 0..) |index, i| {
153157 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
156160 if (this_sym.st_shndx == elf.SHN_UNDEF) continue;
157161
......@@ -166,18 +170,9 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
166170 }
167171}
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
178173pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
179174 for (self.globals(), 0..) |index, i| {
180 const sym = self.symtab[i];
175 const sym = self.symtab.items[i];
181176 if (sym.st_shndx != elf.SHN_UNDEF) continue;
182177
183178 const global = elf_file.symbol(index);
......@@ -193,27 +188,6 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
193188 }
194189}
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
217191pub fn globals(self: SharedObject) []const Symbol.Index {
218192 return self.symbols.items;
219193}
......@@ -223,11 +197,6 @@ pub fn shdrContents(self: SharedObject, index: u16) []const u8 {
223197 return self.data[shdr.sh_offset..][0..shdr.sh_size];
224198}
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
231200pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {
232201 const off = self.verstrings.items[index & elf.VERSYM_VERSION];
233202 return self.getString(off);
......@@ -309,6 +278,25 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3
309278 return aliases.items[start..end];
310279}
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
312300pub fn format(
313301 self: SharedObject,
314302 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 {
5858}
5959
6060pub 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 };
6266}
6367
6468pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
......@@ -71,11 +75,10 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
7175
7276pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
7377 const file_ptr = symbol.file(elf_file).?;
74 switch (file_ptr) {
75 .zig_object => |x| return x.elfSym(symbol.esym_index).*,
76 .linker_defined => |x| return x.symtab.items[symbol.esym_index],
77 inline else => |x| return x.symtab[symbol.esym_index],
78 }
78 return switch (file_ptr) {
79 .zig_object => |x| x.elfSym(symbol.esym_index).*,
80 inline else => |x| x.symtab.items[symbol.esym_index],
81 };
7982}
8083
8184pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
......@@ -201,10 +204,7 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
201204}
202205
203206pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
204 const file_ptr = symbol.file(elf_file) orelse {
205 out.* = Elf.null_sym;
206 return;
207 };
207 const file_ptr = symbol.file(elf_file).?;
208208 const esym = symbol.elfSym(elf_file);
209209 const st_type = symbol.type(elf_file);
210210 const st_bind: u8 = blk: {
......@@ -232,14 +232,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
232232 break :blk symbol.value - elf_file.tlsAddress();
233233 break :blk symbol.value;
234234 };
235 out.* = .{
236 .st_name = symbol.name_offset,
237 .st_info = (st_bind << 4) | st_type,
238 .st_other = esym.st_other,
239 .st_shndx = st_shndx,
240 .st_value = st_value,
241 .st_size = esym.st_size,
242 };
235 out.st_info = (st_bind << 4) | st_type;
236 out.st_other = esym.st_other;
237 out.st_shndx = st_shndx;
238 out.st_value = st_value;
239 out.st_size = esym.st_size;
243240}
244241
245242pub fn format(
......@@ -340,6 +337,12 @@ pub const Flags = packed struct {
340337 /// Whether this symbol is weak.
341338 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
343346 /// Whether the symbol makes into the output symtab.
344347 output_symtab: bool = false,
345348
src/link/Elf/ZigObject.zig+27-75
......@@ -9,6 +9,7 @@ index: File.Index,
99
1010local_esyms: std.MultiArrayList(ElfSym) = .{},
1111global_esyms: std.MultiArrayList(ElfSym) = .{},
12strtab: std.ArrayListUnmanaged(u8) = .{},
1213local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1314global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1415globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
......@@ -74,8 +75,9 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
7475 const gpa = elf_file.base.allocator;
7576
7677 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));
7981 const symbol_index = try elf_file.addSymbol();
8082 try self.local_symbols.append(gpa, symbol_index);
8183 const symbol_ptr = elf_file.symbol(symbol_index);
......@@ -97,6 +99,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
9799pub fn deinit(self: *ZigObject, allocator: Allocator) void {
98100 self.local_esyms.deinit(allocator);
99101 self.global_esyms.deinit(allocator);
102 self.strtab.deinit(allocator);
100103 self.local_symbols.deinit(allocator);
101104 self.global_symbols.deinit(allocator);
102105 self.globals_lookup.deinit(allocator);
......@@ -379,15 +382,6 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
379382 }
380383}
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
391385pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
392386 for (self.globals(), 0..) |index, i| {
393387 const esym = self.global_esyms.items(.elf_sym)[i];
......@@ -404,60 +398,6 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
404398 }
405399}
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
461401pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {
462402 const is_global = index & global_symbol_bit != 0;
463403 const actual_index = index & symbol_mask;
......@@ -727,7 +667,7 @@ fn updateDeclCode(
727667 sym.output_section_index = shdr_index;
728668 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);
731671 atom_ptr.flags.alive = true;
732672 atom_ptr.name_offset = sym.name_offset;
733673 esym.st_name = sym.name_offset;
......@@ -967,7 +907,7 @@ fn updateLazySymbol(
967907 sym.ty.fmt(mod),
968908 });
969909 defer gpa.free(name);
970 break :blk try elf_file.strtab.insert(gpa, name);
910 break :blk try self.insertString(gpa, name);
971911 };
972912
973913 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
......@@ -1100,7 +1040,7 @@ fn lowerConst(
11001040
11011041 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
11021042 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);
11041044 local_sym.name_offset = name_str_index;
11051045 local_sym.output_section_index = output_section_index;
11061046 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
......@@ -1195,8 +1135,8 @@ pub fn updateExports(
11951135 };
11961136 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
11971137 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
1198 const name_off = try elf_file.strtab.insert(gpa, exp_name);
1199 const global_esym_index = if (metadata.@"export"(self, elf_file, exp_name)) |exp_index|
1138 const name_off = try self.insertString(gpa, exp_name);
1139 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
12001140 exp_index.*
12011141 else blk: {
12021142 const global_esym_index = try self.addGlobalEsym(gpa);
......@@ -1205,7 +1145,7 @@ pub fn updateExports(
12051145 global_esym.st_name = name_off;
12061146 lookup_gop.value_ptr.* = global_esym_index;
12071147 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);
12091149 try self.global_symbols.append(gpa, gop.index);
12101150 break :blk global_esym_index;
12111151 };
......@@ -1248,7 +1188,7 @@ pub fn deleteDeclExport(
12481188 const metadata = self.decls.getPtr(decl_index) orelse return;
12491189 const mod = elf_file.base.options.module.?;
12501190 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;
12521192 log.debug("deleting export '{s}'", .{exp_name});
12531193 const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];
12541194 _ = self.globals_lookup.remove(esym.st_name);
......@@ -1265,19 +1205,31 @@ pub fn deleteDeclExport(
12651205pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
12661206 _ = lib_name;
12671207 const gpa = elf_file.base.allocator;
1268 const off = try elf_file.strtab.insert(gpa, name);
1208 const off = try self.insertString(gpa, name);
12691209 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
12701210 if (!lookup_gop.found_existing) {
12711211 const esym_index = try self.addGlobalEsym(gpa);
12721212 const esym = self.elfSym(esym_index);
12731213 esym.st_name = off;
12741214 lookup_gop.value_ptr.* = esym_index;
1275 const gop = try elf_file.getOrPutGlobal(off);
1215 const gop = try elf_file.getOrPutGlobal(name);
12761216 try self.global_symbols.append(gpa, gop.index);
12771217 }
12781218 return lookup_gop.value_ptr.*;
12791219}
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
12811233pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
12821234 return .{ .data = .{
12831235 .self = self,
......@@ -1350,9 +1302,9 @@ const DeclMetadata = struct {
13501302 /// A list of all exports aliases of this Decl.
13511303 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 {
13541306 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);
13561308 if (mem.eql(u8, name, exp_name)) return exp;
13571309 }
13581310 return null;
src/link/Elf/eh_frame.zig+1-1
......@@ -43,7 +43,7 @@ pub const Fde = struct {
4343 pub fn atom(fde: Fde, elf_file: *Elf) *Atom {
4444 const object = elf_file.file(fde.file_index).?.object;
4545 const rel = fde.relocs(elf_file)[0];
46 const sym = object.symtab[rel.r_sym()];
46 const sym = object.symtab.items[rel.r_sym()];
4747 const atom_index = object.atoms.items[sym.st_shndx];
4848 return elf_file.atom(atom_index).?;
4949 }
src/link/Elf/file.zig+77-8
......@@ -68,9 +68,12 @@ pub const File = union(enum) {
6868 }
6969
7070 pub fn resetGlobals(file: File, elf_file: *Elf) void {
71 switch (file) {
72 .linker_defined => unreachable,
73 inline else => |x| x.resetGlobals(elf_file),
71 for (file.globals()) |global_index| {
72 const global = elf_file.symbol(global_index);
73 const name_offset = global.name_offset;
74 global.* = .{};
75 global.name_offset = name_offset;
76 global.flags.global = true;
7477 }
7578 }
7679
......@@ -83,15 +86,14 @@ pub const File = union(enum) {
8386
8487 pub fn markLive(file: File, elf_file: *Elf) void {
8588 switch (file) {
86 .linker_defined => unreachable,
89 .linker_defined => {},
8790 inline else => |x| x.markLive(elf_file),
8891 }
8992 }
9093
9194 pub fn atoms(file: File) []const Atom.Index {
9295 return switch (file) {
93 .linker_defined => unreachable,
94 .shared_object => unreachable,
96 .linker_defined, .shared_object => &[0]Atom.Index{},
9597 .zig_object => |x| x.atoms.items,
9698 .object => |x| x.atoms.items,
9799 };
......@@ -99,8 +101,7 @@ pub const File = union(enum) {
99101
100102 pub fn locals(file: File) []const Symbol.Index {
101103 return switch (file) {
102 .linker_defined => unreachable,
103 .shared_object => unreachable,
104 .linker_defined, .shared_object => &[0]Symbol.Index{},
104105 inline else => |x| x.locals(),
105106 };
106107 }
......@@ -111,6 +112,74 @@ pub const File = union(enum) {
111112 };
112113 }
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
114183 pub const Index = u32;
115184
116185 pub const Entry = union(enum) {
src/link/Elf/synthetic_sections.zig+39-67
......@@ -9,7 +9,7 @@ pub const DynamicSection = struct {
99
1010 pub fn addNeeded(dt: *DynamicSection, shared: *SharedObject, elf_file: *Elf) !void {
1111 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());
1313 try dt.needed.append(gpa, off);
1414 }
1515
......@@ -22,11 +22,11 @@ pub const DynamicSection = struct {
2222 if (i > 0) try rpath.append(':');
2323 try rpath.appendSlice(path);
2424 }
25 dt.rpath = try elf_file.dynstrtab.insert(gpa, rpath.items);
25 dt.rpath = try elf_file.insertDynString(rpath.items);
2626 }
2727
2828 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);
3030 }
3131
3232 fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 {
......@@ -359,31 +359,24 @@ pub const ZigGotSection = struct {
359359 }
360360
361361 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
362 _ = elf_file;
363362 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;
368363 for (zig_got.entries.items) |entry| {
369 const symbol_name = elf_file.symbol(entry).name(elf_file);
370 const name = try std.fmt.allocPrint(gpa, "{s}$ziggot", .{symbol_name});
371 defer gpa.free(name);
372 _ = try elf_file.strtab.insert(gpa, name);
364 const name = elf_file.symbol(entry).name(elf_file);
365 zig_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
373366 }
374367 }
375368
376 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) !void {
377 const gpa = elf_file.base.allocator;
369 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) void {
378370 for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {
379371 const symbol = elf_file.symbol(entry);
380372 const symbol_name = symbol.name(elf_file);
381 const name = try std.fmt.allocPrint(gpa, "{s}$ziggot", .{symbol_name});
382 defer gpa.free(name);
383 const st_name = try elf_file.strtab.insert(gpa, name);
373 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
374 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
375 elf_file.strtab.appendSliceAssumeCapacity("$ziggot");
376 elf_file.strtab.appendAssumeCapacity(0);
384377 const st_value = zig_got.entryAddress(@intCast(index), elf_file);
385378 const st_size = elf_file.archPtrWidthBytes();
386 ctx.symtab[ilocal] = .{
379 elf_file.symtab.items[ilocal] = .{
387380 .st_name = st_name,
388381 .st_info = elf.STT_OBJECT,
389382 .st_other = 0,
......@@ -767,25 +760,17 @@ pub const GotSection = struct {
767760 }
768761
769762 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
770 _ = elf_file;
771763 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;
776764 for (got.entries.items) |entry| {
777765 const symbol_name = switch (entry.tag) {
778766 .tlsld => "",
779767 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
780768 };
781 const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) });
782 defer gpa.free(name);
783 _ = try elf_file.strtab.insert(gpa, name);
769 got.output_symtab_size.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
784770 }
785771 }
786772
787 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) !void {
788 const gpa = elf_file.base.allocator;
773 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) void {
789774 for (got.entries.items, ctx.ilocal..) |entry, ilocal| {
790775 const symbol = switch (entry.tag) {
791776 .tlsld => null,
......@@ -795,12 +780,14 @@ pub const GotSection = struct {
795780 .tlsld => "",
796781 inline else => symbol.?.name(elf_file),
797782 };
798 const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) });
799 defer gpa.free(name);
800 const st_name = try elf_file.strtab.insert(gpa, name);
783 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
784 elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
785 elf_file.strtab.appendAssumeCapacity('$');
786 elf_file.strtab.appendSliceAssumeCapacity(@tagName(entry.tag));
787 elf_file.strtab.appendAssumeCapacity(0);
801788 const st_value = entry.address(elf_file);
802789 const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes();
803 ctx.symtab[ilocal] = .{
790 elf_file.symtab.items[ilocal] = .{
804791 .st_name = st_name,
805792 .st_info = elf.STT_OBJECT,
806793 .st_other = 0,
......@@ -922,30 +909,22 @@ pub const PltSection = struct {
922909 }
923910
924911 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
925 _ = elf_file;
926912 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;
931913 for (plt.symbols.items) |sym_index| {
932 const sym = elf_file.symbol(sym_index);
933 const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)});
934 defer gpa.free(name);
935 _ = try elf_file.strtab.insert(gpa, name);
914 const name = elf_file.symbol(sym_index).name(elf_file);
915 plt.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
936916 }
937917 }
938918
939 pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) !void {
940 const gpa = elf_file.base.allocator;
941
919 pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) void {
942920 var ilocal = ctx.ilocal;
943921 for (plt.symbols.items) |sym_index| {
944922 const sym = elf_file.symbol(sym_index);
945 const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)});
946 defer gpa.free(name);
947 const st_name = try elf_file.strtab.insert(gpa, name);
948 ctx.symtab[ilocal] = .{
923 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
924 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
925 elf_file.strtab.appendSliceAssumeCapacity("$plt");
926 elf_file.strtab.appendAssumeCapacity(0);
927 elf_file.symtab.items[ilocal] = .{
949928 .st_name = st_name,
950929 .st_info = elf.STT_FUNC,
951930 .st_other = 0,
......@@ -1029,29 +1008,22 @@ pub const PltGotSection = struct {
10291008 }
10301009
10311010 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
1032 _ = elf_file;
10331011 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;
10381012 for (plt_got.symbols.items) |sym_index| {
1039 const sym = elf_file.symbol(sym_index);
1040 const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)});
1041 defer gpa.free(name);
1042 _ = try elf_file.strtab.insert(gpa, name);
1013 const name = elf_file.symbol(sym_index).name(elf_file);
1014 plt_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
10431015 }
10441016 }
10451017
1046 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) !void {
1047 const gpa = elf_file.base.allocator;
1018 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) void {
10481019 var ilocal = ctx.ilocal;
10491020 for (plt_got.symbols.items) |sym_index| {
10501021 const sym = elf_file.symbol(sym_index);
1051 const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)});
1052 defer gpa.free(name);
1053 const st_name = try elf_file.strtab.insert(gpa, name);
1054 ctx.symtab[ilocal] = .{
1022 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
1023 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
1024 elf_file.strtab.appendSliceAssumeCapacity("$pltgot");
1025 elf_file.strtab.appendAssumeCapacity(0);
1026 elf_file.symtab.items[ilocal] = .{
10551027 .st_name = st_name,
10561028 .st_info = elf.STT_FUNC,
10571029 .st_other = 0,
......@@ -1166,7 +1138,7 @@ pub const DynsymSection = struct {
11661138 new_extra.dynamic = index;
11671139 sym.setExtra(new_extra, elf_file);
11681140 } 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));
11701142 try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });
11711143 }
11721144
......@@ -1251,7 +1223,7 @@ pub const HashSection = struct {
12511223 @memset(chains, 0);
12521224
12531225 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);
12551227 const hash = hasher(name) % buckets.len;
12561228 chains[@as(u32, @intCast(i))] = buckets[hash];
12571229 buckets[hash] = @as(u32, @intCast(i));
......@@ -1490,7 +1462,7 @@ pub const VerneedSection = struct {
14901462 sym.* = .{
14911463 .vn_version = 1,
14921464 .vn_cnt = 0,
1493 .vn_file = try elf_file.dynstrtab.insert(gpa, soname),
1465 .vn_file = try elf_file.insertDynString(soname),
14941466 .vn_aux = 0,
14951467 .vn_next = 0,
14961468 };
......@@ -1509,7 +1481,7 @@ pub const VerneedSection = struct {
15091481 .vna_hash = HashSection.hasher(version),
15101482 .vna_flags = 0,
15111483 .vna_other = vern.index,
1512 .vna_name = try elf_file.dynstrtab.insert(gpa, version),
1484 .vna_name = try elf_file.insertDynString(version),
15131485 .vna_next = 0,
15141486 };
15151487 verneed_sym.vn_cnt += 1;
src/link/MachO.zig+2-2
......@@ -58,7 +58,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},
5858dyld_stub_binder_index: ?u32 = null,
5959dyld_private_atom_index: ?Atom.Index = null,
6060
61strtab: StringTable(.strtab) = .{},
61strtab: StringTable = .{},
6262
6363got_table: TableSection(SymbolWithLoc) = .{},
6464stub_table: TableSection(SymbolWithLoc) = .{},
......@@ -5643,7 +5643,7 @@ const Module = @import("../Module.zig");
56435643const InternPool = @import("../InternPool.zig");
56445644const Platform = load_commands.Platform;
56455645const Relocation = @import("MachO/Relocation.zig");
5646const StringTable = @import("strtab.zig").StringTable;
5646const StringTable = @import("StringTable.zig");
56475647const TableSection = @import("table_section.zig").TableSection;
56485648const Trie = @import("MachO/Trie.zig");
56495649const Type = @import("../type.zig").Type;
src/link/MachO/DebugSymbols.zig+2-2
......@@ -22,7 +22,7 @@ debug_aranges_section_dirty: bool = false,
2222debug_info_header_dirty: bool = false,
2323debug_line_header_dirty: bool = false,
2424
25strtab: StringTable(.strtab) = .{},
25strtab: StringTable = .{},
2626relocs: std.ArrayListUnmanaged(Reloc) = .{},
2727
2828pub const Reloc = struct {
......@@ -567,5 +567,5 @@ const Allocator = mem.Allocator;
567567const Dwarf = @import("../Dwarf.zig");
568568const MachO = @import("../MachO.zig");
569569const Module = @import("../../Module.zig");
570const StringTable = @import("../strtab.zig").StringTable;
570const StringTable = @import("../StringTable.zig");
571571const Type = @import("../../type.zig").Type;
src/link/MachO/zld.zig-1
......@@ -1227,7 +1227,6 @@ const LibStub = @import("../tapi.zig").LibStub;
12271227const Object = @import("Object.zig");
12281228const Platform = load_commands.Platform;
12291229const Section = MachO.Section;
1230const StringTable = @import("../strtab.zig").StringTable;
12311230const SymbolWithLoc = MachO.SymbolWithLoc;
12321231const TableSection = @import("../table_section.zig").TableSection;
12331232const 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}