zld: new approach at handling static inits
This commit is contained in:
@@ -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});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user