| ... | ... | @@ -82,20 +82,12 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 82 | 82 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 83 | 83 | stubs: std.StringArrayHashMapUnmanaged(u32) = .{}, |
| 84 | 84 | got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, |
| 85 | | cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, |
| 86 | | cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, |
| 87 | 85 | |
| 88 | 86 | stub_helper_stubs_start_off: ?u64 = null, |
| 89 | 87 | |
| 90 | 88 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| 91 | 89 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, |
| 92 | 90 | |
| 93 | | pub const CppStatic = struct { |
| 94 | | index: u32, |
| 95 | | target_addr: u64, |
| 96 | | file: u16, |
| 97 | | }; |
| 98 | | |
| 99 | 91 | const GotEntry = struct { |
| 100 | 92 | tag: enum { |
| 101 | 93 | local, |
| ... | ... | @@ -143,16 +135,6 @@ pub fn deinit(self: *Zld) void { |
| 143 | 135 | } |
| 144 | 136 | self.got_entries.deinit(self.allocator); |
| 145 | 137 | |
| 146 | | for (self.cpp_initializers.items()) |entry| { |
| 147 | | self.allocator.free(entry.key); |
| 148 | | } |
| 149 | | self.cpp_initializers.deinit(self.allocator); |
| 150 | | |
| 151 | | for (self.cpp_finalizers.items()) |entry| { |
| 152 | | self.allocator.free(entry.key); |
| 153 | | } |
| 154 | | self.cpp_finalizers.deinit(self.allocator); |
| 155 | | |
| 156 | 138 | for (self.load_commands.items) |*lc| { |
| 157 | 139 | lc.deinit(self.allocator); |
| 158 | 140 | } |
| ... | ... | @@ -243,6 +225,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 243 | 225 | self.allocateLinkeditSegment(); |
| 244 | 226 | try self.allocateSymbols(); |
| 245 | 227 | try self.allocateStubsAndGotEntries(); |
| 228 | try self.allocateCppStatics(); |
| 246 | 229 | try self.writeStubHelperCommon(); |
| 247 | 230 | try self.resolveRelocsAndWriteSections(); |
| 248 | 231 | try self.flush(); |
| ... | ... | @@ -1007,37 +990,20 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { |
| 1007 | 990 | entry.value.target_addr, |
| 1008 | 991 | }); |
| 1009 | 992 | } |
| 993 | } |
| 1010 | 994 | |
| 1011 | | for (self.cpp_initializers.items()) |*entry| { |
| 1012 | | const object = self.objects.items[entry.value.file]; |
| 1013 | | entry.value.target_addr = target_addr: { |
| 1014 | | if (object.locals.get(entry.key)) |local| { |
| 1015 | | break :target_addr local.address; |
| 1016 | | } |
| 1017 | | const global = self.symtab.get(entry.key) orelse unreachable; |
| 1018 | | break :target_addr global.address; |
| 1019 | | }; |
| 1020 | | |
| 1021 | | log.debug("resolving C++ initializer '{s}' at 0x{x}", .{ |
| 1022 | | entry.key, |
| 1023 | | entry.value.target_addr, |
| 1024 | | }); |
| 1025 | | } |
| 1026 | | |
| 1027 | | for (self.cpp_finalizers.items()) |*entry| { |
| 1028 | | const object = self.objects.items[entry.value.file]; |
| 1029 | | entry.value.target_addr = target_addr: { |
| 1030 | | if (object.locals.get(entry.key)) |local| { |
| 1031 | | break :target_addr local.address; |
| 1032 | | } |
| 1033 | | const global = self.symtab.get(entry.key) orelse unreachable; |
| 1034 | | break :target_addr global.address; |
| 1035 | | }; |
| 995 | fn allocateCppStatics(self: *Zld) !void { |
| 996 | for (self.objects.items) |*object| { |
| 997 | for (object.initializers.items) |*initializer| { |
| 998 | const sym = object.symtab.items[initializer.symbol]; |
| 999 | const sym_name = object.getString(sym.n_strx); |
| 1000 | initializer.target_addr = object.locals.get(sym_name).?.address; |
| 1036 | 1001 | |
| 1037 | | log.debug("resolving C++ finalizer '{s}' at 0x{x}", .{ |
| 1038 | | entry.key, |
| 1039 | | entry.value.target_addr, |
| 1040 | | }); |
| 1002 | log.debug("resolving C++ initializer '{s}' at 0x{x}", .{ |
| 1003 | sym_name, |
| 1004 | initializer.target_addr, |
| 1005 | }); |
| 1006 | } |
| 1041 | 1007 | } |
| 1042 | 1008 | } |
| 1043 | 1009 | |
| ... | ... | @@ -1453,34 +1419,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1453 | 1419 | const relocs = sect.relocs orelse continue; |
| 1454 | 1420 | for (relocs) |rel| { |
| 1455 | 1421 | switch (rel.@"type") { |
| 1456 | | .unsigned => { |
| 1457 | | if (rel.target != .symbol) continue; |
| 1458 | | |
| 1459 | | const sym = object.symtab.items[rel.target.symbol]; |
| 1460 | | const sym_name = object.getString(sym.n_strx); |
| 1461 | | |
| 1462 | | if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS) { |
| 1463 | | if (self.cpp_initializers.contains(sym_name)) continue; |
| 1464 | | |
| 1465 | | var name = try self.allocator.dupe(u8, sym_name); |
| 1466 | | const index = @intCast(u32, self.cpp_initializers.items().len); |
| 1467 | | try self.cpp_initializers.putNoClobber(self.allocator, name, .{ |
| 1468 | | .index = index, |
| 1469 | | .target_addr = 0, |
| 1470 | | .file = @intCast(u16, object_id), |
| 1471 | | }); |
| 1472 | | } else if (sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) { |
| 1473 | | if (self.cpp_finalizers.contains(sym_name)) continue; |
| 1474 | | |
| 1475 | | var name = try self.allocator.dupe(u8, sym_name); |
| 1476 | | const index = @intCast(u32, self.cpp_finalizers.items().len); |
| 1477 | | try self.cpp_finalizers.putNoClobber(self.allocator, name, .{ |
| 1478 | | .index = index, |
| 1479 | | .target_addr = 0, |
| 1480 | | .file = @intCast(u16, object_id), |
| 1481 | | }); |
| 1482 | | } else continue; |
| 1483 | | }, |
| 1422 | .unsigned => continue, |
| 1484 | 1423 | .got_page, .got_page_off, .got_load, .got => { |
| 1485 | 1424 | const sym = object.symtab.items[rel.target.symbol]; |
| 1486 | 1425 | const sym_name = object.getString(sym.n_strx); |
| ... | ... | @@ -2194,36 +2133,18 @@ fn flush(self: *Zld) !void { |
| 2194 | 2133 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2195 | 2134 | const sect = &seg.sections.items[index]; |
| 2196 | 2135 | |
| 2197 | | var buffer = try self.allocator.alloc(u8, self.cpp_initializers.items().len * @sizeOf(u64)); |
| 2198 | | defer self.allocator.free(buffer); |
| 2199 | | |
| 2200 | | var stream = std.io.fixedBufferStream(buffer); |
| 2201 | | var writer = stream.writer(); |
| 2202 | | |
| 2203 | | for (self.cpp_initializers.items()) |entry| { |
| 2204 | | try writer.writeIntLittle(u64, entry.value.target_addr); |
| 2205 | | } |
| 2206 | | |
| 2207 | | _ = try self.file.?.pwriteAll(buffer, sect.offset); |
| 2208 | | sect.size = @intCast(u32, buffer.len); |
| 2209 | | } |
| 2210 | | |
| 2211 | | if (self.mod_term_func_section_index) |index| { |
| 2212 | | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2213 | | const sect = &seg.sections.items[index]; |
| 2214 | | |
| 2215 | | var buffer = try self.allocator.alloc(u8, self.cpp_finalizers.items().len * @sizeOf(u64)); |
| 2216 | | defer self.allocator.free(buffer); |
| 2217 | | |
| 2218 | | var stream = std.io.fixedBufferStream(buffer); |
| 2219 | | var writer = stream.writer(); |
| 2136 | var initializers = std.ArrayList(u64).init(self.allocator); |
| 2137 | defer initializers.deinit(); |
| 2220 | 2138 | |
| 2221 | | for (self.cpp_finalizers.items()) |entry| { |
| 2222 | | try writer.writeIntLittle(u64, entry.value.target_addr); |
| 2139 | // TODO sort the initializers globally |
| 2140 | for (self.objects.items) |object| { |
| 2141 | for (object.initializers.items) |initializer| { |
| 2142 | try initializers.append(initializer.target_addr); |
| 2143 | } |
| 2223 | 2144 | } |
| 2224 | 2145 | |
| 2225 | | _ = try self.file.?.pwriteAll(buffer, sect.offset); |
| 2226 | | sect.size = @intCast(u32, buffer.len); |
| 2146 | _ = try self.file.?.pwriteAll(mem.sliceAsBytes(initializers.items), sect.offset); |
| 2147 | sect.size = @intCast(u32, initializers.items.len * @sizeOf(u64)); |
| 2227 | 2148 | } |
| 2228 | 2149 | |
| 2229 | 2150 | try self.writeGotEntries(); |
| ... | ... | @@ -2328,26 +2249,15 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2328 | 2249 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2329 | 2250 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2330 | 2251 | |
| 2331 | | for (self.cpp_initializers.items()) |entry| { |
| 2332 | | try pointers.append(.{ |
| 2333 | | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2334 | | .segment_id = segment_id, |
| 2335 | | }); |
| 2336 | | } |
| 2337 | | } |
| 2338 | | |
| 2339 | | if (self.mod_term_func_section_index) |idx| { |
| 2340 | | // TODO audit and investigate this. |
| 2341 | | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2342 | | const sect = seg.sections.items[idx]; |
| 2343 | | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2344 | | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2345 | | |
| 2346 | | for (self.cpp_finalizers.items()) |entry| { |
| 2347 | | try pointers.append(.{ |
| 2348 | | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2349 | | .segment_id = segment_id, |
| 2350 | | }); |
| 2252 | var index: u64 = 0; |
| 2253 | for (self.objects.items) |object| { |
| 2254 | for (object.initializers.items) |_| { |
| 2255 | try pointers.append(.{ |
| 2256 | .offset = base_offset + index * @sizeOf(u64), |
| 2257 | .segment_id = segment_id, |
| 2258 | }); |
| 2259 | index += 1; |
| 2260 | } |
| 2351 | 2261 | } |
| 2352 | 2262 | } |
| 2353 | 2263 | |