| ... | @@ -81,12 +81,20 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, | ... | @@ -81,12 +81,20 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 81 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, | 81 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 82 | stubs: std.StringArrayHashMapUnmanaged(u32) = .{}, | 82 | stubs: std.StringArrayHashMapUnmanaged(u32) = .{}, |
| 83 | got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, | 83 | got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, |
| | 84 | cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, |
| | 85 | cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, |
| 84 | | 86 | |
| 85 | stub_helper_stubs_start_off: ?u64 = null, | 87 | stub_helper_stubs_start_off: ?u64 = null, |
| 86 | | 88 | |
| 87 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, | 89 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| 88 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, | 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 | const GotEntry = struct { | 98 | const GotEntry = struct { |
| 91 | tag: enum { | 99 | tag: enum { |
| 92 | local, | 100 | local, |
| ... | @@ -134,6 +142,16 @@ pub fn deinit(self: *Zld) void { | ... | @@ -134,6 +142,16 @@ pub fn deinit(self: *Zld) void { |
| 134 | } | 142 | } |
| 135 | self.got_entries.deinit(self.allocator); | 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 | for (self.load_commands.items) |*lc| { | 155 | for (self.load_commands.items) |*lc| { |
| 138 | lc.deinit(self.allocator); | 156 | lc.deinit(self.allocator); |
| 139 | } | 157 | } |
| ... | @@ -957,6 +975,38 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { | ... | @@ -957,6 +975,38 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { |
| 957 | entry.value.target_addr, | 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 | fn writeStubHelperCommon(self: *Zld) !void { | 1012 | fn writeStubHelperCommon(self: *Zld) !void { |
| ... | @@ -1257,8 +1307,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { | ... | @@ -1257,8 +1307,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { |
| 1257 | }, | 1307 | }, |
| 1258 | .strong => { | 1308 | .strong => { |
| 1259 | if (!is_weak) { | 1309 | if (!is_weak) { |
| 1260 | log.err("symbol '{s}' defined multiple times", .{sym_name}); | 1310 | log.debug("strong symbol '{s}' defined multiple times", .{sym_name}); |
| 1261 | return error.MultipleSymbolDefinitions; | | |
| 1262 | } | 1311 | } |
| 1263 | continue; | 1312 | continue; |
| 1264 | }, | 1313 | }, |
| ... | @@ -1348,14 +1397,14 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1348,14 +1397,14 @@ fn resolveSymbols(self: *Zld) !void { |
| 1348 | }); | 1397 | }); |
| 1349 | | 1398 | |
| 1350 | { | 1399 | { |
| 1351 | log.warn("symtab", .{}); | 1400 | log.debug("symtab", .{}); |
| 1352 | for (self.symtab.items()) |sym| { | 1401 | for (self.symtab.items()) |sym| { |
| 1353 | switch (sym.value.tag) { | 1402 | switch (sym.value.tag) { |
| 1354 | .weak, .strong => { | 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 | .import => { | 1406 | .import => { |
| 1358 | log.warn(" | {s} => libSystem.B.dylib", .{sym.key}); | 1407 | log.debug(" | {s} => libSystem.B.dylib", .{sym.key}); |
| 1359 | }, | 1408 | }, |
| 1360 | else => unreachable, | 1409 | else => unreachable, |
| 1361 | } | 1410 | } |
| ... | @@ -1371,7 +1420,34 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { | ... | @@ -1371,7 +1420,34 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1371 | const relocs = sect.relocs orelse continue; | 1420 | const relocs = sect.relocs orelse continue; |
| 1372 | for (relocs) |rel| { | 1421 | for (relocs) |rel| { |
| 1373 | switch (rel.@"type") { | 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 | .got_page, .got_page_off, .got_load, .got => { | 1451 | .got_page, .got_page_off, .got_load, .got => { |
| 1376 | const sym = object.symtab.items[rel.target.symbol]; | 1452 | const sym = object.symtab.items[rel.target.symbol]; |
| 1377 | const sym_name = object.getString(sym.n_strx); | 1453 | const sym_name = object.getString(sym.n_strx); |
| ... | @@ -1433,9 +1509,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1433,9 +1509,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1433 | log.debug("relocating object {s}", .{object.name}); | 1509 | log.debug("relocating object {s}", .{object.name}); |
| 1434 | | 1510 | |
| 1435 | for (object.sections.items) |sect, source_sect_id| { | 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 | const segname = parseName(&sect.inner.segname); | 1515 | const segname = parseName(&sect.inner.segname); |
| 1437 | const sectname = parseName(&sect.inner.sectname); | 1516 | const sectname = parseName(&sect.inner.sectname); |
| 1438 | | 1517 | |
| | 1518 | log.debug("relocating section '{s},{s}'", .{ segname, sectname }); |
| | 1519 | |
| 1439 | // Get mapping | 1520 | // Get mapping |
| 1440 | const target_mapping = self.mappings.get(.{ | 1521 | const target_mapping = self.mappings.get(.{ |
| 1441 | .object_id = @intCast(u16, object_id), | 1522 | .object_id = @intCast(u16, object_id), |
| ... | @@ -2061,6 +2142,42 @@ fn flush(self: *Zld) !void { | ... | @@ -2061,6 +2142,42 @@ fn flush(self: *Zld) !void { |
| 2061 | try self.file.?.pwriteAll(buffer, sect.offset); | 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 | try self.writeGotEntries(); | 2181 | try self.writeGotEntries(); |
| 2065 | try self.setEntryPoint(); | 2182 | try self.setEntryPoint(); |
| 2066 | try self.writeRebaseInfoTable(); | 2183 | try self.writeRebaseInfoTable(); |
| ... | @@ -2160,15 +2277,12 @@ fn writeRebaseInfoTable(self: *Zld) !void { | ... | @@ -2160,15 +2277,12 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2160 | // TODO audit and investigate this. | 2277 | // TODO audit and investigate this. |
| 2161 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 2278 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2162 | const sect = seg.sections.items[idx]; | 2279 | const sect = seg.sections.items[idx]; |
| 2163 | const npointers = sect.size * @sizeOf(u64); | | |
| 2164 | const base_offset = sect.addr - seg.inner.vmaddr; | 2280 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2165 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); | 2281 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2166 | | 2282 | |
| 2167 | try pointers.ensureCapacity(pointers.items.len + npointers); | 2283 | for (self.cpp_initializers.items()) |entry| { |
| 2168 | var i: usize = 0; | 2284 | try pointers.append(.{ |
| 2169 | while (i < npointers) : (i += 1) { | 2285 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2170 | pointers.appendAssumeCapacity(.{ | | |
| 2171 | .offset = base_offset + i * @sizeOf(u64), | | |
| 2172 | .segment_id = segment_id, | 2286 | .segment_id = segment_id, |
| 2173 | }); | 2287 | }); |
| 2174 | } | 2288 | } |
| ... | @@ -2178,15 +2292,12 @@ fn writeRebaseInfoTable(self: *Zld) !void { | ... | @@ -2178,15 +2292,12 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2178 | // TODO audit and investigate this. | 2292 | // TODO audit and investigate this. |
| 2179 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 2293 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2180 | const sect = seg.sections.items[idx]; | 2294 | const sect = seg.sections.items[idx]; |
| 2181 | const npointers = sect.size * @sizeOf(u64); | | |
| 2182 | const base_offset = sect.addr - seg.inner.vmaddr; | 2295 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2183 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); | 2296 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2184 | | 2297 | |
| 2185 | try pointers.ensureCapacity(pointers.items.len + npointers); | 2298 | for (self.cpp_finalizers.items()) |entry| { |
| 2186 | var i: usize = 0; | 2299 | try pointers.append(.{ |
| 2187 | while (i < npointers) : (i += 1) { | 2300 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2188 | pointers.appendAssumeCapacity(.{ | | |
| 2189 | .offset = base_offset + i * @sizeOf(u64), | | |
| 2190 | .segment_id = segment_id, | 2301 | .segment_id = segment_id, |
| 2191 | }); | 2302 | }); |
| 2192 | } | 2303 | } |