authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-14 15:19:42+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-20 16:55:32+02:00
log8943a0aaaab1cda1285d3732ccc525ea5da8e794
treec2539574b69646598da778bdfb72ff4bc2c1eb65
parent3e73a3c29b597ff05e7a178106ff86056cf4494d

zld: dedup initializers and finalizers


2 files changed, 132 insertions(+), 19 deletions(-)

src/link/MachO/Zld.zig+129-18
...@@ -81,12 +81,20 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},...@@ -81,12 +81,20 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
81local_rebases: std.ArrayListUnmanaged(Pointer) = .{},81local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
82stubs: std.StringArrayHashMapUnmanaged(u32) = .{},82stubs: std.StringArrayHashMapUnmanaged(u32) = .{},
83got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},83got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
84cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{},
85cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{},
8486
85stub_helper_stubs_start_off: ?u64 = null,87stub_helper_stubs_start_off: ?u64 = null,
8688
87mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},89mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
88unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},90unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
8991
92const CppStatic = struct {
93 index: u32,
94 target_addr: u64,
95 file: u16,
96};
97
90const GotEntry = struct {98const 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);
136144
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}
9611011
962fn writeStubHelperCommon(self: *Zld) !void {1012fn 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 });
13491398
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});
14341510
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);
14381517
1518 log.debug("relocating section '{s},{s}'", .{ segname, sectname });
1519
1439 // Get mapping1520 // 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 }
20632144
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.?);
21662282
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.?);
21842297
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 }
src/link/MachO/reloc/aarch64.zig+3-1
...@@ -226,7 +226,9 @@ pub const Parser = struct {...@@ -226,7 +226,9 @@ pub const Parser = struct {
226 try parser.parseTlvpLoadPageOff(rel);226 try parser.parseTlvpLoadPageOff(rel);
227 },227 },
228 .ARM64_RELOC_POINTER_TO_GOT => {228 .ARM64_RELOC_POINTER_TO_GOT => {
229 return error.ToDoRelocPointerToGot;229 // TODO Handle pointer to GOT. This reloc seems to appear in
230 // __LD,__compact_unwind section which we currently don't handle.
231 log.debug("Unhandled relocation ARM64_RELOC_POINTER_TO_GOT", .{});
230 },232 },
231 }233 }
232 }234 }