| ... | ... | @@ -81,12 +81,20 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 81 | 81 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 82 | 82 | stubs: std.StringArrayHashMapUnmanaged(u32) = .{}, |
| 83 | 83 | got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, |
| 84 | cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, |
| 85 | cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, |
| 84 | 86 | |
| 85 | 87 | stub_helper_stubs_start_off: ?u64 = null, |
| 86 | 88 | |
| 87 | 89 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| 88 | 90 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, |
| 89 | 91 | |
| 92 | const CppStatic = struct { |
| 93 | index: u32, |
| 94 | target_addr: u64, |
| 95 | file: u16, |
| 96 | }; |
| 97 | |
| 90 | 98 | const GotEntry = struct { |
| 91 | 99 | tag: enum { |
| 92 | 100 | local, |
| ... | ... | @@ -134,6 +142,16 @@ pub fn deinit(self: *Zld) void { |
| 134 | 142 | } |
| 135 | 143 | self.got_entries.deinit(self.allocator); |
| 136 | 144 | |
| 145 | for (self.cpp_initializers.items()) |entry| { |
| 146 | self.allocator.free(entry.key); |
| 147 | } |
| 148 | self.cpp_initializers.deinit(self.allocator); |
| 149 | |
| 150 | for (self.cpp_finalizers.items()) |entry| { |
| 151 | self.allocator.free(entry.key); |
| 152 | } |
| 153 | self.cpp_finalizers.deinit(self.allocator); |
| 154 | |
| 137 | 155 | for (self.load_commands.items) |*lc| { |
| 138 | 156 | lc.deinit(self.allocator); |
| 139 | 157 | } |
| ... | ... | @@ -957,6 +975,38 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { |
| 957 | 975 | entry.value.target_addr, |
| 958 | 976 | }); |
| 959 | 977 | } |
| 978 | |
| 979 | for (self.cpp_initializers.items()) |*entry| { |
| 980 | const object = self.objects.items[entry.value.file]; |
| 981 | entry.value.target_addr = target_addr: { |
| 982 | if (object.locals.get(entry.key)) |local| { |
| 983 | break :target_addr local.address; |
| 984 | } |
| 985 | const global = self.symtab.get(entry.key) orelse unreachable; |
| 986 | break :target_addr global.address; |
| 987 | }; |
| 988 | |
| 989 | log.debug("resolving C++ initializer '{s}' at 0x{x}", .{ |
| 990 | entry.key, |
| 991 | entry.value.target_addr, |
| 992 | }); |
| 993 | } |
| 994 | |
| 995 | for (self.cpp_finalizers.items()) |*entry| { |
| 996 | const object = self.objects.items[entry.value.file]; |
| 997 | entry.value.target_addr = target_addr: { |
| 998 | if (object.locals.get(entry.key)) |local| { |
| 999 | break :target_addr local.address; |
| 1000 | } |
| 1001 | const global = self.symtab.get(entry.key) orelse unreachable; |
| 1002 | break :target_addr global.address; |
| 1003 | }; |
| 1004 | |
| 1005 | log.debug("resolving C++ finalizer '{s}' at 0x{x}", .{ |
| 1006 | entry.key, |
| 1007 | entry.value.target_addr, |
| 1008 | }); |
| 1009 | } |
| 960 | 1010 | } |
| 961 | 1011 | |
| 962 | 1012 | fn writeStubHelperCommon(self: *Zld) !void { |
| ... | ... | @@ -1257,8 +1307,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { |
| 1257 | 1307 | }, |
| 1258 | 1308 | .strong => { |
| 1259 | 1309 | if (!is_weak) { |
| 1260 | | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 1261 | | return error.MultipleSymbolDefinitions; |
| 1310 | log.debug("strong symbol '{s}' defined multiple times", .{sym_name}); |
| 1262 | 1311 | } |
| 1263 | 1312 | continue; |
| 1264 | 1313 | }, |
| ... | ... | @@ -1348,14 +1397,14 @@ fn resolveSymbols(self: *Zld) !void { |
| 1348 | 1397 | }); |
| 1349 | 1398 | |
| 1350 | 1399 | { |
| 1351 | | log.warn("symtab", .{}); |
| 1400 | log.debug("symtab", .{}); |
| 1352 | 1401 | for (self.symtab.items()) |sym| { |
| 1353 | 1402 | switch (sym.value.tag) { |
| 1354 | 1403 | .weak, .strong => { |
| 1355 | | log.warn(" | {s} => {s}", .{ sym.key, self.objects.items[sym.value.file.?].name.? }); |
| 1404 | log.debug(" | {s} => {s}", .{ sym.key, self.objects.items[sym.value.file.?].name.? }); |
| 1356 | 1405 | }, |
| 1357 | 1406 | .import => { |
| 1358 | | log.warn(" | {s} => libSystem.B.dylib", .{sym.key}); |
| 1407 | log.debug(" | {s} => libSystem.B.dylib", .{sym.key}); |
| 1359 | 1408 | }, |
| 1360 | 1409 | else => unreachable, |
| 1361 | 1410 | } |
| ... | ... | @@ -1371,7 +1420,34 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1371 | 1420 | const relocs = sect.relocs orelse continue; |
| 1372 | 1421 | for (relocs) |rel| { |
| 1373 | 1422 | switch (rel.@"type") { |
| 1374 | | .unsigned => continue, |
| 1423 | .unsigned => { |
| 1424 | if (rel.target != .symbol) continue; |
| 1425 | |
| 1426 | const sym = object.symtab.items[rel.target.symbol]; |
| 1427 | const sym_name = object.getString(sym.n_strx); |
| 1428 | |
| 1429 | if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS) { |
| 1430 | if (self.cpp_initializers.contains(sym_name)) continue; |
| 1431 | |
| 1432 | var name = try self.allocator.dupe(u8, sym_name); |
| 1433 | const index = @intCast(u32, self.cpp_initializers.items().len); |
| 1434 | try self.cpp_initializers.putNoClobber(self.allocator, name, .{ |
| 1435 | .index = index, |
| 1436 | .target_addr = 0, |
| 1437 | .file = @intCast(u16, object_id), |
| 1438 | }); |
| 1439 | } else if (sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) { |
| 1440 | if (self.cpp_finalizers.contains(sym_name)) continue; |
| 1441 | |
| 1442 | var name = try self.allocator.dupe(u8, sym_name); |
| 1443 | const index = @intCast(u32, self.cpp_finalizers.items().len); |
| 1444 | try self.cpp_finalizers.putNoClobber(self.allocator, name, .{ |
| 1445 | .index = index, |
| 1446 | .target_addr = 0, |
| 1447 | .file = @intCast(u16, object_id), |
| 1448 | }); |
| 1449 | } else continue; |
| 1450 | }, |
| 1375 | 1451 | .got_page, .got_page_off, .got_load, .got => { |
| 1376 | 1452 | const sym = object.symtab.items[rel.target.symbol]; |
| 1377 | 1453 | const sym_name = object.getString(sym.n_strx); |
| ... | ... | @@ -1433,9 +1509,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1433 | 1509 | log.debug("relocating object {s}", .{object.name}); |
| 1434 | 1510 | |
| 1435 | 1511 | for (object.sections.items) |sect, source_sect_id| { |
| 1512 | if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or |
| 1513 | sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue; |
| 1514 | |
| 1436 | 1515 | const segname = parseName(&sect.inner.segname); |
| 1437 | 1516 | const sectname = parseName(&sect.inner.sectname); |
| 1438 | 1517 | |
| 1518 | log.debug("relocating section '{s},{s}'", .{ segname, sectname }); |
| 1519 | |
| 1439 | 1520 | // Get mapping |
| 1440 | 1521 | const target_mapping = self.mappings.get(.{ |
| 1441 | 1522 | .object_id = @intCast(u16, object_id), |
| ... | ... | @@ -2061,6 +2142,42 @@ fn flush(self: *Zld) !void { |
| 2061 | 2142 | try self.file.?.pwriteAll(buffer, sect.offset); |
| 2062 | 2143 | } |
| 2063 | 2144 | |
| 2145 | if (self.mod_init_func_section_index) |index| { |
| 2146 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2147 | const sect = &seg.sections.items[index]; |
| 2148 | |
| 2149 | var buffer = try self.allocator.alloc(u8, self.cpp_initializers.items().len * @sizeOf(u64)); |
| 2150 | defer self.allocator.free(buffer); |
| 2151 | |
| 2152 | var stream = std.io.fixedBufferStream(buffer); |
| 2153 | var writer = stream.writer(); |
| 2154 | |
| 2155 | for (self.cpp_initializers.items()) |entry| { |
| 2156 | try writer.writeIntLittle(u64, entry.value.target_addr); |
| 2157 | } |
| 2158 | |
| 2159 | _ = try self.file.?.pwriteAll(buffer, sect.offset); |
| 2160 | sect.size = @intCast(u32, buffer.len); |
| 2161 | } |
| 2162 | |
| 2163 | if (self.mod_term_func_section_index) |index| { |
| 2164 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2165 | const sect = &seg.sections.items[index]; |
| 2166 | |
| 2167 | var buffer = try self.allocator.alloc(u8, self.cpp_finalizers.items().len * @sizeOf(u64)); |
| 2168 | defer self.allocator.free(buffer); |
| 2169 | |
| 2170 | var stream = std.io.fixedBufferStream(buffer); |
| 2171 | var writer = stream.writer(); |
| 2172 | |
| 2173 | for (self.cpp_finalizers.items()) |entry| { |
| 2174 | try writer.writeIntLittle(u64, entry.value.target_addr); |
| 2175 | } |
| 2176 | |
| 2177 | _ = try self.file.?.pwriteAll(buffer, sect.offset); |
| 2178 | sect.size = @intCast(u32, buffer.len); |
| 2179 | } |
| 2180 | |
| 2064 | 2181 | try self.writeGotEntries(); |
| 2065 | 2182 | try self.setEntryPoint(); |
| 2066 | 2183 | try self.writeRebaseInfoTable(); |
| ... | ... | @@ -2160,15 +2277,12 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2160 | 2277 | // TODO audit and investigate this. |
| 2161 | 2278 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2162 | 2279 | const sect = seg.sections.items[idx]; |
| 2163 | | const npointers = sect.size * @sizeOf(u64); |
| 2164 | 2280 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2165 | 2281 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2166 | 2282 | |
| 2167 | | try pointers.ensureCapacity(pointers.items.len + npointers); |
| 2168 | | var i: usize = 0; |
| 2169 | | while (i < npointers) : (i += 1) { |
| 2170 | | pointers.appendAssumeCapacity(.{ |
| 2171 | | .offset = base_offset + i * @sizeOf(u64), |
| 2283 | for (self.cpp_initializers.items()) |entry| { |
| 2284 | try pointers.append(.{ |
| 2285 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2172 | 2286 | .segment_id = segment_id, |
| 2173 | 2287 | }); |
| 2174 | 2288 | } |
| ... | ... | @@ -2178,15 +2292,12 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2178 | 2292 | // TODO audit and investigate this. |
| 2179 | 2293 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2180 | 2294 | const sect = seg.sections.items[idx]; |
| 2181 | | const npointers = sect.size * @sizeOf(u64); |
| 2182 | 2295 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2183 | 2296 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2184 | 2297 | |
| 2185 | | try pointers.ensureCapacity(pointers.items.len + npointers); |
| 2186 | | var i: usize = 0; |
| 2187 | | while (i < npointers) : (i += 1) { |
| 2188 | | pointers.appendAssumeCapacity(.{ |
| 2189 | | .offset = base_offset + i * @sizeOf(u64), |
| 2298 | for (self.cpp_finalizers.items()) |entry| { |
| 2299 | try pointers.append(.{ |
| 2300 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2190 | 2301 | .segment_id = segment_id, |
| 2191 | 2302 | }); |
| 2192 | 2303 | } |