| ... | @@ -583,7 +583,6 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { | ... | @@ -583,7 +583,6 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 583 | const is_lib = self.base.options.output_mode == .Lib; | 583 | const is_lib = self.base.options.output_mode == .Lib; |
| 584 | const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; | 584 | const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; |
| 585 | const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe; | 585 | const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe; |
| 586 | const target = self.base.options.target; | | |
| 587 | const stack_size = self.base.options.stack_size_override orelse 0; | 586 | const stack_size = self.base.options.stack_size_override orelse 0; |
| 588 | const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; | 587 | const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; |
| 589 | | 588 | |
| ... | @@ -2755,6 +2754,7 @@ fn addRpaths(self: *MachO, rpaths: []const []const u8) !void { | ... | @@ -2755,6 +2754,7 @@ fn addRpaths(self: *MachO, rpaths: []const []const u8) !void { |
| 2755 | } | 2754 | } |
| 2756 | | 2755 | |
| 2757 | fn flushZld(self: *MachO) !void { | 2756 | fn flushZld(self: *MachO) !void { |
| | 2757 | self.load_commands_dirty = true; |
| 2758 | try self.writeTextBlocks(); | 2758 | try self.writeTextBlocks(); |
| 2759 | try self.writeStubHelperCommon(); | 2759 | try self.writeStubHelperCommon(); |
| 2760 | | 2760 | |
| ... | @@ -2778,10 +2778,10 @@ fn flushZld(self: *MachO) !void { | ... | @@ -2778,10 +2778,10 @@ fn flushZld(self: *MachO) !void { |
| 2778 | | 2778 | |
| 2779 | try self.writeGotEntries(); | 2779 | try self.writeGotEntries(); |
| 2780 | try self.setEntryPoint(); | 2780 | try self.setEntryPoint(); |
| 2781 | try self.writeRebaseInfoTable(); | 2781 | try self.writeRebaseInfoTableZld(); |
| 2782 | try self.writeBindInfoTable(); | 2782 | try self.writeBindInfoTableZld(); |
| 2783 | try self.writeLazyBindInfoTable(); | 2783 | try self.writeLazyBindInfoTableZld(); |
| 2784 | try self.writeExportInfo(); | 2784 | try self.writeExportInfoZld(); |
| 2785 | try self.writeDices(); | 2785 | try self.writeDices(); |
| 2786 | | 2786 | |
| 2787 | { | 2787 | { |
| ... | @@ -2791,7 +2791,7 @@ fn flushZld(self: *MachO) !void { | ... | @@ -2791,7 +2791,7 @@ fn flushZld(self: *MachO) !void { |
| 2791 | } | 2791 | } |
| 2792 | | 2792 | |
| 2793 | try self.writeSymbolTable(); | 2793 | try self.writeSymbolTable(); |
| 2794 | try self.writeStringTable(); | 2794 | try self.writeStringTableZld(); |
| 2795 | | 2795 | |
| 2796 | { | 2796 | { |
| 2797 | // Seal __LINKEDIT size | 2797 | // Seal __LINKEDIT size |
| ... | @@ -2856,6 +2856,244 @@ fn setEntryPoint(self: *MachO) !void { | ... | @@ -2856,6 +2856,244 @@ fn setEntryPoint(self: *MachO) !void { |
| 2856 | ec.stacksize = self.base.options.stack_size_override orelse 0; | 2856 | ec.stacksize = self.base.options.stack_size_override orelse 0; |
| 2857 | } | 2857 | } |
| 2858 | | 2858 | |
| | 2859 | fn 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 | |
| | 2942 | fn 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 | |
| | 3014 | fn 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 | |
| | 3056 | fn 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 | |
| 2859 | fn writeSymbolTable(self: *MachO) !void { | 3097 | fn writeSymbolTable(self: *MachO) !void { |
| 2860 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 3098 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2861 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 3099 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| ... | @@ -5222,6 +5460,23 @@ fn writeStringTable(self: *MachO) !void { | ... | @@ -5222,6 +5460,23 @@ fn writeStringTable(self: *MachO) !void { |
| 5222 | self.strtab_dirty = false; | 5460 | self.strtab_dirty = false; |
| 5223 | } | 5461 | } |
| 5224 | | 5462 | |
| | 5463 | fn 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 | |
| 5225 | fn updateLinkeditSegmentSizes(self: *MachO) !void { | 5480 | fn updateLinkeditSegmentSizes(self: *MachO) !void { |
| 5226 | if (!self.load_commands_dirty) return; | 5481 | if (!self.load_commands_dirty) return; |
| 5227 | | 5482 | |