| ... | @@ -105,16 +105,17 @@ entry_addr: ?u64 = null, | ... | @@ -105,16 +105,17 @@ entry_addr: ?u64 = null, |
| 105 | /// Table of all local symbols | 105 | /// Table of all local symbols |
| 106 | /// Internally references string table for names (which are optional). | 106 | /// Internally references string table for names (which are optional). |
| 107 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 107 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 108 | /// Table of all defined global symbols | 108 | /// Table of all global symbols |
| 109 | global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 109 | global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 110 | /// Table of all undefined symbols | 110 | /// Table of all extern nonlazy symbols, indexed by name. |
| 111 | undef_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 111 | extern_nonlazy_symbols: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{}, |
| | 112 | /// Table of all extern lazy symbols, indexed by name. |
| | 113 | extern_lazy_symbols: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{}, |
| 112 | | 114 | |
| 113 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 115 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 114 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | 116 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 115 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, | 117 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 116 | | 118 | |
| 117 | dyld_stub_binder_index: ?u16 = null, | | |
| 118 | stub_helper_stubs_start_off: ?u64 = null, | 119 | stub_helper_stubs_start_off: ?u64 = null, |
| 119 | | 120 | |
| 120 | /// Table of symbol names aka the string table. | 121 | /// Table of symbol names aka the string table. |
| ... | @@ -123,13 +124,6 @@ string_table: std.ArrayListUnmanaged(u8) = .{}, | ... | @@ -123,13 +124,6 @@ string_table: std.ArrayListUnmanaged(u8) = .{}, |
| 123 | /// Table of trampolines to the actual symbols in __text section. | 124 | /// Table of trampolines to the actual symbols in __text section. |
| 124 | offset_table: std.ArrayListUnmanaged(u64) = .{}, | 125 | offset_table: std.ArrayListUnmanaged(u64) = .{}, |
| 125 | | 126 | |
| 126 | /// Table of rebase info entries. | | |
| 127 | rebase_info_table: RebaseInfoTable = .{}, | | |
| 128 | /// Table of binding info entries. | | |
| 129 | binding_info_table: BindingInfoTable = .{}, | | |
| 130 | /// Table of lazy binding info entries. | | |
| 131 | lazy_binding_info_table: LazyBindingInfoTable = .{}, | | |
| 132 | | | |
| 133 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 127 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 134 | | 128 | |
| 135 | offset_table_count_dirty: bool = false, | 129 | offset_table_count_dirty: bool = false, |
| ... | @@ -167,11 +161,10 @@ last_text_block: ?*TextBlock = null, | ... | @@ -167,11 +161,10 @@ last_text_block: ?*TextBlock = null, |
| 167 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, | 161 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 168 | | 162 | |
| 169 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, | 163 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, |
| 170 | externs: std.StringHashMapUnmanaged(u32) = .{}, | | |
| 171 | | 164 | |
| 172 | pub const StubFixup = struct { | 165 | pub const StubFixup = struct { |
| 173 | symbol: u32, | 166 | symbol: u32, |
| 174 | exists: bool, | 167 | already_defined: bool, |
| 175 | start: usize, | 168 | start: usize, |
| 176 | len: usize, | 169 | len: usize, |
| 177 | }; | 170 | }; |
| ... | @@ -920,42 +913,42 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -920,42 +913,42 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 920 | return error.NoSymbolTableFound; | 913 | return error.NoSymbolTableFound; |
| 921 | } | 914 | } |
| 922 | | 915 | |
| 923 | // Parse dyld info | 916 | // // Parse dyld info |
| 924 | try self.parseBindingInfoTable(); | 917 | // try self.parseBindingInfoTable(); |
| 925 | try self.parseLazyBindingInfoTable(); | 918 | // try self.parseLazyBindingInfoTable(); |
| 926 | | 919 | |
| 927 | // Update the dylib ordinals. | 920 | // // Update the dylib ordinals. |
| 928 | self.binding_info_table.dylib_ordinal = next_ordinal; | 921 | // self.binding_info_table.dylib_ordinal = next_ordinal; |
| 929 | for (self.lazy_binding_info_table.symbols.items) |*symbol| { | 922 | // for (self.lazy_binding_info_table.symbols.items) |*symbol| { |
| 930 | symbol.dylib_ordinal = next_ordinal; | 923 | // symbol.dylib_ordinal = next_ordinal; |
| 931 | } | 924 | // } |
| 932 | | 925 | |
| 933 | // Write updated dyld info. | 926 | // // Write updated dyld info. |
| 934 | const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 927 | // const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 935 | { | 928 | // { |
| 936 | const size = try self.binding_info_table.calcSize(); | 929 | // const size = try self.binding_info_table.calcSize(); |
| 937 | assert(dyld_info.bind_size >= size); | 930 | // assert(dyld_info.bind_size >= size); |
| 938 | | 931 | |
| 939 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 932 | // var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 940 | defer self.base.allocator.free(buffer); | 933 | // defer self.base.allocator.free(buffer); |
| 941 | | 934 | |
| 942 | var stream = std.io.fixedBufferStream(buffer); | 935 | // var stream = std.io.fixedBufferStream(buffer); |
| 943 | try self.binding_info_table.write(stream.writer()); | 936 | // try self.binding_info_table.write(stream.writer()); |
| 944 | | 937 | |
| 945 | try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); | 938 | // try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); |
| 946 | } | 939 | // } |
| 947 | { | 940 | // { |
| 948 | const size = try self.lazy_binding_info_table.calcSize(); | 941 | // const size = try self.lazy_binding_info_table.calcSize(); |
| 949 | assert(dyld_info.lazy_bind_size >= size); | 942 | // assert(dyld_info.lazy_bind_size >= size); |
| 950 | | 943 | |
| 951 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 944 | // var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 952 | defer self.base.allocator.free(buffer); | 945 | // defer self.base.allocator.free(buffer); |
| 953 | | 946 | |
| 954 | var stream = std.io.fixedBufferStream(buffer); | 947 | // var stream = std.io.fixedBufferStream(buffer); |
| 955 | try self.lazy_binding_info_table.write(stream.writer()); | 948 | // try self.lazy_binding_info_table.write(stream.writer()); |
| 956 | | 949 | |
| 957 | try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); | 950 | // try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); |
| 958 | } | 951 | // } |
| 959 | | 952 | |
| 960 | // Write updated load commands and the header | 953 | // Write updated load commands and the header |
| 961 | try self.writeLoadCommands(); | 954 | try self.writeLoadCommands(); |
| ... | @@ -1037,14 +1030,13 @@ pub fn deinit(self: *MachO) void { | ... | @@ -1037,14 +1030,13 @@ pub fn deinit(self: *MachO) void { |
| 1037 | if (self.d_sym) |*ds| { | 1030 | if (self.d_sym) |*ds| { |
| 1038 | ds.deinit(self.base.allocator); | 1031 | ds.deinit(self.base.allocator); |
| 1039 | } | 1032 | } |
| 1040 | self.binding_info_table.deinit(self.base.allocator); | | |
| 1041 | self.lazy_binding_info_table.deinit(self.base.allocator); | | |
| 1042 | self.pie_fixups.deinit(self.base.allocator); | 1033 | self.pie_fixups.deinit(self.base.allocator); |
| 1043 | self.text_block_free_list.deinit(self.base.allocator); | 1034 | self.text_block_free_list.deinit(self.base.allocator); |
| 1044 | self.offset_table.deinit(self.base.allocator); | 1035 | self.offset_table.deinit(self.base.allocator); |
| 1045 | self.offset_table_free_list.deinit(self.base.allocator); | 1036 | self.offset_table_free_list.deinit(self.base.allocator); |
| 1046 | self.string_table.deinit(self.base.allocator); | 1037 | self.string_table.deinit(self.base.allocator); |
| 1047 | self.undef_symbols.deinit(self.base.allocator); | 1038 | self.extern_lazy_symbols.deinit(self.base.allocator); |
| | 1039 | self.extern_nonlazy_symbols.deinit(self.base.allocator); |
| 1048 | self.global_symbols.deinit(self.base.allocator); | 1040 | self.global_symbols.deinit(self.base.allocator); |
| 1049 | self.global_symbol_free_list.deinit(self.base.allocator); | 1041 | self.global_symbol_free_list.deinit(self.base.allocator); |
| 1050 | self.local_symbols.deinit(self.base.allocator); | 1042 | self.local_symbols.deinit(self.base.allocator); |
| ... | @@ -1261,59 +1253,28 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1261,59 +1253,28 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1261 | } | 1253 | } |
| 1262 | | 1254 | |
| 1263 | // Resolve stubs (if any) | 1255 | // Resolve stubs (if any) |
| 1264 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; | 1256 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |
| 1265 | const stub_h = &text_segment.sections.items[self.stub_helper_section_index.?]; | | |
| 1266 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | | |
| 1267 | const la_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; | | |
| 1268 | for (self.stub_fixups.items) |fixup| { | 1257 | for (self.stub_fixups.items) |fixup| { |
| 1269 | // TODO increment offset for stub writing | | |
| 1270 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; | 1258 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; |
| 1271 | const text_addr = symbol.n_value + fixup.start; | 1259 | const text_addr = symbol.n_value + fixup.start; |
| 1272 | const displacement = @intCast(u32, stub_addr - text_addr); | 1260 | const displacement = @intCast(u32, stub_addr - text_addr); |
| 1273 | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; | 1261 | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; |
| 1274 | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32()); | 1262 | switch (self.base.options.target.cpu.arch) { |
| 1275 | | 1263 | .x86_64 => return error.TODOImplementStubFixupsForx86_64, |
| 1276 | if (!fixup.exists) { | 1264 | .aarch64 => { |
| 1277 | const stub_off = self.stub_helper_stubs_start_off.? + fixup.symbol * 3 * @sizeOf(u32); | 1265 | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32()); |
| 1278 | const end = stub_h.addr + stub_off - stub_h.offset; | 1266 | }, |
| 1279 | var buf: [@sizeOf(u64)]u8 = undefined; | 1267 | else => unreachable, |
| 1280 | mem.writeIntLittle(u64, &buf, end); | 1268 | } |
| 1281 | try self.base.file.?.pwriteAll(&buf, la_ptr.offset + fixup.symbol * @sizeOf(u64)); | 1269 | if (!fixup.already_defined) { |
| 1282 | | 1270 | try self.writeStub(fixup.symbol); |
| 1283 | const la_ptr_addr = la_ptr.addr + fixup.symbol * @sizeOf(u64); | 1271 | try self.writeStubInStubHelper(fixup.symbol); |
| 1284 | const displacement2 = la_ptr_addr - stub_addr; | 1272 | try self.writeLazySymbolPointer(fixup.symbol); |
| 1285 | var ccode: [2 * @sizeOf(u32)]u8 = undefined; | 1273 | |
| 1286 | mem.writeIntLittle(u32, ccode[0..4], aarch64.Instruction.ldr(.x16, .{ | 1274 | const extern_sym = &self.extern_lazy_symbols.items()[fixup.symbol].value; |
| 1287 | .literal = @intCast(u19, displacement2 / 4), | 1275 | extern_sym.segment = self.data_segment_cmd_index.?; |
| 1288 | }).toU32()); | 1276 | extern_sym.offset = fixup.symbol * @sizeOf(u64); |
| 1289 | mem.writeIntLittle(u32, ccode[4..8], aarch64.Instruction.br(.x16).toU32()); | | |
| 1290 | try self.base.file.?.pwriteAll(&ccode, stubs.offset + fixup.symbol * stubs.reserved2); | | |
| 1291 | | | |
| 1292 | const displacement3 = @intCast(i64, stub_h.addr) - @intCast(i64, end + 4); | | |
| 1293 | var cccode: [3 * @sizeOf(u32)]u8 = undefined; | | |
| 1294 | mem.writeIntLittle(u32, cccode[0..4], aarch64.Instruction.ldr(.w16, .{ | | |
| 1295 | .literal = 0x2, | | |
| 1296 | }).toU32()); | | |
| 1297 | mem.writeIntLittle(u32, cccode[4..8], aarch64.Instruction.b(@intCast(i28, displacement3)).toU32()); | | |
| 1298 | mem.writeIntLittle(u32, cccode[8..12], fixup.symbol * 0xd); | | |
| 1299 | try self.base.file.?.pwriteAll(&cccode, stub_off); | | |
| 1300 | | | |
| 1301 | try self.rebase_info_table.symbols.append(self.base.allocator, .{ | | |
| 1302 | .segment = 3, | | |
| 1303 | .offset = fixup.symbol * stubs.reserved2, | | |
| 1304 | }); | | |
| 1305 | self.rebase_info_dirty = true; | 1277 | self.rebase_info_dirty = true; |
| 1306 | | | |
| 1307 | const sym = self.undef_symbols.items[fixup.symbol + 1]; | | |
| 1308 | const name_str = self.getString(sym.n_strx); | | |
| 1309 | var name = try self.base.allocator.alloc(u8, name_str.len); | | |
| 1310 | mem.copy(u8, name, name_str); | | |
| 1311 | try self.lazy_binding_info_table.symbols.append(self.base.allocator, .{ | | |
| 1312 | .segment = 3, | | |
| 1313 | .offset = fixup.symbol * @sizeOf(u64), | | |
| 1314 | .dylib_ordinal = 1, | | |
| 1315 | .name = name, | | |
| 1316 | }); | | |
| 1317 | self.lazy_binding_info_dirty = true; | 1278 | self.lazy_binding_info_dirty = true; |
| 1318 | } | 1279 | } |
| 1319 | } | 1280 | } |
| ... | @@ -2080,51 +2041,51 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -2080,51 +2041,51 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2080 | self.header_dirty = true; | 2041 | self.header_dirty = true; |
| 2081 | self.load_commands_dirty = true; | 2042 | self.load_commands_dirty = true; |
| 2082 | } | 2043 | } |
| 2083 | if (self.dyld_stub_binder_index == null) { | 2044 | if (!self.extern_nonlazy_symbols.contains("dyld_stub_binder")) { |
| 2084 | self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len); | 2045 | const index = @intCast(u32, self.extern_nonlazy_symbols.items().len); |
| 2085 | const name = try self.makeString("dyld_stub_binder"); | 2046 | const name = try std.fmt.allocPrint(self.base.allocator, "dyld_stub_binder", .{}); |
| 2086 | try self.undef_symbols.append(self.base.allocator, .{ | 2047 | try self.extern_nonlazy_symbols.putNoClobber(self.base.allocator, name, .{ |
| 2087 | .n_strx = name, | 2048 | .name = name, |
| 2088 | .n_type = macho.N_UNDF | macho.N_EXT, | 2049 | .dylib_ordinal = 1, // TODO this is currently hardcoded. |
| 2089 | .n_sect = 0, | 2050 | .index = index, |
| 2090 | .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, | 2051 | .segment = self.data_const_segment_cmd_index.?, |
| 2091 | .n_value = 0, | 2052 | .offset = index * @sizeOf(u64), |
| 2092 | }); | | |
| 2093 | | | |
| 2094 | self.binding_info_table.dylib_ordinal = 1; | | |
| 2095 | const nn = self.getString(name); | | |
| 2096 | var n = try self.base.allocator.alloc(u8, nn.len); | | |
| 2097 | mem.copy(u8, n, nn); | | |
| 2098 | try self.binding_info_table.symbols.append(self.base.allocator, .{ | | |
| 2099 | .name = n, | | |
| 2100 | .segment = 2, | | |
| 2101 | .offset = 0, | | |
| 2102 | }); | 2053 | }); |
| 2103 | self.binding_info_dirty = true; | 2054 | self.binding_info_dirty = true; |
| 2104 | } | 2055 | } |
| 2105 | if (self.stub_helper_stubs_start_off == null) { | 2056 | if (self.stub_helper_stubs_start_off == null) { |
| 2106 | const text = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2057 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2107 | const sh = &text.sections.items[self.stub_helper_section_index.?]; | 2058 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| 2108 | const data = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 2059 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2109 | const data_data = &data.sections.items[self.data_section_index.?]; | 2060 | const data = &data_segment.sections.items[self.data_section_index.?]; |
| 2110 | const displacement = data_data.addr - sh.addr; | 2061 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2111 | var code: [4 * @sizeOf(u32)]u8 = undefined; | 2062 | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; |
| 2112 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, @intCast(i21, displacement)).toU32()); | 2063 | switch (self.base.options.target.cpu.arch) { |
| 2113 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.stp( | 2064 | .x86_64 => return error.TODOImplementStubHelperForX86_64, |
| 2114 | .x16, | 2065 | .aarch64 => { |
| 2115 | .x17, | 2066 | var code: [4 * @sizeOf(u32)]u8 = undefined; |
| 2116 | aarch64.Register.sp, | 2067 | { |
| 2117 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), | 2068 | const displacement = data.addr - stub_helper.addr; |
| 2118 | ).toU32()); | 2069 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, @intCast(i21, displacement)).toU32()); |
| 2119 | const dc = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 2070 | } |
| 2120 | const got = &dc.sections.items[self.data_got_section_index.?]; | 2071 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.stp( |
| 2121 | const displacement2 = got.addr - sh.addr - 2 * @sizeOf(u32); | 2072 | .x16, |
| 2122 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.ldr(.x16, .{ | 2073 | .x17, |
| 2123 | .literal = @intCast(u19, displacement2 / 4), | 2074 | aarch64.Register.sp, |
| 2124 | }).toU32()); | 2075 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), |
| 2125 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.br(.x16).toU32()); | 2076 | ).toU32()); |
| 2126 | self.stub_helper_stubs_start_off = sh.offset + 4 * @sizeOf(u32); | 2077 | { |
| 2127 | try self.base.file.?.pwriteAll(&code, sh.offset); | 2078 | const displacement = got.addr - stub_helper.addr - 2 * @sizeOf(u32); |
| | 2079 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.ldr(.x16, .{ |
| | 2080 | .literal = @intCast(u19, displacement / 4), |
| | 2081 | }).toU32()); |
| | 2082 | } |
| | 2083 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.br(.x16).toU32()); |
| | 2084 | self.stub_helper_stubs_start_off = stub_helper.offset + 4 * @sizeOf(u32); |
| | 2085 | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| | 2086 | }, |
| | 2087 | else => unreachable, |
| | 2088 | } |
| 2128 | } | 2089 | } |
| 2129 | } | 2090 | } |
| 2130 | | 2091 | |
| ... | @@ -2460,11 +2421,73 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | ... | @@ -2460,11 +2421,73 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 2460 | try self.base.file.?.pwriteAll(&code, off); | 2421 | try self.base.file.?.pwriteAll(&code, off); |
| 2461 | } | 2422 | } |
| 2462 | | 2423 | |
| | 2424 | fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| | 2425 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 2426 | const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?]; |
| | 2427 | const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 2428 | const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| | 2429 | |
| | 2430 | const stub_off = self.stub_helper_stubs_start_off.? + index * 3 * @sizeOf(u32); |
| | 2431 | const end = stub_helper.addr + stub_off - stub_helper.offset; |
| | 2432 | var buf: [@sizeOf(u64)]u8 = undefined; |
| | 2433 | mem.writeIntLittle(u64, &buf, end); |
| | 2434 | const off = la_symbol_ptr.offset + index * @sizeOf(u64); |
| | 2435 | log.debug("writing lazy symbol pointer entry 0x{x} at 0x{x}", .{ end, off }); |
| | 2436 | try self.base.file.?.pwriteAll(&buf, off); |
| | 2437 | } |
| | 2438 | |
| | 2439 | fn writeStub(self: *MachO, index: u32) !void { |
| | 2440 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 2441 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |
| | 2442 | const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 2443 | const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| | 2444 | |
| | 2445 | const stub_off = stubs.offset + index * stubs.reserved2; |
| | 2446 | const stub_addr = stubs.addr + index * stubs.reserved2; |
| | 2447 | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); |
| | 2448 | const displacement = la_ptr_addr - stub_addr; |
| | 2449 | log.debug("writing stub at 0x{x}", .{stub_off}); |
| | 2450 | switch (self.base.options.target.cpu.arch) { |
| | 2451 | .x86_64 => return error.TODOImplementWritingStubsForx86_64, |
| | 2452 | .aarch64 => { |
| | 2453 | var code: [2 * @sizeOf(u32)]u8 = undefined; |
| | 2454 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ |
| | 2455 | .literal = @intCast(u19, displacement / 4), |
| | 2456 | }).toU32()); |
| | 2457 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.br(.x16).toU32()); |
| | 2458 | try self.base.file.?.pwriteAll(&code, stub_off); |
| | 2459 | }, |
| | 2460 | else => unreachable, |
| | 2461 | } |
| | 2462 | } |
| | 2463 | |
| | 2464 | fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| | 2465 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 2466 | const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?]; |
| | 2467 | |
| | 2468 | const stub_off = self.stub_helper_stubs_start_off.? + index * 3 * @sizeOf(u32); |
| | 2469 | const end = stub_helper.addr + stub_off - stub_helper.offset; |
| | 2470 | const displacement = @intCast(i64, stub_helper.addr) - @intCast(i64, end + 4); |
| | 2471 | switch (self.base.options.target.cpu.arch) { |
| | 2472 | .x86_64 => return error.TODOImplementWritingStubsInStubHelperForx86_64, |
| | 2473 | .aarch64 => { |
| | 2474 | var code: [3 * @sizeOf(u32)]u8 = undefined; |
| | 2475 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.w16, .{ |
| | 2476 | .literal = 0x2, |
| | 2477 | }).toU32()); |
| | 2478 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(@intCast(i28, displacement)).toU32()); |
| | 2479 | mem.writeIntLittle(u32, code[8..12], index * 0xd); // TODO This is the size of lazy binding opcode block. |
| | 2480 | try self.base.file.?.pwriteAll(&code, stub_off); |
| | 2481 | }, |
| | 2482 | else => unreachable, |
| | 2483 | } |
| | 2484 | } |
| | 2485 | |
| 2463 | fn relocateSymbolTable(self: *MachO) !void { | 2486 | fn relocateSymbolTable(self: *MachO) !void { |
| 2464 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 2487 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2465 | const nlocals = self.local_symbols.items.len; | 2488 | const nlocals = self.local_symbols.items.len; |
| 2466 | const nglobals = self.global_symbols.items.len; | 2489 | const nglobals = self.global_symbols.items.len; |
| 2467 | const nundefs = self.undef_symbols.items.len; | 2490 | const nundefs = self.extern_lazy_symbols.items().len + self.extern_nonlazy_symbols.items().len; |
| 2468 | const nsyms = nlocals + nglobals + nundefs; | 2491 | const nsyms = nlocals + nglobals + nundefs; |
| 2469 | | 2492 | |
| 2470 | if (symtab.nsyms < nsyms) { | 2493 | if (symtab.nsyms < nsyms) { |
| ... | @@ -2509,7 +2532,31 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { | ... | @@ -2509,7 +2532,31 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2509 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 2532 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2510 | const nlocals = self.local_symbols.items.len; | 2533 | const nlocals = self.local_symbols.items.len; |
| 2511 | const nglobals = self.global_symbols.items.len; | 2534 | const nglobals = self.global_symbols.items.len; |
| 2512 | const nundefs = self.undef_symbols.items.len; | 2535 | |
| | 2536 | const nundefs = self.extern_lazy_symbols.items().len + self.extern_nonlazy_symbols.items().len; |
| | 2537 | var undefs = std.ArrayList(macho.nlist_64).init(self.base.allocator); |
| | 2538 | defer undefs.deinit(); |
| | 2539 | try undefs.ensureCapacity(nundefs); |
| | 2540 | for (self.extern_lazy_symbols.items()) |entry| { |
| | 2541 | const name = try self.makeString(entry.key); |
| | 2542 | undefs.appendAssumeCapacity(.{ |
| | 2543 | .n_strx = name, |
| | 2544 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, |
| | 2545 | .n_sect = 0, |
| | 2546 | .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, |
| | 2547 | .n_value = 0, |
| | 2548 | }); |
| | 2549 | } |
| | 2550 | for (self.extern_nonlazy_symbols.items()) |entry| { |
| | 2551 | const name = try self.makeString(entry.key); |
| | 2552 | undefs.appendAssumeCapacity(.{ |
| | 2553 | .n_strx = name, |
| | 2554 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, |
| | 2555 | .n_sect = 0, |
| | 2556 | .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, |
| | 2557 | .n_value = 0, |
| | 2558 | }); |
| | 2559 | } |
| 2513 | | 2560 | |
| 2514 | const locals_off = symtab.symoff; | 2561 | const locals_off = symtab.symoff; |
| 2515 | const locals_size = nlocals * @sizeOf(macho.nlist_64); | 2562 | const locals_size = nlocals * @sizeOf(macho.nlist_64); |
| ... | @@ -2521,8 +2568,8 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { | ... | @@ -2521,8 +2568,8 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2521 | | 2568 | |
| 2522 | const undefs_off = globals_off + globals_size; | 2569 | const undefs_off = globals_off + globals_size; |
| 2523 | const undefs_size = nundefs * @sizeOf(macho.nlist_64); | 2570 | const undefs_size = nundefs * @sizeOf(macho.nlist_64); |
| 2524 | log.debug("writing undef symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); | 2571 | log.debug("writing extern symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); |
| 2525 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off); | 2572 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off); |
| 2526 | | 2573 | |
| 2527 | // Update dynamic symbol table. | 2574 | // Update dynamic symbol table. |
| 2528 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | 2575 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| ... | @@ -2546,42 +2593,33 @@ fn writeIndirectSymbolTable(self: *MachO) !void { | ... | @@ -2546,42 +2593,33 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2546 | | 2593 | |
| 2547 | var buf: [@sizeOf(u32)]u8 = undefined; | 2594 | var buf: [@sizeOf(u32)]u8 = undefined; |
| 2548 | var off = dysymtab.indirectsymoff; | 2595 | var off = dysymtab.indirectsymoff; |
| 2549 | var idx: u32 = 0; | | |
| 2550 | | 2596 | |
| 2551 | stubs.reserved1 = 0; | 2597 | stubs.reserved1 = 0; |
| 2552 | for (self.undef_symbols.items) |sym, i| { | 2598 | for (self.extern_lazy_symbols.items()) |entry| { |
| 2553 | if (i == self.dyld_stub_binder_index.?) { | 2599 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index); |
| 2554 | continue; | | |
| 2555 | } | | |
| 2556 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); | | |
| 2557 | mem.writeIntLittle(u32, &buf, symtab_idx); | 2600 | mem.writeIntLittle(u32, &buf, symtab_idx); |
| 2558 | try self.base.file.?.pwriteAll(&buf, off); | 2601 | try self.base.file.?.pwriteAll(&buf, off); |
| 2559 | off += @sizeOf(u32); | 2602 | off += @sizeOf(u32); |
| 2560 | dysymtab.nindirectsyms += 1; | 2603 | dysymtab.nindirectsyms += 1; |
| 2561 | idx += 1; | | |
| 2562 | } | 2604 | } |
| 2563 | | 2605 | |
| 2564 | got.reserved1 = @intCast(u32, self.undef_symbols.items.len - 1); | 2606 | const base_id = @intCast(u32, self.extern_lazy_symbols.items().len); |
| 2565 | if (self.dyld_stub_binder_index) |i| { | 2607 | got.reserved1 = base_id; |
| 2566 | const symtab_idx = i + dysymtab.iundefsym; | 2608 | for (self.extern_nonlazy_symbols.items()) |entry| { |
| | 2609 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index + base_id); |
| 2567 | mem.writeIntLittle(u32, &buf, symtab_idx); | 2610 | mem.writeIntLittle(u32, &buf, symtab_idx); |
| 2568 | try self.base.file.?.pwriteAll(&buf, off); | 2611 | try self.base.file.?.pwriteAll(&buf, off); |
| 2569 | off += @sizeOf(u32); | 2612 | off += @sizeOf(u32); |
| 2570 | dysymtab.nindirectsyms += 1; | 2613 | dysymtab.nindirectsyms += 1; |
| 2571 | idx += 1; | | |
| 2572 | } | 2614 | } |
| 2573 | | 2615 | |
| 2574 | la.reserved1 = got.reserved1 + 1; | 2616 | la.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len); |
| 2575 | for (self.undef_symbols.items) |sym, i| { | 2617 | for (self.extern_lazy_symbols.items()) |entry| { |
| 2576 | if (i == self.dyld_stub_binder_index.?) { | 2618 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index); |
| 2577 | continue; | | |
| 2578 | } | | |
| 2579 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); | | |
| 2580 | mem.writeIntLittle(u32, &buf, symtab_idx); | 2619 | mem.writeIntLittle(u32, &buf, symtab_idx); |
| 2581 | try self.base.file.?.pwriteAll(&buf, off); | 2620 | try self.base.file.?.pwriteAll(&buf, off); |
| 2582 | off += @sizeOf(u32); | 2621 | off += @sizeOf(u32); |
| 2583 | dysymtab.nindirectsyms += 1; | 2622 | dysymtab.nindirectsyms += 1; |
| 2584 | idx += 1; | | |
| 2585 | } | 2623 | } |
| 2586 | } | 2624 | } |
| 2587 | | 2625 | |
| ... | @@ -2689,12 +2727,19 @@ fn writeRebaseInfoTable(self: *MachO) !void { | ... | @@ -2689,12 +2727,19 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2689 | const tracy = trace(@src()); | 2727 | const tracy = trace(@src()); |
| 2690 | defer tracy.end(); | 2728 | defer tracy.end(); |
| 2691 | | 2729 | |
| 2692 | const size = try self.rebase_info_table.calcSize(); | 2730 | var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_lazy_symbols.items().len); |
| | 2731 | defer self.base.allocator.free(symbols); |
| | 2732 | |
| | 2733 | for (self.extern_lazy_symbols.items()) |*entry, i| { |
| | 2734 | symbols[i] = &entry.value; |
| | 2735 | } |
| | 2736 | |
| | 2737 | const size = try rebaseInfoSize(symbols); |
| 2693 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 2738 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2694 | defer self.base.allocator.free(buffer); | 2739 | defer self.base.allocator.free(buffer); |
| 2695 | | 2740 | |
| 2696 | var stream = std.io.fixedBufferStream(buffer); | 2741 | var stream = std.io.fixedBufferStream(buffer); |
| 2697 | try self.rebase_info_table.write(stream.writer()); | 2742 | try writeRebaseInfo(symbols, stream.writer()); |
| 2698 | | 2743 | |
| 2699 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 2744 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2700 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 2745 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| ... | @@ -2720,12 +2765,19 @@ fn writeBindingInfoTable(self: *MachO) !void { | ... | @@ -2720,12 +2765,19 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2720 | const tracy = trace(@src()); | 2765 | const tracy = trace(@src()); |
| 2721 | defer tracy.end(); | 2766 | defer tracy.end(); |
| 2722 | | 2767 | |
| 2723 | const size = try self.binding_info_table.calcSize(); | 2768 | var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_nonlazy_symbols.items().len); |
| | 2769 | defer self.base.allocator.free(symbols); |
| | 2770 | |
| | 2771 | for (self.extern_nonlazy_symbols.items()) |*entry, i| { |
| | 2772 | symbols[i] = &entry.value; |
| | 2773 | } |
| | 2774 | |
| | 2775 | const size = try bindInfoSize(symbols); |
| 2724 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 2776 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2725 | defer self.base.allocator.free(buffer); | 2777 | defer self.base.allocator.free(buffer); |
| 2726 | | 2778 | |
| 2727 | var stream = std.io.fixedBufferStream(buffer); | 2779 | var stream = std.io.fixedBufferStream(buffer); |
| 2728 | try self.binding_info_table.write(stream.writer()); | 2780 | try writeBindInfo(symbols, stream.writer()); |
| 2729 | | 2781 | |
| 2730 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 2782 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2731 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 2783 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| ... | @@ -2748,12 +2800,19 @@ fn writeBindingInfoTable(self: *MachO) !void { | ... | @@ -2748,12 +2800,19 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2748 | fn writeLazyBindingInfoTable(self: *MachO) !void { | 2800 | fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2749 | if (!self.lazy_binding_info_dirty) return; | 2801 | if (!self.lazy_binding_info_dirty) return; |
| 2750 | | 2802 | |
| 2751 | const size = try self.lazy_binding_info_table.calcSize(); | 2803 | var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_lazy_symbols.items().len); |
| | 2804 | defer self.base.allocator.free(symbols); |
| | 2805 | |
| | 2806 | for (self.extern_lazy_symbols.items()) |*entry, i| { |
| | 2807 | symbols[i] = &entry.value; |
| | 2808 | } |
| | 2809 | |
| | 2810 | const size = try lazyBindInfoSize(symbols); |
| 2752 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 2811 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2753 | defer self.base.allocator.free(buffer); | 2812 | defer self.base.allocator.free(buffer); |
| 2754 | | 2813 | |
| 2755 | var stream = std.io.fixedBufferStream(buffer); | 2814 | var stream = std.io.fixedBufferStream(buffer); |
| 2756 | try self.lazy_binding_info_table.write(stream.writer()); | 2815 | try writeLazyBindInfo(symbols, stream.writer()); |
| 2757 | | 2816 | |
| 2758 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 2817 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2759 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 2818 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| ... | @@ -3001,7 +3060,7 @@ fn parseBindingInfoTable(self: *MachO) !void { | ... | @@ -3001,7 +3060,7 @@ fn parseBindingInfoTable(self: *MachO) !void { |
| 3001 | assert(nread == buffer.len); | 3060 | assert(nread == buffer.len); |
| 3002 | | 3061 | |
| 3003 | var stream = std.io.fixedBufferStream(buffer); | 3062 | var stream = std.io.fixedBufferStream(buffer); |
| 3004 | try self.binding_info_table.read(stream.reader(), self.base.allocator); | 3063 | // try self.binding_info_table.read(stream.reader(), self.base.allocator); |
| 3005 | } | 3064 | } |
| 3006 | | 3065 | |
| 3007 | fn parseLazyBindingInfoTable(self: *MachO) !void { | 3066 | fn parseLazyBindingInfoTable(self: *MachO) !void { |
| ... | @@ -3012,5 +3071,5 @@ fn parseLazyBindingInfoTable(self: *MachO) !void { | ... | @@ -3012,5 +3071,5 @@ fn parseLazyBindingInfoTable(self: *MachO) !void { |
| 3012 | assert(nread == buffer.len); | 3071 | assert(nread == buffer.len); |
| 3013 | | 3072 | |
| 3014 | var stream = std.io.fixedBufferStream(buffer); | 3073 | var stream = std.io.fixedBufferStream(buffer); |
| 3015 | try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator); | 3074 | // try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator); |
| 3016 | } | 3075 | } |