authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-14 22:13:21+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log0135b4665988530c0bd6b36ef7cb93ecaf999776
treedd9ba7fdc2173ecfa8fc028d24a2e63f62ada94d
parentf87424ab6393c3208d96a4f078c71f745a37c84b

zld: remove StringTable abstraction


6 files changed, 98 insertions(+), 103 deletions(-)

CMakeLists.txt-1
......@@ -581,7 +581,6 @@ set(ZIG_STAGE2_SOURCES
581581 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
582582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
583583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
584 "${CMAKE_SOURCE_DIR}/src/link/MachO/StringTable.zig"
585584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
586585 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
587586 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
src/link/MachO.zig+46-15
......@@ -26,7 +26,6 @@ const target_util = @import("../target.zig");
2626const DebugSymbols = @import("MachO/DebugSymbols.zig");
2727const Trie = @import("MachO/Trie.zig");
2828const CodeSignature = @import("MachO/CodeSignature.zig");
29const StringTable = @import("MachO/StringTable.zig");
3029const Zld = @import("MachO/Zld.zig");
3130
3231usingnamespace @import("MachO/commands.zig");
......@@ -117,7 +116,8 @@ offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
117116
118117stub_helper_stubs_start_off: ?u64 = null,
119118
120strtab: StringTable = undefined,
119strtab: std.ArrayListUnmanaged(u8) = .{},
120strtab_cache: std.StringHashMapUnmanaged(u32) = .{},
121121
122122/// Table of GOT entries.
123123offset_table: std.ArrayListUnmanaged(GOTEntry) = .{},
......@@ -418,7 +418,6 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO {
418418 .file = null,
419419 },
420420 .page_size = if (options.target.cpu.arch == .aarch64) 0x4000 else 0x1000,
421 .strtab = try StringTable.init(gpa),
422421 };
423422
424423 return self;
......@@ -985,7 +984,14 @@ pub fn deinit(self: *MachO) void {
985984 self.text_block_free_list.deinit(self.base.allocator);
986985 self.offset_table.deinit(self.base.allocator);
987986 self.offset_table_free_list.deinit(self.base.allocator);
988 self.strtab.deinit();
987 {
988 var it = self.strtab_cache.keyIterator();
989 while (it.next()) |key| {
990 self.base.allocator.free(key.*);
991 }
992 }
993 self.strtab_cache.deinit(self.base.allocator);
994 self.strtab.deinit(self.base.allocator);
989995 self.globals.deinit(self.base.allocator);
990996 self.globals_free_list.deinit(self.base.allocator);
991997 self.locals.deinit(self.base.allocator);
......@@ -1203,7 +1209,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12031209 const new_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});
12041210 defer self.base.allocator.free(new_name);
12051211
1206 symbol.n_strx = try self.strtab.getOrPut(new_name);
1212 symbol.n_strx = try self.makeString(new_name);
12071213 symbol.n_type = macho.N_SECT;
12081214 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
12091215 symbol.n_desc = 0;
......@@ -1215,7 +1221,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12151221 const decl_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});
12161222 defer self.base.allocator.free(decl_name);
12171223
1218 const name_str_index = try self.strtab.getOrPut(decl_name);
1224 const name_str_index = try self.makeString(decl_name);
12191225 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);
12201226
12211227 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, addr });
......@@ -1405,14 +1411,14 @@ pub fn updateDeclExports(
14051411 if (exp.link.macho.sym_index) |i| {
14061412 const sym = &self.globals.items[i];
14071413 sym.* = .{
1408 .n_strx = try self.strtab.getOrPut(exp_name),
1414 .n_strx = sym.n_strx,
14091415 .n_type = n_type,
14101416 .n_sect = @intCast(u8, self.text_section_index.?) + 1,
14111417 .n_desc = n_desc,
14121418 .n_value = decl_sym.n_value,
14131419 };
14141420 } else {
1415 const name_str_index = try self.strtab.getOrPut(exp_name);
1421 const name_str_index = try self.makeString(exp_name);
14161422 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {
14171423 _ = self.globals.addOneAssumeCapacity();
14181424 self.export_info_dirty = true;
......@@ -1788,7 +1794,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
17881794 symtab.symoff = @intCast(u32, symtab_off);
17891795 symtab.nsyms = @intCast(u32, self.base.options.symbol_count_hint);
17901796
1791 const strtab_size = self.strtab.size();
1797 try self.strtab.append(self.base.allocator, 0);
1798 const strtab_size = self.strtab.items.len;
17921799 const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1, symtab_off);
17931800 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size });
17941801 symtab.stroff = @intCast(u32, strtab_off);
......@@ -1930,7 +1937,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
19301937 if (!self.nonlazy_imports.contains("dyld_stub_binder")) {
19311938 const index = @intCast(u32, self.nonlazy_imports.count());
19321939 const name = try self.base.allocator.dupe(u8, "dyld_stub_binder");
1933 const offset = try self.strtab.getOrPut("dyld_stub_binder");
1940 const offset = try self.makeString("dyld_stub_binder");
19341941 try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{
19351942 .symbol = .{
19361943 .n_strx = offset,
......@@ -2063,7 +2070,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
20632070
20642071pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
20652072 const index = @intCast(u32, self.lazy_imports.count());
2066 const offset = try self.strtab.getOrPut(name);
2073 const offset = try self.makeString(name);
20672074 const sym_name = try self.base.allocator.dupe(u8, name);
20682075 const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem.
20692076 try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{
......@@ -2253,7 +2260,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
22532260 },
22542261 }
22552262 };
2256 const sym_name = self.strtab.get(sym.n_strx) orelse unreachable;
2263 const sym_name = self.getString(sym.n_strx) orelse unreachable;
22572264 log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{ off, sym.n_value, sym_name });
22582265 try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off);
22592266}
......@@ -2751,7 +2758,7 @@ fn writeExportTrie(self: *MachO) !void {
27512758 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
27522759 for (self.globals.items) |symbol| {
27532760 // TODO figure out if we should put all global symbols into the export trie
2754 const name = self.strtab.get(symbol.n_strx) orelse unreachable;
2761 const name = self.getString(symbol.n_strx) orelse unreachable;
27552762 assert(symbol.n_value >= text_segment.inner.vmaddr);
27562763 try trie.put(.{
27572764 .name = name,
......@@ -3032,7 +3039,7 @@ fn writeStringTable(self: *MachO) !void {
30323039
30333040 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
30343041 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);
3035 const needed_size = mem.alignForwardGeneric(u64, self.strtab.size(), @alignOf(u64));
3042 const needed_size = mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64));
30363043
30373044 if (needed_size > allocated_size or self.strtab_needs_relocation) {
30383045 symtab.strsize = 0;
......@@ -3042,7 +3049,7 @@ fn writeStringTable(self: *MachO) !void {
30423049 symtab.strsize = @intCast(u32, needed_size);
30433050 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
30443051
3045 try self.base.file.?.pwriteAll(self.strtab.asSlice(), symtab.stroff);
3052 try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
30463053 self.load_commands_dirty = true;
30473054 self.strtab_dirty = false;
30483055}
......@@ -3173,3 +3180,27 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
31733180fn hasTlvDescriptors(_: *MachO) bool {
31743181 return false;
31753182}
3183
3184pub fn makeString(self: *MachO, string: []const u8) !u32 {
3185 if (self.strtab_cache.get(string)) |off| {
3186 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
3187 return off;
3188 }
3189
3190 try self.strtab.ensureUnusedCapacity(self.base.allocator, string.len + 1);
3191 const new_off = @intCast(u32, self.strtab.items.len);
3192
3193 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, new_off });
3194
3195 self.strtab.appendSliceAssumeCapacity(string);
3196 self.strtab.appendAssumeCapacity(0);
3197
3198 try self.strtab_cache.putNoClobber(self.base.allocator, try self.base.allocator.dupe(u8, string), new_off);
3199
3200 return new_off;
3201}
3202
3203pub fn getString(self: *MachO, off: u32) ?[]const u8 {
3204 assert(off < self.strtab.items.len);
3205 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off));
3206}
src/link/MachO/DebugSymbols.zig+2-2
......@@ -814,7 +814,7 @@ fn writeStringTable(self: *DebugSymbols) !void {
814814
815815 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
816816 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);
817 const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.size(), @alignOf(u64));
817 const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64));
818818
819819 if (needed_size > allocated_size) {
820820 symtab.strsize = 0;
......@@ -823,7 +823,7 @@ fn writeStringTable(self: *DebugSymbols) !void {
823823 symtab.strsize = @intCast(u32, needed_size);
824824 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
825825
826 try self.file.pwriteAll(self.base.strtab.asSlice(), symtab.stroff);
826 try self.file.pwriteAll(self.base.strtab.items, symtab.stroff);
827827 self.load_commands_dirty = true;
828828 self.strtab_dirty = false;
829829}
src/link/MachO/StringTable.zig deleted-64
......@@ -1,64 +0,0 @@
1const StringTable = @This();
2
3const std = @import("std");
4const log = std.log.scoped(.strtab);
5const mem = std.mem;
6
7const Allocator = mem.Allocator;
8
9allocator: *Allocator,
10buffer: std.ArrayListUnmanaged(u8) = .{},
11cache: std.StringHashMapUnmanaged(u32) = .{},
12
13pub const Error = error{OutOfMemory};
14
15pub fn init(allocator: *Allocator) Error!StringTable {
16 var strtab = StringTable{
17 .allocator = allocator,
18 };
19 try strtab.buffer.append(allocator, 0);
20 return strtab;
21}
22
23pub fn deinit(self: *StringTable) void {
24 {
25 var it = self.cache.keyIterator();
26 while (it.next()) |key| {
27 self.allocator.free(key.*);
28 }
29 }
30 self.cache.deinit(self.allocator);
31 self.buffer.deinit(self.allocator);
32}
33
34pub fn getOrPut(self: *StringTable, string: []const u8) Error!u32 {
35 if (self.cache.get(string)) |off| {
36 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
37 return off;
38 }
39
40 try self.buffer.ensureUnusedCapacity(self.allocator, string.len + 1);
41 const new_off = @intCast(u32, self.buffer.items.len);
42
43 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, new_off });
44
45 self.buffer.appendSliceAssumeCapacity(string);
46 self.buffer.appendAssumeCapacity(0);
47
48 try self.cache.putNoClobber(self.allocator, try self.allocator.dupe(u8, string), new_off);
49
50 return new_off;
51}
52
53pub fn get(self: StringTable, off: u32) ?[]const u8 {
54 if (off >= self.buffer.items.len) return null;
55 return mem.spanZ(@ptrCast([*:0]const u8, self.buffer.items.ptr + off));
56}
57
58pub fn asSlice(self: StringTable) []const u8 {
59 return self.buffer.items;
60}
61
62pub fn size(self: StringTable) u64 {
63 return self.buffer.items.len;
64}
src/link/MachO/Symbol.zig+2-3
......@@ -9,7 +9,6 @@ const mem = std.mem;
99const Allocator = mem.Allocator;
1010const Dylib = @import("Dylib.zig");
1111const Object = @import("Object.zig");
12const StringTable = @import("StringTable.zig");
1312const Zld = @import("Zld.zig");
1413
1514/// Symbol name. Owned slice.
......@@ -226,8 +225,8 @@ pub fn needsTlvOffset(self: Symbol, zld: *Zld) bool {
226225 return sect_type == macho.S_THREAD_LOCAL_VARIABLES;
227226}
228227
229pub fn asNlist(symbol: *Symbol, zld: *Zld, strtab: *StringTable) !macho.nlist_64 {
230 const n_strx = try strtab.getOrPut(symbol.name);
228pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
229 const n_strx = try zld.makeString(symbol.name);
231230 const nlist = nlist: {
232231 switch (symbol.payload) {
233232 .regular => |regular| {
src/link/MachO/Zld.zig+48-18
......@@ -18,7 +18,6 @@ const CodeSignature = @import("CodeSignature.zig");
1818const Dylib = @import("Dylib.zig");
1919const Object = @import("Object.zig");
2020const Relocation = reloc.Relocation;
21const StringTable = @import("StringTable.zig");
2221const Symbol = @import("Symbol.zig");
2322const Trie = @import("Trie.zig");
2423
......@@ -26,7 +25,6 @@ usingnamespace @import("commands.zig");
2625usingnamespace @import("bind.zig");
2726
2827allocator: *Allocator,
29strtab: StringTable,
3028
3129target: ?std.Target = null,
3230page_size: ?u16 = null,
......@@ -114,6 +112,9 @@ stub_helper_stubs_start_off: ?u64 = null,
114112
115113blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
116114
115strtab: std.ArrayListUnmanaged(u8) = .{},
116strtab_cache: std.StringHashMapUnmanaged(u32) = .{},
117
117118has_dices: bool = false,
118119has_stabs: bool = false,
119120
......@@ -169,7 +170,7 @@ pub const TextBlock = struct {
169170 .n_value = reg.address,
170171 });
171172 nlists.appendAssumeCapacity(.{
172 .n_strx = try zld.strtab.getOrPut(sym.name),
173 .n_strx = try zld.makeString(sym.name),
173174 .n_type = macho.N_FUN,
174175 .n_sect = section_id,
175176 .n_desc = 0,
......@@ -192,7 +193,7 @@ pub const TextBlock = struct {
192193 },
193194 .global => {
194195 try nlists.append(.{
195 .n_strx = try zld.strtab.getOrPut(sym.name),
196 .n_strx = try zld.makeString(sym.name),
196197 .n_type = macho.N_GSYM,
197198 .n_sect = 0,
198199 .n_desc = 0,
......@@ -201,7 +202,7 @@ pub const TextBlock = struct {
201202 },
202203 .static => {
203204 try nlists.append(.{
204 .n_strx = try zld.strtab.getOrPut(sym.name),
205 .n_strx = try zld.makeString(sym.name),
205206 .n_type = macho.N_STSYM,
206207 .n_sect = reg.sectionId(zld),
207208 .n_desc = 0,
......@@ -311,10 +312,7 @@ pub const TextBlock = struct {
311312const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
312313
313314pub fn init(allocator: *Allocator) !Zld {
314 return Zld{
315 .allocator = allocator,
316 .strtab = try StringTable.init(allocator),
317 };
315 return Zld{ .allocator = allocator };
318316}
319317
320318pub fn deinit(self: *Zld) void {
......@@ -357,7 +355,15 @@ pub fn deinit(self: *Zld) void {
357355 self.locals.deinit(self.allocator);
358356
359357 self.globals.deinit(self.allocator);
360 self.strtab.deinit();
358
359 {
360 var it = self.strtab_cache.keyIterator();
361 while (it.next()) |key| {
362 self.allocator.free(key.*);
363 }
364 }
365 self.strtab_cache.deinit(self.allocator);
366 self.strtab.deinit(self.allocator);
361367
362368 // TODO dealloc all blocks
363369 self.blocks.deinit(self.allocator);
......@@ -2572,7 +2578,7 @@ fn writeSymbolTable(self: *Zld) !void {
25722578 if (symbol.isTemp()) continue; // TODO when merging codepaths, this should go into freelist
25732579
25742580 const reg = symbol.payload.regular;
2575 const nlist = try symbol.asNlist(self, &self.strtab);
2581 const nlist = try symbol.asNlist(self);
25762582
25772583 if (reg.linkage == .translation_unit) {
25782584 try locals.append(nlist);
......@@ -2588,21 +2594,21 @@ fn writeSymbolTable(self: *Zld) !void {
25882594 // Open scope
25892595 try locals.ensureUnusedCapacity(4);
25902596 locals.appendAssumeCapacity(.{
2591 .n_strx = try self.strtab.getOrPut(object.tu_comp_dir.?),
2597 .n_strx = try self.makeString(object.tu_comp_dir.?),
25922598 .n_type = macho.N_SO,
25932599 .n_sect = 0,
25942600 .n_desc = 0,
25952601 .n_value = 0,
25962602 });
25972603 locals.appendAssumeCapacity(.{
2598 .n_strx = try self.strtab.getOrPut(object.tu_name.?),
2604 .n_strx = try self.makeString(object.tu_name.?),
25992605 .n_type = macho.N_SO,
26002606 .n_sect = 0,
26012607 .n_desc = 0,
26022608 .n_value = 0,
26032609 });
26042610 locals.appendAssumeCapacity(.{
2605 .n_strx = try self.strtab.getOrPut(object.name.?),
2611 .n_strx = try self.makeString(object.name.?),
26062612 .n_type = macho.N_OSO,
26072613 .n_sect = 0,
26082614 .n_desc = 1,
......@@ -2642,7 +2648,7 @@ fn writeSymbolTable(self: *Zld) !void {
26422648 defer undef_dir.deinit();
26432649
26442650 for (self.imports.items) |sym| {
2645 const nlist = try sym.asNlist(self, &self.strtab);
2651 const nlist = try sym.asNlist(self);
26462652 const id = @intCast(u32, undefs.items.len);
26472653 try undefs.append(nlist);
26482654 try undef_dir.putNoClobber(sym.name, id);
......@@ -2737,14 +2743,14 @@ fn writeStringTable(self: *Zld) !void {
27372743 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
27382744 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
27392745 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
2740 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.size(), @alignOf(u64)));
2746 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
27412747 seg.inner.filesize += symtab.strsize;
27422748
27432749 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
27442750
2745 try self.file.?.pwriteAll(self.strtab.asSlice(), symtab.stroff);
2751 try self.file.?.pwriteAll(self.strtab.items, symtab.stroff);
27462752
2747 if (symtab.strsize > self.strtab.size() and self.target.?.cpu.arch == .x86_64) {
2753 if (symtab.strsize > self.strtab.items.len and self.target.?.cpu.arch == .x86_64) {
27482754 // This is the last section, so we need to pad it out.
27492755 try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
27502756 }
......@@ -2910,3 +2916,27 @@ fn writeHeader(self: *Zld) !void {
29102916
29112917 try self.file.?.pwriteAll(mem.asBytes(&header), 0);
29122918}
2919
2920pub fn makeString(self: *Zld, string: []const u8) !u32 {
2921 if (self.strtab_cache.get(string)) |off| {
2922 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
2923 return off;
2924 }
2925
2926 try self.strtab.ensureUnusedCapacity(self.allocator, string.len + 1);
2927 const new_off = @intCast(u32, self.strtab.items.len);
2928
2929 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, new_off });
2930
2931 self.strtab.appendSliceAssumeCapacity(string);
2932 self.strtab.appendAssumeCapacity(0);
2933
2934 try self.strtab_cache.putNoClobber(self.allocator, try self.allocator.dupe(u8, string), new_off);
2935
2936 return new_off;
2937}
2938
2939pub fn getString(self: *Zld, off: u32) ?[]const u8 {
2940 assert(off < self.strtab.items.len);
2941 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off));
2942}