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...@@ -581,7 +581,6 @@ set(ZIG_STAGE2_SOURCES
581 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"581 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
584 "${CMAKE_SOURCE_DIR}/src/link/MachO/StringTable.zig"
585 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
586 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"585 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
587 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"586 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
src/link/MachO.zig+46-15
...@@ -26,7 +26,6 @@ const target_util = @import("../target.zig");...@@ -26,7 +26,6 @@ const target_util = @import("../target.zig");
26const DebugSymbols = @import("MachO/DebugSymbols.zig");26const DebugSymbols = @import("MachO/DebugSymbols.zig");
27const Trie = @import("MachO/Trie.zig");27const Trie = @import("MachO/Trie.zig");
28const CodeSignature = @import("MachO/CodeSignature.zig");28const CodeSignature = @import("MachO/CodeSignature.zig");
29const StringTable = @import("MachO/StringTable.zig");
30const Zld = @import("MachO/Zld.zig");29const Zld = @import("MachO/Zld.zig");
3130
32usingnamespace @import("MachO/commands.zig");31usingnamespace @import("MachO/commands.zig");
...@@ -117,7 +116,8 @@ offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},...@@ -117,7 +116,8 @@ offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
117116
118stub_helper_stubs_start_off: ?u64 = null,117stub_helper_stubs_start_off: ?u64 = null,
119118
120strtab: StringTable = undefined,119strtab: std.ArrayListUnmanaged(u8) = .{},
120strtab_cache: std.StringHashMapUnmanaged(u32) = .{},
121121
122/// Table of GOT entries.122/// Table of GOT entries.
123offset_table: std.ArrayListUnmanaged(GOTEntry) = .{},123offset_table: std.ArrayListUnmanaged(GOTEntry) = .{},
...@@ -418,7 +418,6 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO {...@@ -418,7 +418,6 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO {
418 .file = null,418 .file = null,
419 },419 },
420 .page_size = if (options.target.cpu.arch == .aarch64) 0x4000 else 0x1000,420 .page_size = if (options.target.cpu.arch == .aarch64) 0x4000 else 0x1000,
421 .strtab = try StringTable.init(gpa),
422 };421 };
423422
424 return self;423 return self;
...@@ -985,7 +984,14 @@ pub fn deinit(self: *MachO) void {...@@ -985,7 +984,14 @@ pub fn deinit(self: *MachO) void {
985 self.text_block_free_list.deinit(self.base.allocator);984 self.text_block_free_list.deinit(self.base.allocator);
986 self.offset_table.deinit(self.base.allocator);985 self.offset_table.deinit(self.base.allocator);
987 self.offset_table_free_list.deinit(self.base.allocator);986 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);
989 self.globals.deinit(self.base.allocator);995 self.globals.deinit(self.base.allocator);
990 self.globals_free_list.deinit(self.base.allocator);996 self.globals_free_list.deinit(self.base.allocator);
991 self.locals.deinit(self.base.allocator);997 self.locals.deinit(self.base.allocator);
...@@ -1203,7 +1209,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1203,7 +1209,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1203 const new_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});1209 const new_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});
1204 defer self.base.allocator.free(new_name);1210 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);
1207 symbol.n_type = macho.N_SECT;1213 symbol.n_type = macho.N_SECT;
1208 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;1214 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
1209 symbol.n_desc = 0;1215 symbol.n_desc = 0;
...@@ -1215,7 +1221,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1215,7 +1221,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1215 const decl_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});1221 const decl_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});
1216 defer self.base.allocator.free(decl_name);1222 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);
1219 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);1225 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);
12201226
1221 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, addr });1227 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, addr });
...@@ -1405,14 +1411,14 @@ pub fn updateDeclExports(...@@ -1405,14 +1411,14 @@ pub fn updateDeclExports(
1405 if (exp.link.macho.sym_index) |i| {1411 if (exp.link.macho.sym_index) |i| {
1406 const sym = &self.globals.items[i];1412 const sym = &self.globals.items[i];
1407 sym.* = .{1413 sym.* = .{
1408 .n_strx = try self.strtab.getOrPut(exp_name),1414 .n_strx = sym.n_strx,
1409 .n_type = n_type,1415 .n_type = n_type,
1410 .n_sect = @intCast(u8, self.text_section_index.?) + 1,1416 .n_sect = @intCast(u8, self.text_section_index.?) + 1,
1411 .n_desc = n_desc,1417 .n_desc = n_desc,
1412 .n_value = decl_sym.n_value,1418 .n_value = decl_sym.n_value,
1413 };1419 };
1414 } else {1420 } else {
1415 const name_str_index = try self.strtab.getOrPut(exp_name);1421 const name_str_index = try self.makeString(exp_name);
1416 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {1422 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {
1417 _ = self.globals.addOneAssumeCapacity();1423 _ = self.globals.addOneAssumeCapacity();
1418 self.export_info_dirty = true;1424 self.export_info_dirty = true;
...@@ -1788,7 +1794,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1788,7 +1794,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1788 symtab.symoff = @intCast(u32, symtab_off);1794 symtab.symoff = @intCast(u32, symtab_off);
1789 symtab.nsyms = @intCast(u32, self.base.options.symbol_count_hint);1795 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;
1792 const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1, symtab_off);1799 const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1, symtab_off);
1793 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size });1800 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size });
1794 symtab.stroff = @intCast(u32, strtab_off);1801 symtab.stroff = @intCast(u32, strtab_off);
...@@ -1930,7 +1937,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1930,7 +1937,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1930 if (!self.nonlazy_imports.contains("dyld_stub_binder")) {1937 if (!self.nonlazy_imports.contains("dyld_stub_binder")) {
1931 const index = @intCast(u32, self.nonlazy_imports.count());1938 const index = @intCast(u32, self.nonlazy_imports.count());
1932 const name = try self.base.allocator.dupe(u8, "dyld_stub_binder");1939 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");
1934 try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{1941 try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{
1935 .symbol = .{1942 .symbol = .{
1936 .n_strx = offset,1943 .n_strx = offset,
...@@ -2063,7 +2070,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,...@@ -2063,7 +2070,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
20632070
2064pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {2071pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
2065 const index = @intCast(u32, self.lazy_imports.count());2072 const index = @intCast(u32, self.lazy_imports.count());
2066 const offset = try self.strtab.getOrPut(name);2073 const offset = try self.makeString(name);
2067 const sym_name = try self.base.allocator.dupe(u8, name);2074 const sym_name = try self.base.allocator.dupe(u8, name);
2068 const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem.2075 const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem.
2069 try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{2076 try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{
...@@ -2253,7 +2260,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {...@@ -2253,7 +2260,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
2253 },2260 },
2254 }2261 }
2255 };2262 };
2256 const sym_name = self.strtab.get(sym.n_strx) orelse unreachable;2263 const sym_name = self.getString(sym.n_strx) orelse unreachable;
2257 log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{ off, sym.n_value, sym_name });2264 log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{ off, sym.n_value, sym_name });
2258 try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off);2265 try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off);
2259}2266}
...@@ -2751,7 +2758,7 @@ fn writeExportTrie(self: *MachO) !void {...@@ -2751,7 +2758,7 @@ fn writeExportTrie(self: *MachO) !void {
2751 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;2758 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2752 for (self.globals.items) |symbol| {2759 for (self.globals.items) |symbol| {
2753 // TODO figure out if we should put all global symbols into the export trie2760 // 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;
2755 assert(symbol.n_value >= text_segment.inner.vmaddr);2762 assert(symbol.n_value >= text_segment.inner.vmaddr);
2756 try trie.put(.{2763 try trie.put(.{
2757 .name = name,2764 .name = name,
...@@ -3032,7 +3039,7 @@ fn writeStringTable(self: *MachO) !void {...@@ -3032,7 +3039,7 @@ fn writeStringTable(self: *MachO) !void {
30323039
3033 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;3040 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
3034 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);3041 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
3037 if (needed_size > allocated_size or self.strtab_needs_relocation) {3044 if (needed_size > allocated_size or self.strtab_needs_relocation) {
3038 symtab.strsize = 0;3045 symtab.strsize = 0;
...@@ -3042,7 +3049,7 @@ fn writeStringTable(self: *MachO) !void {...@@ -3042,7 +3049,7 @@ fn writeStringTable(self: *MachO) !void {
3042 symtab.strsize = @intCast(u32, needed_size);3049 symtab.strsize = @intCast(u32, needed_size);
3043 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });3050 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);
3046 self.load_commands_dirty = true;3053 self.load_commands_dirty = true;
3047 self.strtab_dirty = false;3054 self.strtab_dirty = false;
3048}3055}
...@@ -3173,3 +3180,27 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -3173,3 +3180,27 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
3173fn hasTlvDescriptors(_: *MachO) bool {3180fn hasTlvDescriptors(_: *MachO) bool {
3174 return false;3181 return false;
3175}3182}
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 {...@@ -814,7 +814,7 @@ fn writeStringTable(self: *DebugSymbols) !void {
814814
815 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;815 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
816 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);816 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
819 if (needed_size > allocated_size) {819 if (needed_size > allocated_size) {
820 symtab.strsize = 0;820 symtab.strsize = 0;
...@@ -823,7 +823,7 @@ fn writeStringTable(self: *DebugSymbols) !void {...@@ -823,7 +823,7 @@ fn writeStringTable(self: *DebugSymbols) !void {
823 symtab.strsize = @intCast(u32, needed_size);823 symtab.strsize = @intCast(u32, needed_size);
824 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });824 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);
827 self.load_commands_dirty = true;827 self.load_commands_dirty = true;
828 self.strtab_dirty = false;828 self.strtab_dirty = false;
829}829}
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;...@@ -9,7 +9,6 @@ const mem = std.mem;
9const Allocator = mem.Allocator;9const Allocator = mem.Allocator;
10const Dylib = @import("Dylib.zig");10const Dylib = @import("Dylib.zig");
11const Object = @import("Object.zig");11const Object = @import("Object.zig");
12const StringTable = @import("StringTable.zig");
13const Zld = @import("Zld.zig");12const Zld = @import("Zld.zig");
1413
15/// Symbol name. Owned slice.14/// Symbol name. Owned slice.
...@@ -226,8 +225,8 @@ pub fn needsTlvOffset(self: Symbol, zld: *Zld) bool {...@@ -226,8 +225,8 @@ pub fn needsTlvOffset(self: Symbol, zld: *Zld) bool {
226 return sect_type == macho.S_THREAD_LOCAL_VARIABLES;225 return sect_type == macho.S_THREAD_LOCAL_VARIABLES;
227}226}
228227
229pub fn asNlist(symbol: *Symbol, zld: *Zld, strtab: *StringTable) !macho.nlist_64 {228pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
230 const n_strx = try strtab.getOrPut(symbol.name);229 const n_strx = try zld.makeString(symbol.name);
231 const nlist = nlist: {230 const nlist = nlist: {
232 switch (symbol.payload) {231 switch (symbol.payload) {
233 .regular => |regular| {232 .regular => |regular| {
src/link/MachO/Zld.zig+48-18
...@@ -18,7 +18,6 @@ const CodeSignature = @import("CodeSignature.zig");...@@ -18,7 +18,6 @@ const CodeSignature = @import("CodeSignature.zig");
18const Dylib = @import("Dylib.zig");18const Dylib = @import("Dylib.zig");
19const Object = @import("Object.zig");19const Object = @import("Object.zig");
20const Relocation = reloc.Relocation;20const Relocation = reloc.Relocation;
21const StringTable = @import("StringTable.zig");
22const Symbol = @import("Symbol.zig");21const Symbol = @import("Symbol.zig");
23const Trie = @import("Trie.zig");22const Trie = @import("Trie.zig");
2423
...@@ -26,7 +25,6 @@ usingnamespace @import("commands.zig");...@@ -26,7 +25,6 @@ usingnamespace @import("commands.zig");
26usingnamespace @import("bind.zig");25usingnamespace @import("bind.zig");
2726
28allocator: *Allocator,27allocator: *Allocator,
29strtab: StringTable,
3028
31target: ?std.Target = null,29target: ?std.Target = null,
32page_size: ?u16 = null,30page_size: ?u16 = null,
...@@ -114,6 +112,9 @@ stub_helper_stubs_start_off: ?u64 = null,...@@ -114,6 +112,9 @@ stub_helper_stubs_start_off: ?u64 = null,
114112
115blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},113blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
116114
115strtab: std.ArrayListUnmanaged(u8) = .{},
116strtab_cache: std.StringHashMapUnmanaged(u32) = .{},
117
117has_dices: bool = false,118has_dices: bool = false,
118has_stabs: bool = false,119has_stabs: bool = false,
119120
...@@ -169,7 +170,7 @@ pub const TextBlock = struct {...@@ -169,7 +170,7 @@ pub const TextBlock = struct {
169 .n_value = reg.address,170 .n_value = reg.address,
170 });171 });
171 nlists.appendAssumeCapacity(.{172 nlists.appendAssumeCapacity(.{
172 .n_strx = try zld.strtab.getOrPut(sym.name),173 .n_strx = try zld.makeString(sym.name),
173 .n_type = macho.N_FUN,174 .n_type = macho.N_FUN,
174 .n_sect = section_id,175 .n_sect = section_id,
175 .n_desc = 0,176 .n_desc = 0,
...@@ -192,7 +193,7 @@ pub const TextBlock = struct {...@@ -192,7 +193,7 @@ pub const TextBlock = struct {
192 },193 },
193 .global => {194 .global => {
194 try nlists.append(.{195 try nlists.append(.{
195 .n_strx = try zld.strtab.getOrPut(sym.name),196 .n_strx = try zld.makeString(sym.name),
196 .n_type = macho.N_GSYM,197 .n_type = macho.N_GSYM,
197 .n_sect = 0,198 .n_sect = 0,
198 .n_desc = 0,199 .n_desc = 0,
...@@ -201,7 +202,7 @@ pub const TextBlock = struct {...@@ -201,7 +202,7 @@ pub const TextBlock = struct {
201 },202 },
202 .static => {203 .static => {
203 try nlists.append(.{204 try nlists.append(.{
204 .n_strx = try zld.strtab.getOrPut(sym.name),205 .n_strx = try zld.makeString(sym.name),
205 .n_type = macho.N_STSYM,206 .n_type = macho.N_STSYM,
206 .n_sect = reg.sectionId(zld),207 .n_sect = reg.sectionId(zld),
207 .n_desc = 0,208 .n_desc = 0,
...@@ -311,10 +312,7 @@ pub const TextBlock = struct {...@@ -311,10 +312,7 @@ pub const TextBlock = struct {
311const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";312const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
312313
313pub fn init(allocator: *Allocator) !Zld {314pub fn init(allocator: *Allocator) !Zld {
314 return Zld{315 return Zld{ .allocator = allocator };
315 .allocator = allocator,
316 .strtab = try StringTable.init(allocator),
317 };
318}316}
319317
320pub fn deinit(self: *Zld) void {318pub fn deinit(self: *Zld) void {
...@@ -357,7 +355,15 @@ pub fn deinit(self: *Zld) void {...@@ -357,7 +355,15 @@ pub fn deinit(self: *Zld) void {
357 self.locals.deinit(self.allocator);355 self.locals.deinit(self.allocator);
358356
359 self.globals.deinit(self.allocator);357 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
362 // TODO dealloc all blocks368 // TODO dealloc all blocks
363 self.blocks.deinit(self.allocator);369 self.blocks.deinit(self.allocator);
...@@ -2572,7 +2578,7 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2572,7 +2578,7 @@ fn writeSymbolTable(self: *Zld) !void {
2572 if (symbol.isTemp()) continue; // TODO when merging codepaths, this should go into freelist2578 if (symbol.isTemp()) continue; // TODO when merging codepaths, this should go into freelist
25732579
2574 const reg = symbol.payload.regular;2580 const reg = symbol.payload.regular;
2575 const nlist = try symbol.asNlist(self, &self.strtab);2581 const nlist = try symbol.asNlist(self);
25762582
2577 if (reg.linkage == .translation_unit) {2583 if (reg.linkage == .translation_unit) {
2578 try locals.append(nlist);2584 try locals.append(nlist);
...@@ -2588,21 +2594,21 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2588,21 +2594,21 @@ fn writeSymbolTable(self: *Zld) !void {
2588 // Open scope2594 // Open scope
2589 try locals.ensureUnusedCapacity(4);2595 try locals.ensureUnusedCapacity(4);
2590 locals.appendAssumeCapacity(.{2596 locals.appendAssumeCapacity(.{
2591 .n_strx = try self.strtab.getOrPut(object.tu_comp_dir.?),2597 .n_strx = try self.makeString(object.tu_comp_dir.?),
2592 .n_type = macho.N_SO,2598 .n_type = macho.N_SO,
2593 .n_sect = 0,2599 .n_sect = 0,
2594 .n_desc = 0,2600 .n_desc = 0,
2595 .n_value = 0,2601 .n_value = 0,
2596 });2602 });
2597 locals.appendAssumeCapacity(.{2603 locals.appendAssumeCapacity(.{
2598 .n_strx = try self.strtab.getOrPut(object.tu_name.?),2604 .n_strx = try self.makeString(object.tu_name.?),
2599 .n_type = macho.N_SO,2605 .n_type = macho.N_SO,
2600 .n_sect = 0,2606 .n_sect = 0,
2601 .n_desc = 0,2607 .n_desc = 0,
2602 .n_value = 0,2608 .n_value = 0,
2603 });2609 });
2604 locals.appendAssumeCapacity(.{2610 locals.appendAssumeCapacity(.{
2605 .n_strx = try self.strtab.getOrPut(object.name.?),2611 .n_strx = try self.makeString(object.name.?),
2606 .n_type = macho.N_OSO,2612 .n_type = macho.N_OSO,
2607 .n_sect = 0,2613 .n_sect = 0,
2608 .n_desc = 1,2614 .n_desc = 1,
...@@ -2642,7 +2648,7 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2642,7 +2648,7 @@ fn writeSymbolTable(self: *Zld) !void {
2642 defer undef_dir.deinit();2648 defer undef_dir.deinit();
26432649
2644 for (self.imports.items) |sym| {2650 for (self.imports.items) |sym| {
2645 const nlist = try sym.asNlist(self, &self.strtab);2651 const nlist = try sym.asNlist(self);
2646 const id = @intCast(u32, undefs.items.len);2652 const id = @intCast(u32, undefs.items.len);
2647 try undefs.append(nlist);2653 try undefs.append(nlist);
2648 try undef_dir.putNoClobber(sym.name, id);2654 try undef_dir.putNoClobber(sym.name, id);
...@@ -2737,14 +2743,14 @@ fn writeStringTable(self: *Zld) !void {...@@ -2737,14 +2743,14 @@ fn writeStringTable(self: *Zld) !void {
2737 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2743 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2738 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2744 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
2739 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);2745 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)));
2741 seg.inner.filesize += symtab.strsize;2747 seg.inner.filesize += symtab.strsize;
27422748
2743 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });2749 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) {
2748 // This is the last section, so we need to pad it out.2754 // This is the last section, so we need to pad it out.
2749 try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);2755 try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
2750 }2756 }
...@@ -2910,3 +2916,27 @@ fn writeHeader(self: *Zld) !void {...@@ -2910,3 +2916,27 @@ fn writeHeader(self: *Zld) !void {
29102916
2911 try self.file.?.pwriteAll(mem.asBytes(&header), 0);2917 try self.file.?.pwriteAll(mem.asBytes(&header), 0);
2912}2918}
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}