diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 8ccd320274..6703a5bfb7 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -14,7 +14,6 @@ const Allocator = mem.Allocator; const Relocation = reloc.Relocation; const Symbol = @import("Symbol.zig"); const parseName = @import("Zld.zig").parseName; -const CppStatic = @import("Zld.zig").CppStatic; usingnamespace @import("commands.zig"); @@ -33,7 +32,9 @@ symtab_cmd_index: ?u16 = null, dysymtab_cmd_index: ?u16 = null, build_version_cmd_index: ?u16 = null, data_in_code_cmd_index: ?u16 = null, + text_section_index: ?u16 = null, +mod_init_func_section_index: ?u16 = null, // __DWARF segment sections dwarf_debug_info_index: ?u16 = null, @@ -50,6 +51,7 @@ stabs: std.ArrayListUnmanaged(Stab) = .{}, tu_path: ?[]const u8 = null, tu_mtime: ?u64 = null, +initializers: std.ArrayListUnmanaged(CppStatic) = .{}, data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, pub const Section = struct { @@ -69,6 +71,11 @@ pub const Section = struct { } }; +const CppStatic = struct { + symbol: u32, + target_addr: u64, +}; + const Stab = struct { tag: Tag, symbol: u32, @@ -171,6 +178,7 @@ pub fn deinit(self: *Object) void { self.strtab.deinit(self.allocator); self.stabs.deinit(self.allocator); self.data_in_code_entries.deinit(self.allocator); + self.initializers.deinit(self.allocator); if (self.name) |n| { self.allocator.free(n); @@ -252,6 +260,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void { if (mem.eql(u8, sectname, "__text")) { self.text_section_index = index; } + } else if (mem.eql(u8, segname, "__DATA")) { + if (mem.eql(u8, sectname, "__mod_init_func")) { + self.mod_init_func_section_index = index; + } } sect.offset += offset; @@ -323,16 +335,27 @@ pub fn parseSections(self: *Object) !void { } pub fn parseInitializers(self: *Object) !void { - for (self.sections.items) |section| { - if (section.inner.flags != macho.S_MOD_INIT_FUNC_POINTERS) continue; - log.warn("parsing initializers in {s}", .{self.name.?}); - // Parse C++ initializers - const relocs = section.relocs orelse unreachable; - for (relocs) |rel| { - const sym = self.symtab.items[rel.target.symbol]; - const sym_name = self.getString(sym.n_strx); - log.warn(" | {s}", .{sym_name}); - } + const index = self.mod_init_func_section_index orelse return; + const section = self.sections.items[index]; + + log.debug("parsing initializers in {s}", .{self.name.?}); + + // Parse C++ initializers + const relocs = section.relocs orelse unreachable; + try self.initializers.ensureCapacity(self.allocator, relocs.len); + for (relocs) |rel| { + self.initializers.appendAssumeCapacity(.{ + .symbol = rel.target.symbol, + .target_addr = undefined, + }); + } + + mem.reverse(CppStatic, self.initializers.items); + + for (self.initializers.items) |initializer| { + const sym = self.symtab.items[initializer.symbol]; + const sym_name = self.getString(sym.n_strx); + log.debug(" | {s}", .{sym_name}); } } diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 02344d36d4..a585b1fd1e 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -82,20 +82,12 @@ threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, stubs: std.StringArrayHashMapUnmanaged(u32) = .{}, got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, -cpp_initializers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, -cpp_finalizers: std.StringArrayHashMapUnmanaged(CppStatic) = .{}, stub_helper_stubs_start_off: ?u64 = null, mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, -pub const CppStatic = struct { - index: u32, - target_addr: u64, - file: u16, -}; - const GotEntry = struct { tag: enum { local, @@ -143,16 +135,6 @@ pub fn deinit(self: *Zld) void { } self.got_entries.deinit(self.allocator); - for (self.cpp_initializers.items()) |entry| { - self.allocator.free(entry.key); - } - self.cpp_initializers.deinit(self.allocator); - - for (self.cpp_finalizers.items()) |entry| { - self.allocator.free(entry.key); - } - self.cpp_finalizers.deinit(self.allocator); - for (self.load_commands.items) |*lc| { lc.deinit(self.allocator); } @@ -243,6 +225,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { self.allocateLinkeditSegment(); try self.allocateSymbols(); try self.allocateStubsAndGotEntries(); + try self.allocateCppStatics(); try self.writeStubHelperCommon(); try self.resolveRelocsAndWriteSections(); try self.flush(); @@ -1007,37 +990,20 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { entry.value.target_addr, }); } +} - for (self.cpp_initializers.items()) |*entry| { - const object = self.objects.items[entry.value.file]; - entry.value.target_addr = target_addr: { - if (object.locals.get(entry.key)) |local| { - break :target_addr local.address; - } - const global = self.symtab.get(entry.key) orelse unreachable; - break :target_addr global.address; - }; +fn allocateCppStatics(self: *Zld) !void { + for (self.objects.items) |*object| { + for (object.initializers.items) |*initializer| { + const sym = object.symtab.items[initializer.symbol]; + const sym_name = object.getString(sym.n_strx); + initializer.target_addr = object.locals.get(sym_name).?.address; - log.debug("resolving C++ initializer '{s}' at 0x{x}", .{ - entry.key, - entry.value.target_addr, - }); - } - - for (self.cpp_finalizers.items()) |*entry| { - const object = self.objects.items[entry.value.file]; - entry.value.target_addr = target_addr: { - if (object.locals.get(entry.key)) |local| { - break :target_addr local.address; - } - const global = self.symtab.get(entry.key) orelse unreachable; - break :target_addr global.address; - }; - - log.debug("resolving C++ finalizer '{s}' at 0x{x}", .{ - entry.key, - entry.value.target_addr, - }); + log.debug("resolving C++ initializer '{s}' at 0x{x}", .{ + sym_name, + initializer.target_addr, + }); + } } } @@ -1453,34 +1419,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { const relocs = sect.relocs orelse continue; for (relocs) |rel| { switch (rel.@"type") { - .unsigned => { - if (rel.target != .symbol) continue; - - const sym = object.symtab.items[rel.target.symbol]; - const sym_name = object.getString(sym.n_strx); - - if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS) { - if (self.cpp_initializers.contains(sym_name)) continue; - - var name = try self.allocator.dupe(u8, sym_name); - const index = @intCast(u32, self.cpp_initializers.items().len); - try self.cpp_initializers.putNoClobber(self.allocator, name, .{ - .index = index, - .target_addr = 0, - .file = @intCast(u16, object_id), - }); - } else if (sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) { - if (self.cpp_finalizers.contains(sym_name)) continue; - - var name = try self.allocator.dupe(u8, sym_name); - const index = @intCast(u32, self.cpp_finalizers.items().len); - try self.cpp_finalizers.putNoClobber(self.allocator, name, .{ - .index = index, - .target_addr = 0, - .file = @intCast(u16, object_id), - }); - } else continue; - }, + .unsigned => continue, .got_page, .got_page_off, .got_load, .got => { const sym = object.symtab.items[rel.target.symbol]; const sym_name = object.getString(sym.n_strx); @@ -2194,36 +2133,18 @@ fn flush(self: *Zld) !void { const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; const sect = &seg.sections.items[index]; - var buffer = try self.allocator.alloc(u8, self.cpp_initializers.items().len * @sizeOf(u64)); - defer self.allocator.free(buffer); + var initializers = std.ArrayList(u64).init(self.allocator); + defer initializers.deinit(); - var stream = std.io.fixedBufferStream(buffer); - var writer = stream.writer(); - - for (self.cpp_initializers.items()) |entry| { - try writer.writeIntLittle(u64, entry.value.target_addr); + // TODO sort the initializers globally + for (self.objects.items) |object| { + for (object.initializers.items) |initializer| { + try initializers.append(initializer.target_addr); + } } - _ = try self.file.?.pwriteAll(buffer, sect.offset); - sect.size = @intCast(u32, buffer.len); - } - - if (self.mod_term_func_section_index) |index| { - const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; - const sect = &seg.sections.items[index]; - - var buffer = try self.allocator.alloc(u8, self.cpp_finalizers.items().len * @sizeOf(u64)); - defer self.allocator.free(buffer); - - var stream = std.io.fixedBufferStream(buffer); - var writer = stream.writer(); - - for (self.cpp_finalizers.items()) |entry| { - try writer.writeIntLittle(u64, entry.value.target_addr); - } - - _ = try self.file.?.pwriteAll(buffer, sect.offset); - sect.size = @intCast(u32, buffer.len); + _ = try self.file.?.pwriteAll(mem.sliceAsBytes(initializers.items), sect.offset); + sect.size = @intCast(u32, initializers.items.len * @sizeOf(u64)); } try self.writeGotEntries(); @@ -2328,26 +2249,15 @@ fn writeRebaseInfoTable(self: *Zld) !void { const base_offset = sect.addr - seg.inner.vmaddr; const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); - for (self.cpp_initializers.items()) |entry| { - try pointers.append(.{ - .offset = base_offset + entry.value.index * @sizeOf(u64), - .segment_id = segment_id, - }); - } - } - - if (self.mod_term_func_section_index) |idx| { - // TODO audit and investigate this. - const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; - const sect = seg.sections.items[idx]; - const base_offset = sect.addr - seg.inner.vmaddr; - const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); - - for (self.cpp_finalizers.items()) |entry| { - try pointers.append(.{ - .offset = base_offset + entry.value.index * @sizeOf(u64), - .segment_id = segment_id, - }); + var index: u64 = 0; + for (self.objects.items) |object| { + for (object.initializers.items) |_| { + try pointers.append(.{ + .offset = base_offset + index * @sizeOf(u64), + .segment_id = segment_id, + }); + index += 1; + } } }