authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-18 18:33:23+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-18 18:36:48+02:00
log4bc72c48b76eb59e6f1eb160d3d590606e7ae090
tree24b330bd7a2128caecc787a937c130454f28a440
parentf6d13e9d6f7a4b9161f369544501ecbb447c1658

macho: temporarily dupe a few linkedit fns so that traditional linker works


1 files changed, 261 insertions(+), 6 deletions(-)

src/link/MachO.zig+261-6
......@@ -583,7 +583,6 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
583583 const is_lib = self.base.options.output_mode == .Lib;
584584 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
585585 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
586 const target = self.base.options.target;
587586 const stack_size = self.base.options.stack_size_override orelse 0;
588587 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
589588
......@@ -2755,6 +2754,7 @@ fn addRpaths(self: *MachO, rpaths: []const []const u8) !void {
27552754}
27562755
27572756fn flushZld(self: *MachO) !void {
2757 self.load_commands_dirty = true;
27582758 try self.writeTextBlocks();
27592759 try self.writeStubHelperCommon();
27602760
......@@ -2778,10 +2778,10 @@ fn flushZld(self: *MachO) !void {
27782778
27792779 try self.writeGotEntries();
27802780 try self.setEntryPoint();
2781 try self.writeRebaseInfoTable();
2782 try self.writeBindInfoTable();
2783 try self.writeLazyBindInfoTable();
2784 try self.writeExportInfo();
2781 try self.writeRebaseInfoTableZld();
2782 try self.writeBindInfoTableZld();
2783 try self.writeLazyBindInfoTableZld();
2784 try self.writeExportInfoZld();
27852785 try self.writeDices();
27862786
27872787 {
......@@ -2791,7 +2791,7 @@ fn flushZld(self: *MachO) !void {
27912791 }
27922792
27932793 try self.writeSymbolTable();
2794 try self.writeStringTable();
2794 try self.writeStringTableZld();
27952795
27962796 {
27972797 // Seal __LINKEDIT size
......@@ -2856,6 +2856,244 @@ fn setEntryPoint(self: *MachO) !void {
28562856 ec.stacksize = self.base.options.stack_size_override orelse 0;
28572857}
28582858
2859fn writeRebaseInfoTableZld(self: *MachO) !void {
2860 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
2861 defer pointers.deinit();
2862
2863 {
2864 var it = self.blocks.iterator();
2865 while (it.next()) |entry| {
2866 const match = entry.key_ptr.*;
2867 var block: *TextBlock = entry.value_ptr.*;
2868
2869 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
2870
2871 const seg = self.load_commands.items[match.seg].Segment;
2872
2873 while (true) {
2874 const sym = self.locals.items[block.local_sym_index];
2875 const base_offset = sym.n_value - seg.inner.vmaddr;
2876
2877 for (block.rebases.items) |offset| {
2878 try pointers.append(.{
2879 .offset = base_offset + offset,
2880 .segment_id = match.seg,
2881 });
2882 }
2883
2884 if (block.prev) |prev| {
2885 block = prev;
2886 } else break;
2887 }
2888 }
2889 }
2890
2891 if (self.got_section_index) |idx| {
2892 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2893 const sect = seg.sections.items[idx];
2894 const base_offset = sect.addr - seg.inner.vmaddr;
2895 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
2896
2897 for (self.got_entries.items) |entry, i| {
2898 if (entry.where == .import) continue;
2899
2900 try pointers.append(.{
2901 .offset = base_offset + i * @sizeOf(u64),
2902 .segment_id = segment_id,
2903 });
2904 }
2905 }
2906
2907 if (self.la_symbol_ptr_section_index) |idx| {
2908 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2909 const sect = seg.sections.items[idx];
2910 const base_offset = sect.addr - seg.inner.vmaddr;
2911 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
2912
2913 try pointers.ensureUnusedCapacity(self.stubs.items.len);
2914 for (self.stubs.items) |_, i| {
2915 pointers.appendAssumeCapacity(.{
2916 .offset = base_offset + i * @sizeOf(u64),
2917 .segment_id = segment_id,
2918 });
2919 }
2920 }
2921
2922 std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);
2923
2924 const size = try bind.rebaseInfoSize(pointers.items);
2925 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
2926 defer self.base.allocator.free(buffer);
2927
2928 var stream = std.io.fixedBufferStream(buffer);
2929 try bind.writeRebaseInfo(pointers.items, stream.writer());
2930
2931 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2932 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
2933 dyld_info.rebase_off = @intCast(u32, seg.inner.fileoff);
2934 dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @sizeOf(u64)));
2935 seg.inner.filesize += dyld_info.rebase_size;
2936
2937 log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size });
2938
2939 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
2940}
2941
2942fn writeBindInfoTableZld(self: *MachO) !void {
2943 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
2944 defer pointers.deinit();
2945
2946 if (self.got_section_index) |idx| {
2947 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2948 const sect = seg.sections.items[idx];
2949 const base_offset = sect.addr - seg.inner.vmaddr;
2950 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
2951
2952 for (self.got_entries.items) |entry, i| {
2953 if (entry.where == .local) continue;
2954
2955 const sym = self.imports.items[entry.where_index];
2956 try pointers.append(.{
2957 .offset = base_offset + i * @sizeOf(u64),
2958 .segment_id = segment_id,
2959 .dylib_ordinal = unpackDylibOrdinal(sym.n_desc),
2960 .name = self.getString(sym.n_strx),
2961 });
2962 }
2963 }
2964
2965 {
2966 var it = self.blocks.iterator();
2967 while (it.next()) |entry| {
2968 const match = entry.key_ptr.*;
2969 var block: *TextBlock = entry.value_ptr.*;
2970
2971 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
2972
2973 const seg = self.load_commands.items[match.seg].Segment;
2974
2975 while (true) {
2976 const sym = self.locals.items[block.local_sym_index];
2977 const base_offset = sym.n_value - seg.inner.vmaddr;
2978
2979 for (block.bindings.items) |binding| {
2980 const bind_sym = self.imports.items[binding.local_sym_index];
2981 try pointers.append(.{
2982 .offset = binding.offset + base_offset,
2983 .segment_id = match.seg,
2984 .dylib_ordinal = unpackDylibOrdinal(bind_sym.n_desc),
2985 .name = self.getString(bind_sym.n_strx),
2986 });
2987 }
2988
2989 if (block.prev) |prev| {
2990 block = prev;
2991 } else break;
2992 }
2993 }
2994 }
2995
2996 const size = try bind.bindInfoSize(pointers.items);
2997 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
2998 defer self.base.allocator.free(buffer);
2999
3000 var stream = std.io.fixedBufferStream(buffer);
3001 try bind.writeBindInfo(pointers.items, stream.writer());
3002
3003 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3004 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3005 dyld_info.bind_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3006 dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
3007 seg.inner.filesize += dyld_info.bind_size;
3008
3009 log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size });
3010
3011 try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
3012}
3013
3014fn writeLazyBindInfoTableZld(self: *MachO) !void {
3015 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
3016 defer pointers.deinit();
3017
3018 if (self.la_symbol_ptr_section_index) |idx| {
3019 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
3020 const sect = seg.sections.items[idx];
3021 const base_offset = sect.addr - seg.inner.vmaddr;
3022 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
3023
3024 try pointers.ensureUnusedCapacity(self.stubs.items.len);
3025
3026 for (self.stubs.items) |import_id, i| {
3027 const sym = self.imports.items[import_id];
3028 pointers.appendAssumeCapacity(.{
3029 .offset = base_offset + i * @sizeOf(u64),
3030 .segment_id = segment_id,
3031 .dylib_ordinal = unpackDylibOrdinal(sym.n_desc),
3032 .name = self.getString(sym.n_strx),
3033 });
3034 }
3035 }
3036
3037 const size = try bind.lazyBindInfoSize(pointers.items);
3038 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
3039 defer self.base.allocator.free(buffer);
3040
3041 var stream = std.io.fixedBufferStream(buffer);
3042 try bind.writeLazyBindInfo(pointers.items, stream.writer());
3043
3044 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3045 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3046 dyld_info.lazy_bind_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3047 dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
3048 seg.inner.filesize += dyld_info.lazy_bind_size;
3049
3050 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 });
3051
3052 try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
3053 try self.populateLazyBindOffsetsInStubHelper(buffer);
3054}
3055
3056fn writeExportInfoZld(self: *MachO) !void {
3057 var trie = Trie.init(self.base.allocator);
3058 defer trie.deinit();
3059
3060 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
3061 const base_address = text_segment.inner.vmaddr;
3062
3063 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
3064 log.debug("writing export trie", .{});
3065
3066 for (self.globals.items) |sym| {
3067 const sym_name = self.getString(sym.n_strx);
3068 log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, sym.n_value });
3069
3070 try trie.put(.{
3071 .name = sym_name,
3072 .vmaddr_offset = sym.n_value - base_address,
3073 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
3074 });
3075 }
3076
3077 try trie.finalize();
3078
3079 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, trie.size));
3080 defer self.base.allocator.free(buffer);
3081
3082 var stream = std.io.fixedBufferStream(buffer);
3083 const nwritten = try trie.write(stream.writer());
3084 assert(nwritten == trie.size);
3085
3086 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3087 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3088 dyld_info.export_off = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3089 dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)));
3090 seg.inner.filesize += dyld_info.export_size;
3091
3092 log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
3093
3094 try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
3095}
3096
28593097fn writeSymbolTable(self: *MachO) !void {
28603098 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
28613099 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
......@@ -5222,6 +5460,23 @@ fn writeStringTable(self: *MachO) !void {
52225460 self.strtab_dirty = false;
52235461}
52245462
5463fn writeStringTableZld(self: *MachO) !void {
5464 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5465 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
5466 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
5467 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
5468 seg.inner.filesize += symtab.strsize;
5469
5470 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
5471
5472 try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
5473
5474 if (symtab.strsize > self.strtab.items.len and self.base.options.target.cpu.arch == .x86_64) {
5475 // This is the last section, so we need to pad it out.
5476 try self.base.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
5477 }
5478}
5479
52255480fn updateLinkeditSegmentSizes(self: *MachO) !void {
52265481 if (!self.load_commands_dirty) return;
52275482