| ... | @@ -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. |
| 101 | entry_addr: ?u64 = null, | 101 | entry_addr: ?u64 = null, |
| 102 | | 102 | |
| 103 | /// Table of all local symbols | | |
| 104 | /// Internally references string table for names (which are optional). | | |
| 105 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 103 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 106 | /// Table of all global symbols | | |
| 107 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 104 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 108 | /// Table of all extern nonlazy symbols, indexed by name. | 105 | imports: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 109 | nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, | 106 | symbol_resolver: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, |
| 110 | /// Table of all extern lazy symbols, indexed by name. | | |
| 111 | lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, | | |
| 112 | | 107 | |
| 113 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 108 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 114 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 109 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 115 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, | | |
| 116 | | 110 | |
| 117 | stub_helper_stubs_start_off: ?u64 = null, | 111 | stub_helper_stubs_start_off: ?u64 = null, |
| 118 | | 112 | |
| 119 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 113 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 120 | strtab_cache: std.StringHashMapUnmanaged(u32) = .{}, | | |
| 121 | | 114 | |
| 122 | /// Table of GOT entries. | 115 | got_entries: std.ArrayListUnmanaged(GotIndirectionKey) = .{}, |
| 123 | offset_table: std.ArrayListUnmanaged(GOTEntry) = .{}, | 116 | got_entries_map: std.AutoHashMapUnmanaged(GotIndirectionKey, u32) = .{}, |
| | 117 | |
| | 118 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| | 119 | |
| | 120 | stubs: std.ArrayListUnmanaged(u32) = .{}, |
| | 121 | stubs_map: std.AutoHashMapUnmanaged(u32, u32) = .{}, |
| 124 | | 122 | |
| 125 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 123 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 126 | | 124 | |
| 127 | offset_table_count_dirty: bool = false, | 125 | got_entries_count_dirty: bool = false, |
| 128 | load_commands_dirty: bool = false, | 126 | load_commands_dirty: bool = false, |
| 129 | rebase_info_dirty: bool = false, | 127 | rebase_info_dirty: bool = false, |
| 130 | binding_info_dirty: bool = false, | 128 | binding_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. |
| 171 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, | 169 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, |
| 172 | | 170 | |
| 173 | pub const GOTEntry = struct { | 171 | const 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 | }, |
| 179 | | 179 | 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 tables | 181 | 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 | }; |
| 188 | | 183 | |
| 189 | pub const Import = struct { | 184 | pub const GotIndirectionKey = struct { |
| 190 | /// MachO symbol table entry. | 185 | where: enum { |
| 191 | symbol: macho.nlist_64, | 186 | local, |
| 192 | | 187 | 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 | }; |
| 199 | | 191 | |
| 200 | pub const PIEFixup = struct { | 192 | pub 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 or | 245 | /// 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 block | 248 | /// Size of this text block |
| 260 | /// Unlike in Elf, we need to store the size of this symbol as part of | 249 | /// 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 { |
| 275 | | 264 | |
| 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 | } |
| 435 | | 423 | |
| 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 | } |
| 502 | | 490 | |
| 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 |
| 1086 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | 1070 | pub 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; |
| 1088 | | 1072 | |
| 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); |
| 1091 | | 1075 | |
| 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 | } |
| 1100 | | 1084 | |
| 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 | }; |
| 1111 | | 1098 | |
| 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 | } |
| 1125 | | 1113 | |
| 1126 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | 1114 | 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,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 }); |
| 1192 | | 1180 | |
| 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 | } |
| 1202 | | 1189 | |
| 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 | }; | | |
| 1243 | | 1225 | |
| 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 | } |
| 1249 | | 1237 | |
| 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 architecture | 1298 | 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); |
| 1315 | | 1304 | |
| 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 {}; | | |
| 1452 | | 1440 | |
| 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 {}; |
| 1454 | | 1448 | |
| | 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; |
| 1507 | | 1502 | |
| 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); |
| 1512 | | 1507 | |
| 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 | } |
| 2070 | | 2065 | |
| 2071 | pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { | 2066 | pub 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 | } |
| 2090 | | 2086 | |
| 2091 | const NextSegmentAddressAndOffset = struct { | 2087 | const 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 | } |
| 2241 | | 2237 | |
| 2242 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | 2238 | fn 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; |
| 2246 | | 2242 | |
| 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 | } |
| 2251 | | 2247 | |
| 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 | } |
| 2267 | | 2260 | |
| ... | @@ -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; |
| 2544 | | 2537 | |
| 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; |
| 2587 | | 2580 | 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 | } | | |
| 2598 | | 2581 | |
| 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); |
| 2611 | | 2594 | |
| 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; |
| 2635 | | 2618 | |
| 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)); |
| 2641 | | 2624 | |
| 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(); |
| 2656 | | 2639 | |
| 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 | } |
| 2665 | | 2644 | |
| 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 | } |
| 2679 | | 2656 | |
| 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 | } |
| 2688 | | 2661 | |
| 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(); |
| 2757 | | 2730 | |
| 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 trie | 2733 | |
| 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; |
| 2808 | | 2789 | |
| 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 | } |
| 2817 | | 2796 | |
| 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.?); |
| 2824 | | 2802 | |
| 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.?); |
| 2874 | | 2853 | |
| 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(); |
| 2921 | | 2900 | |
| 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.?); |
| 2928 | | 2906 | |
| 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 | } |
| 2967 | | 2945 | |
| 2968 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { | 2946 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 2969 | if (self.lazy_imports.count() == 0) return; | 2947 | if (self.stubs.items.len == 0) return; |
| 2970 | | 2948 | |
| 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); |
| 3015 | | 2993 | |
| 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 | } |
| 3183 | | 3161 | |
| 3184 | pub fn makeString(self: *MachO, string: []const u8) !u32 { | 3162 | 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); | 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); |
| 3192 | | 3165 | |
| ... | @@ -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); |
| 3197 | | 3170 | |
| 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 | } |
| 3202 | | 3173 | |
| 3203 | pub fn getString(self: *MachO, off: u32) ?[]const u8 { | 3174 | pub 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 | |
| | 3179 | fn packDylibOrdinal(ordinal: u16) u16 { |
| | 3180 | return ordinal * macho.N_SYMBOL_RESOLVER; |
| | 3181 | } |
| | 3182 | |
| | 3183 | fn unpackDylibOrdinal(pack: u16) u16 { |
| | 3184 | return @divExact(pack, macho.N_SYMBOL_RESOLVER); |
| | 3185 | } |