| author | |
| committer | |
| log | 0135b4665988530c0bd6b36ef7cb93ecaf999776 |
| tree | dd9ba7fdc2173ecfa8fc028d24a2e63f62ada94d |
| parent | f87424ab6393c3208d96a4f078c71f745a37c84b |
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"); |
| 26 | const DebugSymbols = @import("MachO/DebugSymbols.zig"); | 26 | const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 27 | const Trie = @import("MachO/Trie.zig"); | 27 | const Trie = @import("MachO/Trie.zig"); |
| 28 | const CodeSignature = @import("MachO/CodeSignature.zig"); | 28 | const CodeSignature = @import("MachO/CodeSignature.zig"); |
| 29 | const StringTable = @import("MachO/StringTable.zig"); | ||
| 30 | const Zld = @import("MachO/Zld.zig"); | 29 | const Zld = @import("MachO/Zld.zig"); |
| 31 | 30 | ||
| 32 | usingnamespace @import("MachO/commands.zig"); | 31 | usingnamespace @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) = .{}, |
| 117 | 116 | ||
| 118 | stub_helper_stubs_start_off: ?u64 = null, | 117 | stub_helper_stubs_start_off: ?u64 = null, |
| 119 | 118 | ||
| 120 | strtab: StringTable = undefined, | 119 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 120 | strtab_cache: std.StringHashMapUnmanaged(u32) = .{}, | ||
| 121 | 121 | ||
| 122 | /// Table of GOT entries. | 122 | /// Table of GOT entries. |
| 123 | offset_table: std.ArrayListUnmanaged(GOTEntry) = .{}, | 123 | offset_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 | }; |
| 423 | 422 | ||
| 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); |
| 1205 | 1211 | ||
| 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); |
| 1217 | 1223 | ||
| 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); |
| 1220 | 1226 | ||
| 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); |
| 1790 | 1796 | ||
| 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, |
| 2063 | 2070 | ||
| 2064 | pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { | 2071 | pub 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 trie | 2760 | // 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 { |
| 3032 | 3039 | ||
| 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)); |
| 3036 | 3043 | ||
| 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 }); |
| 3044 | 3051 | ||
| 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) { |
| 3173 | fn hasTlvDescriptors(_: *MachO) bool { | 3180 | fn hasTlvDescriptors(_: *MachO) bool { |
| 3174 | return false; | 3181 | return false; |
| 3175 | } | 3182 | } |
| 3183 | |||
| 3184 | pub 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 | |||
| 3203 | pub 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 { |
| 814 | 814 | ||
| 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)); |
| 818 | 818 | ||
| 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 }); |
| 825 | 825 | ||
| 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 @@ | ||
| 1 | const StringTable = @This(); | ||
| 2 | |||
| 3 | const std = @import("std"); | ||
| 4 | const log = std.log.scoped(.strtab); | ||
| 5 | const mem = std.mem; | ||
| 6 | |||
| 7 | const Allocator = mem.Allocator; | ||
| 8 | |||
| 9 | allocator: *Allocator, | ||
| 10 | buffer: std.ArrayListUnmanaged(u8) = .{}, | ||
| 11 | cache: std.StringHashMapUnmanaged(u32) = .{}, | ||
| 12 | |||
| 13 | pub const Error = error{OutOfMemory}; | ||
| 14 | |||
| 15 | pub 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 | |||
| 23 | pub 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 | |||
| 34 | pub 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 | |||
| 53 | pub 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 | |||
| 58 | pub fn asSlice(self: StringTable) []const u8 { | ||
| 59 | return self.buffer.items; | ||
| 60 | } | ||
| 61 | |||
| 62 | pub 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; |
| 9 | const Allocator = mem.Allocator; | 9 | const Allocator = mem.Allocator; |
| 10 | const Dylib = @import("Dylib.zig"); | 10 | const Dylib = @import("Dylib.zig"); |
| 11 | const Object = @import("Object.zig"); | 11 | const Object = @import("Object.zig"); |
| 12 | const StringTable = @import("StringTable.zig"); | ||
| 13 | const Zld = @import("Zld.zig"); | 12 | const Zld = @import("Zld.zig"); |
| 14 | 13 | ||
| 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 | } |
| 228 | 227 | ||
| 229 | pub fn asNlist(symbol: *Symbol, zld: *Zld, strtab: *StringTable) !macho.nlist_64 { | 228 | pub 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"); |
| 18 | const Dylib = @import("Dylib.zig"); | 18 | const Dylib = @import("Dylib.zig"); |
| 19 | const Object = @import("Object.zig"); | 19 | const Object = @import("Object.zig"); |
| 20 | const Relocation = reloc.Relocation; | 20 | const Relocation = reloc.Relocation; |
| 21 | const StringTable = @import("StringTable.zig"); | ||
| 22 | const Symbol = @import("Symbol.zig"); | 21 | const Symbol = @import("Symbol.zig"); |
| 23 | const Trie = @import("Trie.zig"); | 22 | const Trie = @import("Trie.zig"); |
| 24 | 23 | ||
| ... | @@ -26,7 +25,6 @@ usingnamespace @import("commands.zig"); | ... | @@ -26,7 +25,6 @@ usingnamespace @import("commands.zig"); |
| 26 | usingnamespace @import("bind.zig"); | 25 | usingnamespace @import("bind.zig"); |
| 27 | 26 | ||
| 28 | allocator: *Allocator, | 27 | allocator: *Allocator, |
| 29 | strtab: StringTable, | ||
| 30 | 28 | ||
| 31 | target: ?std.Target = null, | 29 | target: ?std.Target = null, |
| 32 | page_size: ?u16 = null, | 30 | page_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, |
| 114 | 112 | ||
| 115 | blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{}, | 113 | blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{}, |
| 116 | 114 | ||
| 115 | strtab: std.ArrayListUnmanaged(u8) = .{}, | ||
| 116 | strtab_cache: std.StringHashMapUnmanaged(u32) = .{}, | ||
| 117 | |||
| 117 | has_dices: bool = false, | 118 | has_dices: bool = false, |
| 118 | has_stabs: bool = false, | 119 | has_stabs: bool = false, |
| 119 | 120 | ||
| ... | @@ -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 { |
| 311 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; | 312 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; |
| 312 | 313 | ||
| 313 | pub fn init(allocator: *Allocator) !Zld { | 314 | pub 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 | } |
| 319 | 317 | ||
| 320 | pub fn deinit(self: *Zld) void { | 318 | pub 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); |
| 358 | 356 | ||
| 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); | ||
| 361 | 367 | ||
| 362 | // TODO dealloc all blocks | 368 | // 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 freelist | 2578 | if (symbol.isTemp()) continue; // TODO when merging codepaths, this should go into freelist |
| 2573 | 2579 | ||
| 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); |
| 2576 | 2582 | ||
| 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 scope | 2594 | // 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(); |
| 2643 | 2649 | ||
| 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; |
| 2742 | 2748 | ||
| 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 }); |
| 2744 | 2750 | ||
| 2745 | try self.file.?.pwriteAll(self.strtab.asSlice(), symtab.stroff); | 2751 | try self.file.?.pwriteAll(self.strtab.items, symtab.stroff); |
| 2746 | 2752 | ||
| 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 { |
| 2910 | 2916 | ||
| 2911 | try self.file.?.pwriteAll(mem.asBytes(&header), 0); | 2917 | try self.file.?.pwriteAll(mem.asBytes(&header), 0); |
| 2912 | } | 2918 | } |
| 2919 | |||
| 2920 | pub 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 | |||
| 2939 | pub 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 | } |