authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-18 15:05:52+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-18 15:05:52+02:00
log2828cd2983446b116dc8d543ca5e209e361f39d0
treed4df4ca4a00657490ebde1270e5a0fe74193c0bf
parent5aa9c0b4ab8ca00b0da3ce695924218984d11f11

zld: migrate symbol mgmt to incremental backend


4 files changed, 222 insertions(+), 256 deletions(-)

src/codegen.zig+15-8
...@@ -2500,7 +2500,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2500,7 +2500,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2500 const got_addr = blk: {2500 const got_addr = blk: {
2501 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;2501 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
2502 const got = seg.sections.items[macho_file.got_section_index.?];2502 const got = seg.sections.items[macho_file.got_section_index.?];
2503 break :blk got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);2503 const got_index = macho_file.got_entries_map.get(.{
2504 .where = .local,
2505 .where_index = func.owner_decl.link.macho.local_sym_index,
2506 }) orelse unreachable;
2507 break :blk got.addr + got_index * @sizeOf(u64);
2504 };2508 };
2505 log.debug("got_addr = 0x{x}", .{got_addr});2509 log.debug("got_addr = 0x{x}", .{got_addr});
2506 switch (arch) {2510 switch (arch) {
...@@ -2521,11 +2525,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2521,11 +2525,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2521 const decl = func_payload.data;2525 const decl = func_payload.data;
2522 const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name});2526 const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name});
2523 defer self.bin_file.allocator.free(decl_name);2527 defer self.bin_file.allocator.free(decl_name);
2524 const already_defined = macho_file.lazy_imports.contains(decl_name);2528 const already_defined = macho_file.symbol_resolver.contains(decl_name);
2525 const symbol: u32 = if (macho_file.lazy_imports.getIndex(decl_name)) |index|2529 const resolv = macho_file.symbol_resolver.get(decl_name) orelse blk: {
2526 @intCast(u32, index)2530 break :blk try macho_file.addExternFn(decl_name);
2527 else2531 };
2528 try macho_file.addExternSymbol(decl_name);
2529 const start = self.code.items.len;2532 const start = self.code.items.len;
2530 const len: usize = blk: {2533 const len: usize = blk: {
2531 switch (arch) {2534 switch (arch) {
...@@ -2544,7 +2547,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2544,7 +2547,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2544 }2547 }
2545 };2548 };
2546 try macho_file.stub_fixups.append(self.bin_file.allocator, .{2549 try macho_file.stub_fixups.append(self.bin_file.allocator, .{
2547 .symbol = symbol,2550 .symbol = resolv.where_index,
2548 .already_defined = already_defined,2551 .already_defined = already_defined,
2549 .start = start,2552 .start = start,
2550 .len = len,2553 .len = len,
...@@ -4351,7 +4354,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4351,7 +4354,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4351 const got_addr = blk: {4354 const got_addr = blk: {
4352 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;4355 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
4353 const got = seg.sections.items[macho_file.got_section_index.?];4356 const got = seg.sections.items[macho_file.got_section_index.?];
4354 break :blk got.addr + decl.link.macho.offset_table_index * ptr_bytes;4357 const got_index = macho_file.got_entries_map.get(.{
4358 .where = .local,
4359 .where_index = decl.link.macho.local_sym_index,
4360 }) orelse unreachable;
4361 break :blk got.addr + got_index * ptr_bytes;
4355 };4362 };
4356 return MCValue{ .memory = got_addr };4363 return MCValue{ .memory = got_addr };
4357 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {4364 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
src/link/MachO.zig+205-226
...@@ -100,31 +100,29 @@ data_section_index: ?u16 = null,...@@ -100,31 +100,29 @@ data_section_index: ?u16 = null,
100/// The absolute address of the entry point.100/// The absolute address of the entry point.
101entry_addr: ?u64 = null,101entry_addr: ?u64 = null,
102102
103/// Table of all local symbols
104/// Internally references string table for names (which are optional).
105locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},103locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
106/// Table of all global symbols
107globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},104globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
108/// Table of all extern nonlazy symbols, indexed by name.105imports: std.ArrayListUnmanaged(macho.nlist_64) = .{},
109nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},106symbol_resolver: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
110/// Table of all extern lazy symbols, indexed by name.
111lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
112107
113locals_free_list: std.ArrayListUnmanaged(u32) = .{},108locals_free_list: std.ArrayListUnmanaged(u32) = .{},
114globals_free_list: std.ArrayListUnmanaged(u32) = .{},109globals_free_list: std.ArrayListUnmanaged(u32) = .{},
115offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
116110
117stub_helper_stubs_start_off: ?u64 = null,111stub_helper_stubs_start_off: ?u64 = null,
118112
119strtab: std.ArrayListUnmanaged(u8) = .{},113strtab: std.ArrayListUnmanaged(u8) = .{},
120strtab_cache: std.StringHashMapUnmanaged(u32) = .{},
121114
122/// Table of GOT entries.115got_entries: std.ArrayListUnmanaged(GotIndirectionKey) = .{},
123offset_table: std.ArrayListUnmanaged(GOTEntry) = .{},116got_entries_map: std.AutoHashMapUnmanaged(GotIndirectionKey, u32) = .{},
117
118got_entries_free_list: std.ArrayListUnmanaged(u32) = .{},
119
120stubs: std.ArrayListUnmanaged(u32) = .{},
121stubs_map: std.AutoHashMapUnmanaged(u32, u32) = .{},
124122
125error_flags: File.ErrorFlags = File.ErrorFlags{},123error_flags: File.ErrorFlags = File.ErrorFlags{},
126124
127offset_table_count_dirty: bool = false,125got_entries_count_dirty: bool = false,
128load_commands_dirty: bool = false,126load_commands_dirty: bool = false,
129rebase_info_dirty: bool = false,127rebase_info_dirty: bool = false,
130binding_info_dirty: bool = false,128binding_info_dirty: bool = false,
...@@ -170,31 +168,25 @@ pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{},...@@ -170,31 +168,25 @@ pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{},
170/// rather than sitting in the global scope.168/// rather than sitting in the global scope.
171stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{},169stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{},
172170
173pub const GOTEntry = struct {171const SymbolWithLoc = struct {
174 /// GOT entry can either be a local pointer or an extern (nonlazy) import.172 // Table where the symbol can be found.
175 kind: enum {173 where: enum {
176 Local,174 global,
177 Extern,175 import,
176 undef,
177 tentative,
178 },178 },
179179 where_index: u32,
180 /// Id to the macho.nlist_64 from the respective table: either locals or nonlazy imports.180 local_sym_index: u32 = 0,
181 /// TODO I'm more and more inclined to just manage a single, max two symbol tables181 file: u16 = 0,
182 /// rather than 4 as we currently do, but I'll follow up in the future PR.
183 symbol: u32,
184
185 /// Index of this entry in the GOT.
186 index: u32,
187};182};
188183
189pub const Import = struct {184pub const GotIndirectionKey = struct {
190 /// MachO symbol table entry.185 where: enum {
191 symbol: macho.nlist_64,186 local,
192187 import,
193 /// Id of the dynamic library where the specified entries can be found.188 },
194 dylib_ordinal: i64,189 where_index: u32,
195
196 /// Index of this import within the import list.
197 index: u32,
198};190};
199191
200pub const PIEFixup = struct {192pub const PIEFixup = struct {
...@@ -253,9 +245,6 @@ pub const TextBlock = struct {...@@ -253,9 +245,6 @@ pub const TextBlock = struct {
253 /// If this field is 0, it means the codegen size = 0 and there is no symbol or245 /// If this field is 0, it means the codegen size = 0 and there is no symbol or
254 /// offset table entry.246 /// offset table entry.
255 local_sym_index: u32,247 local_sym_index: u32,
256 /// Index into offset table
257 /// This field is undefined for symbols with size = 0.
258 offset_table_index: u32,
259 /// Size of this text block248 /// Size of this text block
260 /// Unlike in Elf, we need to store the size of this symbol as part of249 /// Unlike in Elf, we need to store the size of this symbol as part of
261 /// the TextBlock since macho.nlist_64 lacks this information.250 /// the TextBlock since macho.nlist_64 lacks this information.
...@@ -275,7 +264,6 @@ pub const TextBlock = struct {...@@ -275,7 +264,6 @@ pub const TextBlock = struct {
275264
276 pub const empty = TextBlock{265 pub const empty = TextBlock{
277 .local_sym_index = 0,266 .local_sym_index = 0,
278 .offset_table_index = undefined,
279 .size = 0,267 .size = 0,
280 .prev = null,268 .prev = null,
281 .next = null,269 .next = null,
...@@ -433,7 +421,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -433,7 +421,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
433 }421 }
434 }422 }
435423
436 if (build_options.have_llvm) {424 if (build_options.is_stage1) {
437 return self.linkWithZld(comp);425 return self.linkWithZld(comp);
438 } else {426 } else {
439 switch (self.base.options.effectiveOutputMode()) {427 switch (self.base.options.effectiveOutputMode()) {
...@@ -500,7 +488,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -500,7 +488,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
500 self.error_flags.no_entry_point_found = false;488 self.error_flags.no_entry_point_found = false;
501 }489 }
502490
503 assert(!self.offset_table_count_dirty);491 assert(!self.got_entries_count_dirty);
504 assert(!self.load_commands_dirty);492 assert(!self.load_commands_dirty);
505 assert(!self.rebase_info_dirty);493 assert(!self.rebase_info_dirty);
506 assert(!self.binding_info_dirty);494 assert(!self.binding_info_dirty);
...@@ -971,31 +959,27 @@ pub fn deinit(self: *MachO) void {...@@ -971,31 +959,27 @@ pub fn deinit(self: *MachO) void {
971 if (self.d_sym) |*ds| {959 if (self.d_sym) |*ds| {
972 ds.deinit(self.base.allocator);960 ds.deinit(self.base.allocator);
973 }961 }
974 for (self.lazy_imports.keys()) |*key| {962
975 self.base.allocator.free(key.*);
976 }
977 self.lazy_imports.deinit(self.base.allocator);
978 for (self.nonlazy_imports.keys()) |*key| {
979 self.base.allocator.free(key.*);
980 }
981 self.nonlazy_imports.deinit(self.base.allocator);
982 self.pie_fixups.deinit(self.base.allocator);963 self.pie_fixups.deinit(self.base.allocator);
983 self.stub_fixups.deinit(self.base.allocator);964 self.stub_fixups.deinit(self.base.allocator);
984 self.text_block_free_list.deinit(self.base.allocator);965 self.text_block_free_list.deinit(self.base.allocator);
985 self.offset_table.deinit(self.base.allocator);966 self.got_entries.deinit(self.base.allocator);
986 self.offset_table_free_list.deinit(self.base.allocator);967 self.got_entries_map.deinit(self.base.allocator);
987 {968 self.got_entries_free_list.deinit(self.base.allocator);
988 var it = self.strtab_cache.keyIterator();969 self.stubs.deinit(self.base.allocator);
989 while (it.next()) |key| {970 self.stubs_map.deinit(self.base.allocator);
990 self.base.allocator.free(key.*);
991 }
992 }
993 self.strtab_cache.deinit(self.base.allocator);
994 self.strtab.deinit(self.base.allocator);971 self.strtab.deinit(self.base.allocator);
972 self.imports.deinit(self.base.allocator);
995 self.globals.deinit(self.base.allocator);973 self.globals.deinit(self.base.allocator);
996 self.globals_free_list.deinit(self.base.allocator);974 self.globals_free_list.deinit(self.base.allocator);
997 self.locals.deinit(self.base.allocator);975 self.locals.deinit(self.base.allocator);
998 self.locals_free_list.deinit(self.base.allocator);976 self.locals_free_list.deinit(self.base.allocator);
977
978 for (self.symbol_resolver.keys()) |key| {
979 self.base.allocator.free(key);
980 }
981 self.symbol_resolver.deinit(self.base.allocator);
982
999 for (self.load_commands.items) |*lc| {983 for (self.load_commands.items) |*lc| {
1000 lc.deinit(self.base.allocator);984 lc.deinit(self.base.allocator);
1001 }985 }
...@@ -1086,8 +1070,8 @@ fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alig...@@ -1086,8 +1070,8 @@ fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alig
1086pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {1070pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
1087 if (decl.link.macho.local_sym_index != 0) return;1071 if (decl.link.macho.local_sym_index != 0) return;
10881072
1089 try self.locals.ensureCapacity(self.base.allocator, self.locals.items.len + 1);1073 try self.locals.ensureUnusedCapacity(self.base.allocator, 1);
1090 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);1074 try self.got_entries.ensureUnusedCapacity(self.base.allocator, 1);
10911075
1092 if (self.locals_free_list.popOrNull()) |i| {1076 if (self.locals_free_list.popOrNull()) |i| {
1093 log.debug("reusing symbol index {d} for {s}", .{ i, decl.name });1077 log.debug("reusing symbol index {d} for {s}", .{ i, decl.name });
...@@ -1098,16 +1082,19 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -1098,16 +1082,19 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
1098 _ = self.locals.addOneAssumeCapacity();1082 _ = self.locals.addOneAssumeCapacity();
1099 }1083 }
11001084
1101 if (self.offset_table_free_list.popOrNull()) |i| {1085 const got_index: u32 = blk: {
1102 log.debug("reusing offset table entry index {d} for {s}", .{ i, decl.name });1086 if (self.got_entries_free_list.popOrNull()) |i| {
1103 decl.link.macho.offset_table_index = i;1087 log.debug("reusing GOT entry index {d} for {s}", .{ i, decl.name });
1104 } else {1088 break :blk i;
1105 log.debug("allocating offset table entry index {d} for {s}", .{ self.offset_table.items.len, decl.name });1089 } else {
1106 decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len);1090 const got_index = @intCast(u32, self.got_entries.items.len);
1107 _ = self.offset_table.addOneAssumeCapacity();1091 log.debug("allocating GOT entry index {d} for {s}", .{ got_index, decl.name });
1108 self.offset_table_count_dirty = true;1092 _ = self.got_entries.addOneAssumeCapacity();
1109 self.rebase_info_dirty = true;1093 self.got_entries_count_dirty = true;
1110 }1094 self.rebase_info_dirty = true;
1095 break :blk got_index;
1096 }
1097 };
11111098
1112 self.locals.items[decl.link.macho.local_sym_index] = .{1099 self.locals.items[decl.link.macho.local_sym_index] = .{
1113 .n_strx = 0,1100 .n_strx = 0,
...@@ -1116,11 +1103,12 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -1116,11 +1103,12 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
1116 .n_desc = 0,1103 .n_desc = 0,
1117 .n_value = 0,1104 .n_value = 0,
1118 };1105 };
1119 self.offset_table.items[decl.link.macho.offset_table_index] = .{1106 const got_entry = GotIndirectionKey{
1120 .kind = .Local,1107 .where = .local,
1121 .symbol = decl.link.macho.local_sym_index,1108 .where_index = decl.link.macho.local_sym_index,
1122 .index = decl.link.macho.offset_table_index,
1123 };1109 };
1110 self.got_entries.items[got_index] = got_entry;
1111 try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index);
1124}1112}
11251113
1126pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {1114pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
...@@ -1191,13 +1179,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1191,13 +1179,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1191 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });1179 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });
11921180
1193 if (vaddr != symbol.n_value) {1181 if (vaddr != symbol.n_value) {
1194 log.debug(" (writing new offset table entry)", .{});1182 log.debug(" (writing new GOT entry)", .{});
1195 self.offset_table.items[decl.link.macho.offset_table_index] = .{1183 const got_index = self.got_entries_map.get(.{
1196 .kind = .Local,1184 .where = .local,
1197 .symbol = decl.link.macho.local_sym_index,1185 .where_index = decl.link.macho.local_sym_index,
1198 .index = decl.link.macho.offset_table_index,1186 }) orelse unreachable;
1199 };1187 try self.writeGotEntry(got_index);
1200 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
1201 }1188 }
12021189
1203 symbol.n_value = vaddr;1190 symbol.n_value = vaddr;
...@@ -1235,16 +1222,17 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1235,16 +1222,17 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1235 .n_desc = 0,1222 .n_desc = 0,
1236 .n_value = addr,1223 .n_value = addr,
1237 };1224 };
1238 self.offset_table.items[decl.link.macho.offset_table_index] = .{
1239 .kind = .Local,
1240 .symbol = decl.link.macho.local_sym_index,
1241 .index = decl.link.macho.offset_table_index,
1242 };
12431225
1244 try self.writeLocalSymbol(decl.link.macho.local_sym_index);1226 try self.writeLocalSymbol(decl.link.macho.local_sym_index);
1227
1245 if (self.d_sym) |*ds|1228 if (self.d_sym) |*ds|
1246 try ds.writeLocalSymbol(decl.link.macho.local_sym_index);1229 try ds.writeLocalSymbol(decl.link.macho.local_sym_index);
1247 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);1230
1231 const got_index = self.got_entries_map.get(.{
1232 .where = .local,
1233 .where_index = decl.link.macho.local_sym_index,
1234 }) orelse unreachable;
1235 try self.writeGotEntry(got_index);
1248 }1236 }
12491237
1250 // Calculate displacements to target addr (if any).1238 // Calculate displacements to target addr (if any).
...@@ -1291,7 +1279,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1291,7 +1279,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1291 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;1279 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1292 const stubs = text_segment.sections.items[self.stubs_section_index.?];1280 const stubs = text_segment.sections.items[self.stubs_section_index.?];
1293 for (self.stub_fixups.items) |fixup| {1281 for (self.stub_fixups.items) |fixup| {
1294 const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2;1282 const stubs_index = self.stubs_map.get(fixup.symbol) orelse unreachable;
1283 const stub_addr = stubs.addr + stubs_index * stubs.reserved2;
1295 const text_addr = symbol.n_value + fixup.start;1284 const text_addr = symbol.n_value + fixup.start;
1296 switch (self.base.options.target.cpu.arch) {1285 switch (self.base.options.target.cpu.arch) {
1297 .x86_64 => {1286 .x86_64 => {
...@@ -1309,9 +1298,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1309,9 +1298,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1309 else => unreachable, // unsupported target architecture1298 else => unreachable, // unsupported target architecture
1310 }1299 }
1311 if (!fixup.already_defined) {1300 if (!fixup.already_defined) {
1312 try self.writeStub(fixup.symbol);1301 try self.writeStub(stubs_index);
1313 try self.writeStubInStubHelper(fixup.symbol);1302 try self.writeStubInStubHelper(stubs_index);
1314 try self.writeLazySymbolPointer(fixup.symbol);1303 try self.writeLazySymbolPointer(stubs_index);
13151304
1316 self.rebase_info_dirty = true;1305 self.rebase_info_dirty = true;
1317 self.lazy_binding_info_dirty = true;1306 self.lazy_binding_info_dirty = true;
...@@ -1448,10 +1437,16 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -1448,10 +1437,16 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
1448 self.freeTextBlock(&decl.link.macho);1437 self.freeTextBlock(&decl.link.macho);
1449 if (decl.link.macho.local_sym_index != 0) {1438 if (decl.link.macho.local_sym_index != 0) {
1450 self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};1439 self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};
1451 self.offset_table_free_list.append(self.base.allocator, decl.link.macho.offset_table_index) catch {};
14521440
1453 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;1441 const got_key = GotIndirectionKey{
1442 .where = .local,
1443 .where_index = decl.link.macho.local_sym_index,
1444 };
1445 const got_index = self.got_entries_map.get(got_key) orelse unreachable;
1446 _ = self.got_entries_map.remove(got_key);
1447 self.got_entries_free_list.append(self.base.allocator, got_index) catch {};
14541448
1449 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;
1455 decl.link.macho.local_sym_index = 0;1450 decl.link.macho.local_sym_index = 0;
1456 }1451 }
1457 if (self.d_sym) |*ds| {1452 if (self.d_sym) |*ds| {
...@@ -1506,8 +1501,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1506,8 +1501,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1506 const initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE;1501 const initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE;
15071502
1508 const program_code_size_hint = self.base.options.program_code_size_hint;1503 const program_code_size_hint = self.base.options.program_code_size_hint;
1509 const offset_table_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;1504 const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
1510 const ideal_size = self.header_pad + program_code_size_hint + 3 * offset_table_size_hint;1505 const ideal_size = self.header_pad + program_code_size_hint + 3 * got_size_hint;
1511 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);1506 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
15121507
1513 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });1508 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
...@@ -1934,28 +1929,28 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1934,28 +1929,28 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1934 });1929 });
1935 self.load_commands_dirty = true;1930 self.load_commands_dirty = true;
1936 }1931 }
1937 if (!self.nonlazy_imports.contains("dyld_stub_binder")) {1932 if (!self.symbol_resolver.contains("dyld_stub_binder")) {
1938 const index = @intCast(u32, self.nonlazy_imports.count());1933 const import_sym_index = @intCast(u32, self.imports.items.len);
1939 const name = try self.base.allocator.dupe(u8, "dyld_stub_binder");1934 try self.imports.append(self.base.allocator, .{
1940 const offset = try self.makeString("dyld_stub_binder");1935 .n_strx = try self.makeString("dyld_stub_binder"),
1941 try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{1936 .n_type = macho.N_UNDF | macho.N_EXT,
1942 .symbol = .{1937 .n_sect = 0,
1943 .n_strx = offset,1938 .n_desc = packDylibOrdinal(1),
1944 .n_type = std.macho.N_UNDF | std.macho.N_EXT,1939 .n_value = 0,
1945 .n_sect = 0,
1946 .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER,
1947 .n_value = 0,
1948 },
1949 .dylib_ordinal = 1, // TODO this is currently hardcoded.
1950 .index = index,
1951 });1940 });
1952 const off_index = @intCast(u32, self.offset_table.items.len);1941 const name = try self.base.allocator.dupe(u8, "dyld_stub_binder");
1953 try self.offset_table.append(self.base.allocator, .{1942 try self.symbol_resolver.putNoClobber(self.base.allocator, name, .{
1954 .kind = .Extern,1943 .where = .import,
1955 .symbol = index,1944 .where_index = import_sym_index,
1956 .index = off_index,
1957 });1945 });
1958 try self.writeOffsetTableEntry(off_index);1946 const got_key = GotIndirectionKey{
1947 .where = .import,
1948 .where_index = import_sym_index,
1949 };
1950 const got_index = @intCast(u32, self.got_entries.items.len);
1951 try self.got_entries.append(self.base.allocator, got_key);
1952 try self.got_entries_map.putNoClobber(self.base.allocator, got_key, got_index);
1953 try self.writeGotEntry(got_index);
1959 self.binding_info_dirty = true;1954 self.binding_info_dirty = true;
1960 }1955 }
1961 if (self.stub_helper_stubs_start_off == null) {1956 if (self.stub_helper_stubs_start_off == null) {
...@@ -2068,24 +2063,25 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,...@@ -2068,24 +2063,25 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
2068 return vaddr;2063 return vaddr;
2069}2064}
20702065
2071pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {2066pub fn addExternFn(self: *MachO, name: []const u8) !SymbolWithLoc {
2072 const index = @intCast(u32, self.lazy_imports.count());2067 log.debug("adding new extern function '{s}' with dylib ordinal 1", .{name});
2073 const offset = try self.makeString(name);2068 const import_sym_index = @intCast(u32, self.imports.items.len);
2074 const sym_name = try self.base.allocator.dupe(u8, name);2069 try self.imports.append(self.base.allocator, .{
2075 const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem.2070 .n_strx = try self.makeString(name),
2076 try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{2071 .n_type = macho.N_UNDF | macho.N_EXT,
2077 .symbol = .{2072 .n_sect = 0,
2078 .n_strx = offset,2073 .n_desc = packDylibOrdinal(1),
2079 .n_type = macho.N_UNDF | macho.N_EXT,2074 .n_value = 0,
2080 .n_sect = 0,
2081 .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,
2082 .n_value = 0,
2083 },
2084 .dylib_ordinal = dylib_ordinal,
2085 .index = index,
2086 });2075 });
2087 log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal });2076 const resolv = .{
2088 return index;2077 .where = .import,
2078 .where_index = import_sym_index,
2079 };
2080 try self.symbol_resolver.putNoClobber(self.base.allocator, try self.base.allocator.dupe(u8, name), resolv);
2081 const stubs_index = @intCast(u32, self.stubs.items.len);
2082 try self.stubs.append(self.base.allocator, import_sym_index);
2083 try self.stubs_map.putNoClobber(self.base.allocator, import_sym_index, stubs_index);
2084 return resolv;
2089}2085}
20902086
2091const NextSegmentAddressAndOffset = struct {2087const NextSegmentAddressAndOffset = struct {
...@@ -2239,29 +2235,26 @@ fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, sta...@@ -2239,29 +2235,26 @@ fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, sta
2239 return st;2235 return st;
2240}2236}
22412237
2242fn writeOffsetTableEntry(self: *MachO, index: usize) !void {2238fn writeGotEntry(self: *MachO, index: usize) !void {
2243 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;2239 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2244 const sect = &seg.sections.items[self.got_section_index.?];2240 const sect = &seg.sections.items[self.got_section_index.?];
2245 const off = sect.offset + @sizeOf(u64) * index;2241 const off = sect.offset + @sizeOf(u64) * index;
22462242
2247 if (self.offset_table_count_dirty) {2243 if (self.got_entries_count_dirty) {
2248 // TODO relocate.2244 // TODO relocate.
2249 self.offset_table_count_dirty = false;2245 self.got_entries_count_dirty = false;
2250 }2246 }
22512247
2252 const got_entry = self.offset_table.items[index];2248 const got_entry = self.got_entries.items[index];
2253 const sym = blk: {2249 const sym = switch (got_entry.where) {
2254 switch (got_entry.kind) {2250 .local => self.locals.items[got_entry.where_index],
2255 .Local => {2251 .import => self.imports.items[got_entry.where_index],
2256 break :blk self.locals.items[got_entry.symbol];
2257 },
2258 .Extern => {
2259 break :blk self.nonlazy_imports.values()[got_entry.symbol].symbol;
2260 },
2261 }
2262 };2252 };
2263 const sym_name = self.getString(sym.n_strx) orelse unreachable;2253 log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{
2264 log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{ off, sym.n_value, sym_name });2254 off,
2255 sym.n_value,
2256 self.getString(sym.n_strx),
2257 });
2265 try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off);2258 try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off);
2266}2259}
22672260
...@@ -2539,7 +2532,7 @@ fn relocateSymbolTable(self: *MachO) !void {...@@ -2539,7 +2532,7 @@ fn relocateSymbolTable(self: *MachO) !void {
2539 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2532 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
2540 const nlocals = self.locals.items.len;2533 const nlocals = self.locals.items.len;
2541 const nglobals = self.globals.items.len;2534 const nglobals = self.globals.items.len;
2542 const nundefs = self.lazy_imports.count() + self.nonlazy_imports.count();2535 const nundefs = self.imports.items.len;
2543 const nsyms = nlocals + nglobals + nundefs;2536 const nsyms = nlocals + nglobals + nundefs;
25442537
2545 if (symtab.nsyms < nsyms) {2538 if (symtab.nsyms < nsyms) {
...@@ -2584,17 +2577,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {...@@ -2584,17 +2577,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
2584 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2577 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
2585 const nlocals = self.locals.items.len;2578 const nlocals = self.locals.items.len;
2586 const nglobals = self.globals.items.len;2579 const nglobals = self.globals.items.len;
25872580 const nundefs = self.imports.items.len;
2588 const nundefs = self.lazy_imports.count() + self.nonlazy_imports.count();
2589 var undefs = std.ArrayList(macho.nlist_64).init(self.base.allocator);
2590 defer undefs.deinit();
2591 try undefs.ensureCapacity(nundefs);
2592 for (self.lazy_imports.values()) |*value| {
2593 undefs.appendAssumeCapacity(value.symbol);
2594 }
2595 for (self.nonlazy_imports.values()) |*value| {
2596 undefs.appendAssumeCapacity(value.symbol);
2597 }
25982581
2599 const locals_off = symtab.symoff;2582 const locals_off = symtab.symoff;
2600 const locals_size = nlocals * @sizeOf(macho.nlist_64);2583 const locals_size = nlocals * @sizeOf(macho.nlist_64);
...@@ -2607,7 +2590,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {...@@ -2607,7 +2590,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
2607 const undefs_off = globals_off + globals_size;2590 const undefs_off = globals_off + globals_size;
2608 const undefs_size = nundefs * @sizeOf(macho.nlist_64);2591 const undefs_size = nundefs * @sizeOf(macho.nlist_64);
2609 log.debug("writing extern symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off });2592 log.debug("writing extern symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off });
2610 try self.base.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off);2593 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.imports.items), undefs_off);
26112594
2612 // Update dynamic symbol table.2595 // Update dynamic symbol table.
2613 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;2596 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
...@@ -2633,10 +2616,10 @@ fn writeIndirectSymbolTable(self: *MachO) !void {...@@ -2633,10 +2616,10 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
2633 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];2616 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
2634 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;2617 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
26352618
2636 const lazy_count = self.lazy_imports.count();2619 const nstubs = @intCast(u32, self.stubs.items.len);
2637 const got_entries = self.offset_table.items;2620 const ngot_entries = @intCast(u32, self.got_entries.items.len);
2638 const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff);2621 const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff);
2639 const nindirectsyms = @intCast(u32, lazy_count * 2 + got_entries.len);2622 const nindirectsyms = nstubs * 2 + ngot_entries;
2640 const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32));2623 const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32));
26412624
2642 if (needed_size > allocated_size) {2625 if (needed_size > allocated_size) {
...@@ -2655,35 +2638,25 @@ fn writeIndirectSymbolTable(self: *MachO) !void {...@@ -2655,35 +2638,25 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
2655 var writer = stream.writer();2638 var writer = stream.writer();
26562639
2657 stubs.reserved1 = 0;2640 stubs.reserved1 = 0;
2658 {2641 for (self.stubs.items) |id| {
2659 var i: usize = 0;2642 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
2660 while (i < lazy_count) : (i += 1) {
2661 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
2662 try writer.writeIntLittle(u32, symtab_idx);
2663 }
2664 }2643 }
26652644
2666 const base_id = @intCast(u32, lazy_count);2645 got.reserved1 = nstubs;
2667 got.reserved1 = base_id;2646 for (self.got_entries.items) |entry| {
2668 for (got_entries) |entry| {2647 switch (entry.where) {
2669 switch (entry.kind) {2648 .import => {
2670 .Local => {2649 try writer.writeIntLittle(u32, dysymtab.iundefsym + entry.where_index);
2671 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
2672 },2650 },
2673 .Extern => {2651 .local => {
2674 const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.index + base_id);2652 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
2675 try writer.writeIntLittle(u32, symtab_idx);
2676 },2653 },
2677 }2654 }
2678 }2655 }
26792656
2680 la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, got_entries.len);2657 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
2681 {2658 for (self.stubs.items) |id| {
2682 var i: usize = 0;2659 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
2683 while (i < lazy_count) : (i += 1) {
2684 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
2685 try writer.writeIntLittle(u32, symtab_idx);
2686 }
2687 }2660 }
26882661
2689 try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);2662 try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
...@@ -2756,13 +2729,18 @@ fn writeExportTrie(self: *MachO) !void {...@@ -2756,13 +2729,18 @@ fn writeExportTrie(self: *MachO) !void {
2756 defer trie.deinit();2729 defer trie.deinit();
27572730
2758 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;2731 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2759 for (self.globals.items) |symbol| {2732 const base_address = text_segment.inner.vmaddr;
2760 // TODO figure out if we should put all global symbols into the export trie2733
2761 const name = self.getString(symbol.n_strx) orelse unreachable;2734 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
2762 assert(symbol.n_value >= text_segment.inner.vmaddr);2735 log.debug("writing export trie", .{});
2736
2737 for (self.globals.items) |sym| {
2738 const sym_name = self.getString(sym.n_strx);
2739 log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, sym.n_value });
2740
2763 try trie.put(.{2741 try trie.put(.{
2764 .name = name,2742 .name = sym_name,
2765 .vmaddr_offset = symbol.n_value - text_segment.inner.vmaddr,2743 .vmaddr_offset = sym.n_value - base_address,
2766 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,2744 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
2767 });2745 });
2768 }2746 }
...@@ -2804,27 +2782,28 @@ fn writeRebaseInfoTable(self: *MachO) !void {...@@ -2804,27 +2782,28 @@ fn writeRebaseInfoTable(self: *MachO) !void {
2804 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;2782 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2805 const sect = seg.sections.items[idx];2783 const sect = seg.sections.items[idx];
2806 const base_offset = sect.addr - seg.inner.vmaddr;2784 const base_offset = sect.addr - seg.inner.vmaddr;
2807 const segment_id = self.data_const_segment_cmd_index.?;2785 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
2786
2787 for (self.got_entries.items) |entry, i| {
2788 if (entry.where == .import) continue;
28082789
2809 for (self.offset_table.items) |entry| {
2810 if (entry.kind == .Extern) continue;
2811 try pointers.append(.{2790 try pointers.append(.{
2812 .offset = base_offset + entry.index * @sizeOf(u64),2791 .offset = base_offset + i * @sizeOf(u64),
2813 .segment_id = segment_id,2792 .segment_id = segment_id,
2814 });2793 });
2815 }2794 }
2816 }2795 }
28172796
2818 if (self.la_symbol_ptr_section_index) |idx| {2797 if (self.la_symbol_ptr_section_index) |idx| {
2819 try pointers.ensureCapacity(pointers.items.len + self.lazy_imports.count());
2820 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;2798 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2821 const sect = seg.sections.items[idx];2799 const sect = seg.sections.items[idx];
2822 const base_offset = sect.addr - seg.inner.vmaddr;2800 const base_offset = sect.addr - seg.inner.vmaddr;
2823 const segment_id = self.data_segment_cmd_index.?;2801 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
28242802
2825 for (self.lazy_imports.values()) |*value| {2803 try pointers.ensureUnusedCapacity(self.stubs.items.len);
2804 for (self.stubs.items) |_, i| {
2826 pointers.appendAssumeCapacity(.{2805 pointers.appendAssumeCapacity(.{
2827 .offset = base_offset + value.index * @sizeOf(u64),2806 .offset = base_offset + i * @sizeOf(u64),
2828 .segment_id = segment_id,2807 .segment_id = segment_id,
2829 });2808 });
2830 }2809 }
...@@ -2872,15 +2851,15 @@ fn writeBindingInfoTable(self: *MachO) !void {...@@ -2872,15 +2851,15 @@ fn writeBindingInfoTable(self: *MachO) !void {
2872 const base_offset = sect.addr - seg.inner.vmaddr;2851 const base_offset = sect.addr - seg.inner.vmaddr;
2873 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);2852 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
28742853
2875 for (self.offset_table.items) |entry| {2854 for (self.got_entries.items) |entry, i| {
2876 if (entry.kind == .Local) continue;2855 if (entry.where == .local) continue;
2877 const import_key = self.nonlazy_imports.keys()[entry.symbol];2856
2878 const import_ordinal = self.nonlazy_imports.values()[entry.symbol].dylib_ordinal;2857 const sym = self.imports.items[entry.where_index];
2879 try pointers.append(.{2858 try pointers.append(.{
2880 .offset = base_offset + entry.index * @sizeOf(u64),2859 .offset = base_offset + i * @sizeOf(u64),
2881 .segment_id = segment_id,2860 .segment_id = segment_id,
2882 .dylib_ordinal = import_ordinal,2861 .dylib_ordinal = unpackDylibOrdinal(sym.n_desc),
2883 .name = import_key,2862 .name = self.getString(sym.n_strx),
2884 });2863 });
2885 }2864 }
2886 }2865 }
...@@ -2920,21 +2899,20 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {...@@ -2920,21 +2899,20 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
2920 defer pointers.deinit();2899 defer pointers.deinit();
29212900
2922 if (self.la_symbol_ptr_section_index) |idx| {2901 if (self.la_symbol_ptr_section_index) |idx| {
2923 try pointers.ensureCapacity(self.lazy_imports.count());
2924 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;2902 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2925 const sect = seg.sections.items[idx];2903 const sect = seg.sections.items[idx];
2926 const base_offset = sect.addr - seg.inner.vmaddr;2904 const base_offset = sect.addr - seg.inner.vmaddr;
2927 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);2905 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
29282906
2929 const slice = self.lazy_imports.entries.slice();2907 try pointers.ensureUnusedCapacity(self.stubs.items.len);
2930 const keys = slice.items(.key);2908
2931 const values = slice.items(.value);2909 for (self.stubs.items) |import_id, i| {
2932 for (keys) |*key, i| {2910 const sym = self.imports.items[import_id];
2933 pointers.appendAssumeCapacity(.{2911 pointers.appendAssumeCapacity(.{
2934 .offset = base_offset + values[i].index * @sizeOf(u64),2912 .offset = base_offset + i * @sizeOf(u64),
2935 .segment_id = segment_id,2913 .segment_id = segment_id,
2936 .dylib_ordinal = values[i].dylib_ordinal,2914 .dylib_ordinal = unpackDylibOrdinal(sym.n_desc),
2937 .name = key.*,2915 .name = self.getString(sym.n_strx),
2938 });2916 });
2939 }2917 }
2940 }2918 }
...@@ -2966,7 +2944,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {...@@ -2966,7 +2944,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
2966}2944}
29672945
2968fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {2946fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
2969 if (self.lazy_imports.count() == 0) return;2947 if (self.stubs.items.len == 0) return;
29702948
2971 var stream = std.io.fixedBufferStream(buffer);2949 var stream = std.io.fixedBufferStream(buffer);
2972 var reader = stream.reader();2950 var reader = stream.reader();
...@@ -3011,7 +2989,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -3011,7 +2989,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
3011 else => {},2989 else => {},
3012 }2990 }
3013 }2991 }
3014 assert(self.lazy_imports.count() <= offsets.items.len);2992 assert(self.stubs.items.len <= offsets.items.len);
30152993
3016 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {2994 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
3017 .x86_64 => 10,2995 .x86_64 => 10,
...@@ -3024,9 +3002,9 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -3024,9 +3002,9 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
3024 else => unreachable,3002 else => unreachable,
3025 };3003 };
3026 var buf: [@sizeOf(u32)]u8 = undefined;3004 var buf: [@sizeOf(u32)]u8 = undefined;
3027 for (offsets.items[0..self.lazy_imports.count()]) |offset, i| {3005 for (self.stubs.items) |_, index| {
3028 const placeholder_off = self.stub_helper_stubs_start_off.? + i * stub_size + off;3006 const placeholder_off = self.stub_helper_stubs_start_off.? + index * stub_size + off;
3029 mem.writeIntLittle(u32, &buf, offset);3007 mem.writeIntLittle(u32, &buf, offsets.items[index]);
3030 try self.base.file.?.pwriteAll(&buf, placeholder_off);3008 try self.base.file.?.pwriteAll(&buf, placeholder_off);
3031 }3009 }
3032}3010}
...@@ -3182,11 +3160,6 @@ fn hasTlvDescriptors(_: *MachO) bool {...@@ -3182,11 +3160,6 @@ fn hasTlvDescriptors(_: *MachO) bool {
3182}3160}
31833161
3184pub fn makeString(self: *MachO, string: []const u8) !u32 {3162pub 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);3163 try self.strtab.ensureUnusedCapacity(self.base.allocator, string.len + 1);
3191 const new_off = @intCast(u32, self.strtab.items.len);3164 const new_off = @intCast(u32, self.strtab.items.len);
31923165
...@@ -3195,12 +3168,18 @@ pub fn makeString(self: *MachO, string: []const u8) !u32 {...@@ -3195,12 +3168,18 @@ pub fn makeString(self: *MachO, string: []const u8) !u32 {
3195 self.strtab.appendSliceAssumeCapacity(string);3168 self.strtab.appendSliceAssumeCapacity(string);
3196 self.strtab.appendAssumeCapacity(0);3169 self.strtab.appendAssumeCapacity(0);
31973170
3198 try self.strtab_cache.putNoClobber(self.base.allocator, try self.base.allocator.dupe(u8, string), new_off);
3199
3200 return new_off;3171 return new_off;
3201}3172}
32023173
3203pub fn getString(self: *MachO, off: u32) ?[]const u8 {3174pub fn getString(self: *MachO, off: u32) []const u8 {
3204 assert(off < self.strtab.items.len);3175 assert(off < self.strtab.items.len);
3205 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off));3176 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off));
3206}3177}
3178
3179fn packDylibOrdinal(ordinal: u16) u16 {
3180 return ordinal * macho.N_SYMBOL_RESOLVER;
3181}
3182
3183fn unpackDylibOrdinal(pack: u16) u16 {
3184 return @divExact(pack, macho.N_SYMBOL_RESOLVER);
3185}
src/link/MachO/TextBlock.zig-4
...@@ -1059,10 +1059,6 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {...@@ -1059,10 +1059,6 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
1059 break :blk sym.n_value;1059 break :blk sym.n_value;
1060 },1060 },
1061 .import => {1061 .import => {
1062 // TODO I think this will be autohandled by self.bindings.
1063 // if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) {
1064 // break :blk 0; // Dynamically bound by dyld.
1065 // }
1066 const stubs_index = zld.stubs.getIndex(rel.where_index) orelse {1062 const stubs_index = zld.stubs.getIndex(rel.where_index) orelse {
1067 // TODO verify in TextBlock that the symbol is indeed dynamically bound.1063 // TODO verify in TextBlock that the symbol is indeed dynamically bound.
1068 break :blk 0; // Dynamically bound by dyld.1064 break :blk 0; // Dynamically bound by dyld.
src/link/MachO/Zld.zig+2-18
...@@ -2367,7 +2367,7 @@ fn writeRebaseInfoTable(self: *Zld) !void {...@@ -2367,7 +2367,7 @@ fn writeRebaseInfoTable(self: *Zld) !void {
2367 const base_offset = sect.addr - seg.inner.vmaddr;2367 const base_offset = sect.addr - seg.inner.vmaddr;
2368 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);2368 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
23692369
2370 try pointers.ensureCapacity(pointers.items.len + self.stubs.count());2370 try pointers.ensureUnusedCapacity(self.stubs.count());
2371 for (self.stubs.keys()) |_, i| {2371 for (self.stubs.keys()) |_, i| {
2372 pointers.appendAssumeCapacity(.{2372 pointers.appendAssumeCapacity(.{
2373 .offset = base_offset + i * @sizeOf(u64),2373 .offset = base_offset + i * @sizeOf(u64),
...@@ -2450,22 +2450,6 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2450,22 +2450,6 @@ fn writeBindInfoTable(self: *Zld) !void {
2450 }2450 }
2451 }2451 }
24522452
2453 // if (self.tlv_section_index) |idx| {
2454 // const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2455 // const sect = seg.sections.items[idx];
2456 // const base_offset = sect.addr - seg.inner.vmaddr;
2457 // const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
2458
2459 // const sym = self.globals.get("__tlv_bootstrap") orelse unreachable;
2460 // const proxy = sym.payload.proxy;
2461 // try pointers.append(.{
2462 // .offset = base_offset,
2463 // .segment_id = segment_id,
2464 // .dylib_ordinal = proxy.dylibOrdinal(),
2465 // .name = self.getString(sym.strx),
2466 // });
2467 // }
2468
2469 const size = try bindInfoSize(pointers.items);2453 const size = try bindInfoSize(pointers.items);
2470 var buffer = try self.allocator.alloc(u8, @intCast(usize, size));2454 var buffer = try self.allocator.alloc(u8, @intCast(usize, size));
2471 defer self.allocator.free(buffer);2455 defer self.allocator.free(buffer);
...@@ -2494,7 +2478,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void {...@@ -2494,7 +2478,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void {
2494 const base_offset = sect.addr - seg.inner.vmaddr;2478 const base_offset = sect.addr - seg.inner.vmaddr;
2495 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);2479 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
24962480
2497 try pointers.ensureCapacity(self.stubs.count());2481 try pointers.ensureUnusedCapacity(self.stubs.count());
24982482
2499 for (self.stubs.keys()) |key, i| {2483 for (self.stubs.keys()) |key, i| {
2500 const sym = self.imports.items[key];2484 const sym = self.imports.items[key];