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) = .{},
8181local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
8282stubs: std.StringArrayHashMapUnmanaged(u32) = .{},
8383got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
84cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{},
85cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{},
8486
8587stub_helper_stubs_start_off: ?u64 = null,
8688
8789mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
8890unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
8991
92const CppStatic = struct {
93 index: u32,
94 target_addr: u64,
95 file: u16,
96};
97
9098const GotEntry = struct {
9199 tag: enum {
92100 local,
......@@ -134,6 +142,16 @@ pub fn deinit(self: *Zld) void {
134142 }
135143 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
137155 for (self.load_commands.items) |*lc| {
138156 lc.deinit(self.allocator);
139157 }
......@@ -957,6 +975,38 @@ fn allocateStubsAndGotEntries(self: *Zld) !void {
957975 entry.value.target_addr,
958976 });
959977 }
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 }
9601010}
9611011
9621012fn writeStubHelperCommon(self: *Zld) !void {
......@@ -1257,8 +1307,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
12571307 },
12581308 .strong => {
12591309 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});
12621311 }
12631312 continue;
12641313 },
......@@ -1348,14 +1397,14 @@ fn resolveSymbols(self: *Zld) !void {
13481397 });
13491398
13501399 {
1351 log.warn("symtab", .{});
1400 log.debug("symtab", .{});
13521401 for (self.symtab.items()) |sym| {
13531402 switch (sym.value.tag) {
13541403 .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.? });
13561405 },
13571406 .import => {
1358 log.warn(" | {s} => libSystem.B.dylib", .{sym.key});
1407 log.debug(" | {s} => libSystem.B.dylib", .{sym.key});
13591408 },
13601409 else => unreachable,
13611410 }
......@@ -1371,7 +1420,34 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
13711420 const relocs = sect.relocs orelse continue;
13721421 for (relocs) |rel| {
13731422 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 },
13751451 .got_page, .got_page_off, .got_load, .got => {
13761452 const sym = object.symtab.items[rel.target.symbol];
13771453 const sym_name = object.getString(sym.n_strx);
......@@ -1433,9 +1509,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
14331509 log.debug("relocating object {s}", .{object.name});
14341510
14351511 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
14361515 const segname = parseName(&sect.inner.segname);
14371516 const sectname = parseName(&sect.inner.sectname);
14381517
1518 log.debug("relocating section '{s},{s}'", .{ segname, sectname });
1519
14391520 // Get mapping
14401521 const target_mapping = self.mappings.get(.{
14411522 .object_id = @intCast(u16, object_id),
......@@ -2061,6 +2142,42 @@ fn flush(self: *Zld) !void {
20612142 try self.file.?.pwriteAll(buffer, sect.offset);
20622143 }
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
20642181 try self.writeGotEntries();
20652182 try self.setEntryPoint();
20662183 try self.writeRebaseInfoTable();
......@@ -2160,15 +2277,12 @@ fn writeRebaseInfoTable(self: *Zld) !void {
21602277 // TODO audit and investigate this.
21612278 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
21622279 const sect = seg.sections.items[idx];
2163 const npointers = sect.size * @sizeOf(u64);
21642280 const base_offset = sect.addr - seg.inner.vmaddr;
21652281 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
21662282
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),
21722286 .segment_id = segment_id,
21732287 });
21742288 }
......@@ -2178,15 +2292,12 @@ fn writeRebaseInfoTable(self: *Zld) !void {
21782292 // TODO audit and investigate this.
21792293 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
21802294 const sect = seg.sections.items[idx];
2181 const npointers = sect.size * @sizeOf(u64);
21822295 const base_offset = sect.addr - seg.inner.vmaddr;
21832296 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
21842297
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),
21902301 .segment_id = segment_id,
21912302 });
21922303 }
src/link/MachO/reloc/aarch64.zig+3-1
......@@ -226,7 +226,9 @@ pub const Parser = struct {
226226 try parser.parseTlvpLoadPageOff(rel);
227227 },
228228 .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", .{});
230232 },
231233 }
232234 }