diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO/Zld.zig | 147 | ||||
| -rw-r--r-- | src/link/MachO/reloc/aarch64.zig | 4 |
2 files changed, 132 insertions, 19 deletions
diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 0fb1ab2145..52761ef048 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -81,12 +81,20 @@ 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) = .{}, +const CppStatic = struct { + index: u32, + target_addr: u64, + file: u16, +}; + const GotEntry = struct { tag: enum { local, @@ -134,6 +142,16 @@ 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); } @@ -957,6 +975,38 @@ 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; + }; + + log.debug("resolving C++ finalizer '{s}' at 0x{x}", .{ + entry.key, + entry.value.target_addr, + }); + } } fn writeStubHelperCommon(self: *Zld) !void { @@ -1257,8 +1307,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { }, .strong => { if (!is_weak) { - log.err("symbol '{s}' defined multiple times", .{sym_name}); - return error.MultipleSymbolDefinitions; + log.debug("strong symbol '{s}' defined multiple times", .{sym_name}); } continue; }, @@ -1348,14 +1397,14 @@ fn resolveSymbols(self: *Zld) !void { }); { - log.warn("symtab", .{}); + log.debug("symtab", .{}); for (self.symtab.items()) |sym| { switch (sym.value.tag) { .weak, .strong => { - log.warn(" | {s} => {s}", .{ sym.key, self.objects.items[sym.value.file.?].name.? }); + log.debug(" | {s} => {s}", .{ sym.key, self.objects.items[sym.value.file.?].name.? }); }, .import => { - log.warn(" | {s} => libSystem.B.dylib", .{sym.key}); + log.debug(" | {s} => libSystem.B.dylib", .{sym.key}); }, else => unreachable, } @@ -1371,7 +1420,34 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { const relocs = sect.relocs orelse continue; for (relocs) |rel| { switch (rel.@"type") { - .unsigned => continue, + .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; + }, .got_page, .got_page_off, .got_load, .got => { const sym = object.symtab.items[rel.target.symbol]; const sym_name = object.getString(sym.n_strx); @@ -1433,9 +1509,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { log.debug("relocating object {s}", .{object.name}); for (object.sections.items) |sect, source_sect_id| { + if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or + sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue; + const segname = parseName(§.inner.segname); const sectname = parseName(§.inner.sectname); + log.debug("relocating section '{s},{s}'", .{ segname, sectname }); + // Get mapping const target_mapping = self.mappings.get(.{ .object_id = @intCast(u16, object_id), @@ -2061,6 +2142,42 @@ fn flush(self: *Zld) !void { try self.file.?.pwriteAll(buffer, sect.offset); } + if (self.mod_init_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_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(); + + 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.writeGotEntries(); try self.setEntryPoint(); try self.writeRebaseInfoTable(); @@ -2160,15 +2277,12 @@ fn writeRebaseInfoTable(self: *Zld) !void { // 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 npointers = sect.size * @sizeOf(u64); const base_offset = sect.addr - seg.inner.vmaddr; const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); - try pointers.ensureCapacity(pointers.items.len + npointers); - var i: usize = 0; - while (i < npointers) : (i += 1) { - pointers.appendAssumeCapacity(.{ - .offset = base_offset + i * @sizeOf(u64), + for (self.cpp_initializers.items()) |entry| { + try pointers.append(.{ + .offset = base_offset + entry.value.index * @sizeOf(u64), .segment_id = segment_id, }); } @@ -2178,15 +2292,12 @@ fn writeRebaseInfoTable(self: *Zld) !void { // 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 npointers = sect.size * @sizeOf(u64); const base_offset = sect.addr - seg.inner.vmaddr; const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); - try pointers.ensureCapacity(pointers.items.len + npointers); - var i: usize = 0; - while (i < npointers) : (i += 1) { - pointers.appendAssumeCapacity(.{ - .offset = base_offset + i * @sizeOf(u64), + for (self.cpp_finalizers.items()) |entry| { + try pointers.append(.{ + .offset = base_offset + entry.value.index * @sizeOf(u64), .segment_id = segment_id, }); } diff --git a/src/link/MachO/reloc/aarch64.zig b/src/link/MachO/reloc/aarch64.zig index a7dd0919b4..d8e7cebddd 100644 --- a/src/link/MachO/reloc/aarch64.zig +++ b/src/link/MachO/reloc/aarch64.zig @@ -226,7 +226,9 @@ pub const Parser = struct { try parser.parseTlvpLoadPageOff(rel); }, .ARM64_RELOC_POINTER_TO_GOT => { - return error.ToDoRelocPointerToGot; + // TODO Handle pointer to GOT. This reloc seems to appear in + // __LD,__compact_unwind section which we currently don't handle. + log.debug("Unhandled relocation ARM64_RELOC_POINTER_TO_GOT", .{}); }, } } |
