authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-23 10:33:32+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-24 08:13:53+02:00
log4ec6d174adc038741f1274d157f5253752eb8d51
tree088029d57d1ea6a819bcf464c4eb822310265c43
parentb00d08b667ab8f0face2d5dc8ddc7b0b6f13a763

zld: new approach at handling static inits


2 files changed, 66 insertions(+), 133 deletions(-)

src/link/MachO/Object.zig+34-11
......@@ -14,7 +14,6 @@ const Allocator = mem.Allocator;
1414const Relocation = reloc.Relocation;
1515const Symbol = @import("Symbol.zig");
1616const parseName = @import("Zld.zig").parseName;
17const CppStatic = @import("Zld.zig").CppStatic;
1817
1918usingnamespace @import("commands.zig");
2019
......@@ -33,7 +32,9 @@ symtab_cmd_index: ?u16 = null,
3332dysymtab_cmd_index: ?u16 = null,
3433build_version_cmd_index: ?u16 = null,
3534data_in_code_cmd_index: ?u16 = null,
35
3636text_section_index: ?u16 = null,
37mod_init_func_section_index: ?u16 = null,
3738
3839// __DWARF segment sections
3940dwarf_debug_info_index: ?u16 = null,
......@@ -50,6 +51,7 @@ stabs: std.ArrayListUnmanaged(Stab) = .{},
5051tu_path: ?[]const u8 = null,
5152tu_mtime: ?u64 = null,
5253
54initializers: std.ArrayListUnmanaged(CppStatic) = .{},
5355data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
5456
5557pub const Section = struct {
......@@ -69,6 +71,11 @@ pub const Section = struct {
6971 }
7072};
7173
74const CppStatic = struct {
75 symbol: u32,
76 target_addr: u64,
77};
78
7279const Stab = struct {
7380 tag: Tag,
7481 symbol: u32,
......@@ -171,6 +178,7 @@ pub fn deinit(self: *Object) void {
171178 self.strtab.deinit(self.allocator);
172179 self.stabs.deinit(self.allocator);
173180 self.data_in_code_entries.deinit(self.allocator);
181 self.initializers.deinit(self.allocator);
174182
175183 if (self.name) |n| {
176184 self.allocator.free(n);
......@@ -252,6 +260,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
252260 if (mem.eql(u8, sectname, "__text")) {
253261 self.text_section_index = index;
254262 }
263 } else if (mem.eql(u8, segname, "__DATA")) {
264 if (mem.eql(u8, sectname, "__mod_init_func")) {
265 self.mod_init_func_section_index = index;
266 }
255267 }
256268
257269 sect.offset += offset;
......@@ -323,16 +335,27 @@ pub fn parseSections(self: *Object) !void {
323335}
324336
325337pub fn parseInitializers(self: *Object) !void {
326 for (self.sections.items) |section| {
327 if (section.inner.flags != macho.S_MOD_INIT_FUNC_POINTERS) continue;
328 log.warn("parsing initializers in {s}", .{self.name.?});
329 // Parse C++ initializers
330 const relocs = section.relocs orelse unreachable;
331 for (relocs) |rel| {
332 const sym = self.symtab.items[rel.target.symbol];
333 const sym_name = self.getString(sym.n_strx);
334 log.warn(" | {s}", .{sym_name});
335 }
338 const index = self.mod_init_func_section_index orelse return;
339 const section = self.sections.items[index];
340
341 log.debug("parsing initializers in {s}", .{self.name.?});
342
343 // Parse C++ initializers
344 const relocs = section.relocs orelse unreachable;
345 try self.initializers.ensureCapacity(self.allocator, relocs.len);
346 for (relocs) |rel| {
347 self.initializers.appendAssumeCapacity(.{
348 .symbol = rel.target.symbol,
349 .target_addr = undefined,
350 });
351 }
352
353 mem.reverse(CppStatic, self.initializers.items);
354
355 for (self.initializers.items) |initializer| {
356 const sym = self.symtab.items[initializer.symbol];
357 const sym_name = self.getString(sym.n_strx);
358 log.debug(" | {s}", .{sym_name});
336359 }
337360}
338361
src/link/MachO/Zld.zig+32-122
......@@ -82,20 +82,12 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
8282local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
8383stubs: std.StringArrayHashMapUnmanaged(u32) = .{},
8484got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
85cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{},
86cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{},
8785
8886stub_helper_stubs_start_off: ?u64 = null,
8987
9088mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
9189unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
9290
93pub const CppStatic = struct {
94 index: u32,
95 target_addr: u64,
96 file: u16,
97};
98
9991const GotEntry = struct {
10092 tag: enum {
10193 local,
......@@ -143,16 +135,6 @@ pub fn deinit(self: *Zld) void {
143135 }
144136 self.got_entries.deinit(self.allocator);
145137
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
156138 for (self.load_commands.items) |*lc| {
157139 lc.deinit(self.allocator);
158140 }
......@@ -243,6 +225,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
243225 self.allocateLinkeditSegment();
244226 try self.allocateSymbols();
245227 try self.allocateStubsAndGotEntries();
228 try self.allocateCppStatics();
246229 try self.writeStubHelperCommon();
247230 try self.resolveRelocsAndWriteSections();
248231 try self.flush();
......@@ -1007,37 +990,20 @@ fn allocateStubsAndGotEntries(self: *Zld) !void {
1007990 entry.value.target_addr,
1008991 });
1009992 }
993}
1010994
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 };
995fn 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;
10361001
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 }
10411007 }
10421008}
10431009
......@@ -1453,34 +1419,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
14531419 const relocs = sect.relocs orelse continue;
14541420 for (relocs) |rel| {
14551421 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,
14841423 .got_page, .got_page_off, .got_load, .got => {
14851424 const sym = object.symtab.items[rel.target.symbol];
14861425 const sym_name = object.getString(sym.n_strx);
......@@ -2194,36 +2133,18 @@ fn flush(self: *Zld) !void {
21942133 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
21952134 const sect = &seg.sections.items[index];
21962135
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();
22202138
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 }
22232144 }
22242145
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));
22272148 }
22282149
22292150 try self.writeGotEntries();
......@@ -2328,26 +2249,15 @@ fn writeRebaseInfoTable(self: *Zld) !void {
23282249 const base_offset = sect.addr - seg.inner.vmaddr;
23292250 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
23302251
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 }
23512261 }
23522262 }
23532263