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;...@@ -14,7 +14,6 @@ const Allocator = mem.Allocator;
14const Relocation = reloc.Relocation;14const Relocation = reloc.Relocation;
15const Symbol = @import("Symbol.zig");15const Symbol = @import("Symbol.zig");
16const parseName = @import("Zld.zig").parseName;16const parseName = @import("Zld.zig").parseName;
17const CppStatic = @import("Zld.zig").CppStatic;
1817
19usingnamespace @import("commands.zig");18usingnamespace @import("commands.zig");
2019
...@@ -33,7 +32,9 @@ symtab_cmd_index: ?u16 = null,...@@ -33,7 +32,9 @@ symtab_cmd_index: ?u16 = null,
33dysymtab_cmd_index: ?u16 = null,32dysymtab_cmd_index: ?u16 = null,
34build_version_cmd_index: ?u16 = null,33build_version_cmd_index: ?u16 = null,
35data_in_code_cmd_index: ?u16 = null,34data_in_code_cmd_index: ?u16 = null,
35
36text_section_index: ?u16 = null,36text_section_index: ?u16 = null,
37mod_init_func_section_index: ?u16 = null,
3738
38// __DWARF segment sections39// __DWARF segment sections
39dwarf_debug_info_index: ?u16 = null,40dwarf_debug_info_index: ?u16 = null,
...@@ -50,6 +51,7 @@ stabs: std.ArrayListUnmanaged(Stab) = .{},...@@ -50,6 +51,7 @@ stabs: std.ArrayListUnmanaged(Stab) = .{},
50tu_path: ?[]const u8 = null,51tu_path: ?[]const u8 = null,
51tu_mtime: ?u64 = null,52tu_mtime: ?u64 = null,
5253
54initializers: std.ArrayListUnmanaged(CppStatic) = .{},
53data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},55data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
5456
55pub const Section = struct {57pub const Section = struct {
...@@ -69,6 +71,11 @@ pub const Section = struct {...@@ -69,6 +71,11 @@ pub const Section = struct {
69 }71 }
70};72};
7173
74const CppStatic = struct {
75 symbol: u32,
76 target_addr: u64,
77};
78
72const Stab = struct {79const Stab = struct {
73 tag: Tag,80 tag: Tag,
74 symbol: u32,81 symbol: u32,
...@@ -171,6 +178,7 @@ pub fn deinit(self: *Object) void {...@@ -171,6 +178,7 @@ pub fn deinit(self: *Object) void {
171 self.strtab.deinit(self.allocator);178 self.strtab.deinit(self.allocator);
172 self.stabs.deinit(self.allocator);179 self.stabs.deinit(self.allocator);
173 self.data_in_code_entries.deinit(self.allocator);180 self.data_in_code_entries.deinit(self.allocator);
181 self.initializers.deinit(self.allocator);
174182
175 if (self.name) |n| {183 if (self.name) |n| {
176 self.allocator.free(n);184 self.allocator.free(n);
...@@ -252,6 +260,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {...@@ -252,6 +260,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
252 if (mem.eql(u8, sectname, "__text")) {260 if (mem.eql(u8, sectname, "__text")) {
253 self.text_section_index = index;261 self.text_section_index = index;
254 }262 }
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 }
255 }267 }
256268
257 sect.offset += offset;269 sect.offset += offset;
...@@ -323,16 +335,27 @@ pub fn parseSections(self: *Object) !void {...@@ -323,16 +335,27 @@ pub fn parseSections(self: *Object) !void {
323}335}
324336
325pub fn parseInitializers(self: *Object) !void {337pub fn parseInitializers(self: *Object) !void {
326 for (self.sections.items) |section| {338 const index = self.mod_init_func_section_index orelse return;
327 if (section.inner.flags != macho.S_MOD_INIT_FUNC_POINTERS) continue;339 const section = self.sections.items[index];
328 log.warn("parsing initializers in {s}", .{self.name.?});340
329 // Parse C++ initializers341 log.debug("parsing initializers in {s}", .{self.name.?});
330 const relocs = section.relocs orelse unreachable;342
331 for (relocs) |rel| {343 // Parse C++ initializers
332 const sym = self.symtab.items[rel.target.symbol];344 const relocs = section.relocs orelse unreachable;
333 const sym_name = self.getString(sym.n_strx);345 try self.initializers.ensureCapacity(self.allocator, relocs.len);
334 log.warn(" | {s}", .{sym_name});346 for (relocs) |rel| {
335 }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});
336 }359 }
337}360}
338361
src/link/MachO/Zld.zig+32-122
...@@ -82,20 +82,12 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},...@@ -82,20 +82,12 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
82local_rebases: std.ArrayListUnmanaged(Pointer) = .{},82local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
83stubs: std.StringArrayHashMapUnmanaged(u32) = .{},83stubs: std.StringArrayHashMapUnmanaged(u32) = .{},
84got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},84got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
85cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{},
86cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{},
8785
88stub_helper_stubs_start_off: ?u64 = null,86stub_helper_stubs_start_off: ?u64 = null,
8987
90mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},88mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
91unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},89unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
9290
93pub const CppStatic = struct {
94 index: u32,
95 target_addr: u64,
96 file: u16,
97};
98
99const GotEntry = struct {91const 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);
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
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}
1010994
1011 for (self.cpp_initializers.items()) |*entry| {995fn 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 };
10361001
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}
10431009
...@@ -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];
21962135
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();
22202138
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 }
22242145
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 }
22282149
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.?);
23302251
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 });
23382259 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 }
23532263