| ... | @@ -82,20 +82,12 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, | ... | @@ -82,20 +82,12 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 82 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, | 82 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 83 | stubs: std.StringArrayHashMapUnmanaged(u32) = .{}, | 83 | stubs: std.StringArrayHashMapUnmanaged(u32) = .{}, |
| 84 | got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, | 84 | got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, |
| 85 | cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, | | |
| 86 | cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, | | |
| 87 | | 85 | |
| 88 | stub_helper_stubs_start_off: ?u64 = null, | 86 | stub_helper_stubs_start_off: ?u64 = null, |
| 89 | | 87 | |
| 90 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, | 88 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| 91 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, | 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 | const GotEntry = struct { | 91 | const GotEntry = struct { |
| 100 | tag: enum { | 92 | tag: enum { |
| 101 | local, | 93 | local, |
| ... | @@ -143,16 +135,6 @@ pub fn deinit(self: *Zld) void { | ... | @@ -143,16 +135,6 @@ pub fn deinit(self: *Zld) void { |
| 143 | } | 135 | } |
| 144 | self.got_entries.deinit(self.allocator); | 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 | for (self.load_commands.items) |*lc| { | 138 | for (self.load_commands.items) |*lc| { |
| 157 | lc.deinit(self.allocator); | 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,6 +225,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 243 | self.allocateLinkeditSegment(); | 225 | self.allocateLinkeditSegment(); |
| 244 | try self.allocateSymbols(); | 226 | try self.allocateSymbols(); |
| 245 | try self.allocateStubsAndGotEntries(); | 227 | try self.allocateStubsAndGotEntries(); |
| | 228 | try self.allocateCppStatics(); |
| 246 | try self.writeStubHelperCommon(); | 229 | try self.writeStubHelperCommon(); |
| 247 | try self.resolveRelocsAndWriteSections(); | 230 | try self.resolveRelocsAndWriteSections(); |
| 248 | try self.flush(); | 231 | try self.flush(); |
| ... | @@ -1007,37 +990,20 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { | ... | @@ -1007,37 +990,20 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { |
| 1007 | entry.value.target_addr, | 990 | entry.value.target_addr, |
| 1008 | }); | 991 | }); |
| 1009 | } | 992 | } |
| | 993 | } |
| 1010 | | 994 | |
| 1011 | for (self.cpp_initializers.items()) |*entry| { | 995 | fn allocateCppStatics(self: *Zld) !void { |
| 1012 | const object = self.objects.items[entry.value.file]; | 996 | for (self.objects.items) |*object| { |
| 1013 | entry.value.target_addr = target_addr: { | 997 | for (object.initializers.items) |*initializer| { |
| 1014 | if (object.locals.get(entry.key)) |local| { | 998 | const sym = object.symtab.items[initializer.symbol]; |
| 1015 | break :target_addr local.address; | 999 | const sym_name = object.getString(sym.n_strx); |
| 1016 | } | 1000 | initializer.target_addr = object.locals.get(sym_name).?.address; |
| 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 | }; | | |
| 1036 | | 1001 | |
| 1037 | log.debug("resolving C++ finalizer '{s}' at 0x{x}", .{ | 1002 | log.debug("resolving C++ initializer '{s}' at 0x{x}", .{ |
| 1038 | entry.key, | 1003 | sym_name, |
| 1039 | entry.value.target_addr, | 1004 | initializer.target_addr, |
| 1040 | }); | 1005 | }); |
| | 1006 | } |
| 1041 | } | 1007 | } |
| 1042 | } | 1008 | } |
| 1043 | | 1009 | |
| ... | @@ -1453,34 +1419,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { | ... | @@ -1453,34 +1419,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1453 | const relocs = sect.relocs orelse continue; | 1419 | const relocs = sect.relocs orelse continue; |
| 1454 | for (relocs) |rel| { | 1420 | for (relocs) |rel| { |
| 1455 | switch (rel.@"type") { | 1421 | switch (rel.@"type") { |
| 1456 | .unsigned => { | 1422 | .unsigned => continue, |
| 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 | }, | | |
| 1484 | .got_page, .got_page_off, .got_load, .got => { | 1423 | .got_page, .got_page_off, .got_load, .got => { |
| 1485 | const sym = object.symtab.items[rel.target.symbol]; | 1424 | const sym = object.symtab.items[rel.target.symbol]; |
| 1486 | const sym_name = object.getString(sym.n_strx); | 1425 | const sym_name = object.getString(sym.n_strx); |
| ... | @@ -2194,36 +2133,18 @@ fn flush(self: *Zld) !void { | ... | @@ -2194,36 +2133,18 @@ fn flush(self: *Zld) !void { |
| 2194 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 2133 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2195 | const sect = &seg.sections.items[index]; | 2134 | const sect = &seg.sections.items[index]; |
| 2196 | | 2135 | |
| 2197 | var buffer = try self.allocator.alloc(u8, self.cpp_initializers.items().len * @sizeOf(u64)); | 2136 | var initializers = std.ArrayList(u64).init(self.allocator); |
| 2198 | defer self.allocator.free(buffer); | 2137 | defer initializers.deinit(); |
| 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(); | | |
| 2220 | | 2138 | |
| 2221 | for (self.cpp_finalizers.items()) |entry| { | 2139 | // TODO sort the initializers globally |
| 2222 | try writer.writeIntLittle(u64, entry.value.target_addr); | 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); | 2146 | _ = try self.file.?.pwriteAll(mem.sliceAsBytes(initializers.items), sect.offset); |
| 2226 | sect.size = @intCast(u32, buffer.len); | 2147 | sect.size = @intCast(u32, initializers.items.len * @sizeOf(u64)); |
| 2227 | } | 2148 | } |
| 2228 | | 2149 | |
| 2229 | try self.writeGotEntries(); | 2150 | try self.writeGotEntries(); |
| ... | @@ -2328,26 +2249,15 @@ fn writeRebaseInfoTable(self: *Zld) !void { | ... | @@ -2328,26 +2249,15 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2328 | const base_offset = sect.addr - seg.inner.vmaddr; | 2249 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2329 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); | 2250 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2330 | | 2251 | |
| 2331 | for (self.cpp_initializers.items()) |entry| { | 2252 | var index: u64 = 0; |
| 2332 | try pointers.append(.{ | 2253 | for (self.objects.items) |object| { |
| 2333 | .offset = base_offset + entry.value.index * @sizeOf(u64), | 2254 | for (object.initializers.items) |_| { |
| 2334 | .segment_id = segment_id, | 2255 | try pointers.append(.{ |
| 2335 | }); | 2256 | .offset = base_offset + index * @sizeOf(u64), |
| 2336 | } | 2257 | .segment_id = segment_id, |
| 2337 | } | 2258 | }); |
| 2338 | | 2259 | index += 1; |
| 2339 | if (self.mod_term_func_section_index) |idx| { | 2260 | } |
| 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 | }); | | |
| 2351 | } | 2261 | } |
| 2352 | } | 2262 | } |
| 2353 | | 2263 | |