aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-07-18 18:33:23 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-07-18 18:36:48 +0200
commit4bc72c48b76eb59e6f1eb160d3d590606e7ae090 (patch)
tree24b330bd7a2128caecc787a937c130454f28a440 /src
parentf6d13e9d6f7a4b9161f369544501ecbb447c1658 (diff)
downloadzig-4bc72c48b76eb59e6f1eb160d3d590606e7ae090.tar.gz
zig-4bc72c48b76eb59e6f1eb160d3d590606e7ae090.zip
macho: temporarily dupe a few linkedit fns so that traditional linker works
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO.zig267
1 files changed, 261 insertions, 6 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 66a1ee4e04..8aac8820da 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -583,7 +583,6 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
const is_lib = self.base.options.output_mode == .Lib;
const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
- const target = self.base.options.target;
const stack_size = self.base.options.stack_size_override orelse 0;
const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
@@ -2755,6 +2754,7 @@ fn addRpaths(self: *MachO, rpaths: []const []const u8) !void {
}
fn flushZld(self: *MachO) !void {
+ self.load_commands_dirty = true;
try self.writeTextBlocks();
try self.writeStubHelperCommon();
@@ -2778,10 +2778,10 @@ fn flushZld(self: *MachO) !void {
try self.writeGotEntries();
try self.setEntryPoint();
- try self.writeRebaseInfoTable();
- try self.writeBindInfoTable();
- try self.writeLazyBindInfoTable();
- try self.writeExportInfo();
+ try self.writeRebaseInfoTableZld();
+ try self.writeBindInfoTableZld();
+ try self.writeLazyBindInfoTableZld();
+ try self.writeExportInfoZld();
try self.writeDices();
{
@@ -2791,7 +2791,7 @@ fn flushZld(self: *MachO) !void {
}
try self.writeSymbolTable();
- try self.writeStringTable();
+ try self.writeStringTableZld();
{
// Seal __LINKEDIT size
@@ -2856,6 +2856,244 @@ fn setEntryPoint(self: *MachO) !void {
ec.stacksize = self.base.options.stack_size_override orelse 0;
}
+fn writeRebaseInfoTableZld(self: *MachO) !void {
+ var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
+ defer pointers.deinit();
+
+ {
+ var it = self.blocks.iterator();
+ while (it.next()) |entry| {
+ const match = entry.key_ptr.*;
+ var block: *TextBlock = entry.value_ptr.*;
+
+ if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
+
+ const seg = self.load_commands.items[match.seg].Segment;
+
+ while (true) {
+ const sym = self.locals.items[block.local_sym_index];
+ const base_offset = sym.n_value - seg.inner.vmaddr;
+
+ for (block.rebases.items) |offset| {
+ try pointers.append(.{
+ .offset = base_offset + offset,
+ .segment_id = match.seg,
+ });
+ }
+
+ if (block.prev) |prev| {
+ block = prev;
+ } else break;
+ }
+ }
+ }
+
+ if (self.got_section_index) |idx| {
+ 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.got_entries.items) |entry, i| {
+ if (entry.where == .import) continue;
+
+ try pointers.append(.{
+ .offset = base_offset + i * @sizeOf(u64),
+ .segment_id = segment_id,
+ });
+ }
+ }
+
+ if (self.la_symbol_ptr_section_index) |idx| {
+ const seg = self.load_commands.items[self.data_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_segment_cmd_index.?);
+
+ try pointers.ensureUnusedCapacity(self.stubs.items.len);
+ for (self.stubs.items) |_, i| {
+ pointers.appendAssumeCapacity(.{
+ .offset = base_offset + i * @sizeOf(u64),
+ .segment_id = segment_id,
+ });
+ }
+ }
+
+ std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);
+
+ const size = try bind.rebaseInfoSize(pointers.items);
+ var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
+ defer self.base.allocator.free(buffer);
+
+ var stream = std.io.fixedBufferStream(buffer);
+ try bind.writeRebaseInfo(pointers.items, stream.writer());
+
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
+ dyld_info.rebase_off = @intCast(u32, seg.inner.fileoff);
+ dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @sizeOf(u64)));
+ seg.inner.filesize += dyld_info.rebase_size;
+
+ log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size });
+
+ try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
+}
+
+fn writeBindInfoTableZld(self: *MachO) !void {
+ var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
+ defer pointers.deinit();
+
+ if (self.got_section_index) |idx| {
+ 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.got_entries.items) |entry, i| {
+ if (entry.where == .local) continue;
+
+ const sym = self.imports.items[entry.where_index];
+ try pointers.append(.{
+ .offset = base_offset + i * @sizeOf(u64),
+ .segment_id = segment_id,
+ .dylib_ordinal = unpackDylibOrdinal(sym.n_desc),
+ .name = self.getString(sym.n_strx),
+ });
+ }
+ }
+
+ {
+ var it = self.blocks.iterator();
+ while (it.next()) |entry| {
+ const match = entry.key_ptr.*;
+ var block: *TextBlock = entry.value_ptr.*;
+
+ if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
+
+ const seg = self.load_commands.items[match.seg].Segment;
+
+ while (true) {
+ const sym = self.locals.items[block.local_sym_index];
+ const base_offset = sym.n_value - seg.inner.vmaddr;
+
+ for (block.bindings.items) |binding| {
+ const bind_sym = self.imports.items[binding.local_sym_index];
+ try pointers.append(.{
+ .offset = binding.offset + base_offset,
+ .segment_id = match.seg,
+ .dylib_ordinal = unpackDylibOrdinal(bind_sym.n_desc),
+ .name = self.getString(bind_sym.n_strx),
+ });
+ }
+
+ if (block.prev) |prev| {
+ block = prev;
+ } else break;
+ }
+ }
+ }
+
+ const size = try bind.bindInfoSize(pointers.items);
+ var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
+ defer self.base.allocator.free(buffer);
+
+ var stream = std.io.fixedBufferStream(buffer);
+ try bind.writeBindInfo(pointers.items, stream.writer());
+
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
+ dyld_info.bind_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
+ dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
+ seg.inner.filesize += dyld_info.bind_size;
+
+ log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size });
+
+ try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
+}
+
+fn writeLazyBindInfoTableZld(self: *MachO) !void {
+ var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
+ defer pointers.deinit();
+
+ if (self.la_symbol_ptr_section_index) |idx| {
+ const seg = self.load_commands.items[self.data_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_segment_cmd_index.?);
+
+ try pointers.ensureUnusedCapacity(self.stubs.items.len);
+
+ for (self.stubs.items) |import_id, i| {
+ const sym = self.imports.items[import_id];
+ pointers.appendAssumeCapacity(.{
+ .offset = base_offset + i * @sizeOf(u64),
+ .segment_id = segment_id,
+ .dylib_ordinal = unpackDylibOrdinal(sym.n_desc),
+ .name = self.getString(sym.n_strx),
+ });
+ }
+ }
+
+ const size = try bind.lazyBindInfoSize(pointers.items);
+ var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
+ defer self.base.allocator.free(buffer);
+
+ var stream = std.io.fixedBufferStream(buffer);
+ try bind.writeLazyBindInfo(pointers.items, stream.writer());
+
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
+ dyld_info.lazy_bind_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
+ dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
+ seg.inner.filesize += dyld_info.lazy_bind_size;
+
+ log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size });
+
+ try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
+ try self.populateLazyBindOffsetsInStubHelper(buffer);
+}
+
+fn writeExportInfoZld(self: *MachO) !void {
+ var trie = Trie.init(self.base.allocator);
+ defer trie.deinit();
+
+ const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const base_address = text_segment.inner.vmaddr;
+
+ // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
+ log.debug("writing export trie", .{});
+
+ for (self.globals.items) |sym| {
+ const sym_name = self.getString(sym.n_strx);
+ log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, sym.n_value });
+
+ try trie.put(.{
+ .name = sym_name,
+ .vmaddr_offset = sym.n_value - base_address,
+ .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
+ });
+ }
+
+ try trie.finalize();
+
+ var buffer = try self.base.allocator.alloc(u8, @intCast(usize, trie.size));
+ defer self.base.allocator.free(buffer);
+
+ var stream = std.io.fixedBufferStream(buffer);
+ const nwritten = try trie.write(stream.writer());
+ assert(nwritten == trie.size);
+
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
+ dyld_info.export_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
+ dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
+ seg.inner.filesize += dyld_info.export_size;
+
+ log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
+
+ try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
+}
+
fn writeSymbolTable(self: *MachO) !void {
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
@@ -5222,6 +5460,23 @@ fn writeStringTable(self: *MachO) !void {
self.strtab_dirty = false;
}
+fn writeStringTableZld(self: *MachO) !void {
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
+ symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
+ symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
+ seg.inner.filesize += symtab.strsize;
+
+ log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
+
+ try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
+
+ if (symtab.strsize > self.strtab.items.len and self.base.options.target.cpu.arch == .x86_64) {
+ // This is the last section, so we need to pad it out.
+ try self.base.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
+ }
+}
+
fn updateLinkeditSegmentSizes(self: *MachO) !void {
if (!self.load_commands_dirty) return;