Commit 4ec6d174ad
Changed files (2)
src
link
MachO
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});
}
}
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;
- };
-
- 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;
- };
+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++ 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 stream = std.io.fixedBufferStream(buffer);
- var writer = stream.writer();
-
- for (self.cpp_initializers.items()) |entry| {
- try writer.writeIntLittle(u64, entry.value.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();
+ var initializers = std.ArrayList(u64).init(self.allocator);
+ defer initializers.deinit();
- for (self.cpp_finalizers.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);
+ _ = 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;
+ }
}
}