| ... | ... | @@ -105,16 +105,17 @@ entry_addr: ?u64 = null, |
| 105 | 105 | /// Table of all local symbols |
| 106 | 106 | /// Internally references string table for names (which are optional). |
| 107 | 107 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 108 | | /// Table of all defined global symbols |
| 108 | /// Table of all global symbols |
| 109 | 109 | global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 110 | | /// Table of all undefined symbols |
| 111 | | undef_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 110 | /// Table of all extern nonlazy symbols, indexed by name. |
| 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 | 115 | local_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 114 | 116 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 115 | 117 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 116 | 118 | |
| 117 | | dyld_stub_binder_index: ?u16 = null, |
| 118 | 119 | stub_helper_stubs_start_off: ?u64 = null, |
| 119 | 120 | |
| 120 | 121 | /// Table of symbol names aka the string table. |
| ... | ... | @@ -123,13 +124,6 @@ string_table: std.ArrayListUnmanaged(u8) = .{}, |
| 123 | 124 | /// Table of trampolines to the actual symbols in __text section. |
| 124 | 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 | 127 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 134 | 128 | |
| 135 | 129 | offset_table_count_dirty: bool = false, |
| ... | ... | @@ -167,11 +161,10 @@ last_text_block: ?*TextBlock = null, |
| 167 | 161 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 168 | 162 | |
| 169 | 163 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, |
| 170 | | externs: std.StringHashMapUnmanaged(u32) = .{}, |
| 171 | 164 | |
| 172 | 165 | pub const StubFixup = struct { |
| 173 | 166 | symbol: u32, |
| 174 | | exists: bool, |
| 167 | already_defined: bool, |
| 175 | 168 | start: usize, |
| 176 | 169 | len: usize, |
| 177 | 170 | }; |
| ... | ... | @@ -920,42 +913,42 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 920 | 913 | return error.NoSymbolTableFound; |
| 921 | 914 | } |
| 922 | 915 | |
| 923 | | // Parse dyld info |
| 924 | | try self.parseBindingInfoTable(); |
| 925 | | try self.parseLazyBindingInfoTable(); |
| 916 | // // Parse dyld info |
| 917 | // try self.parseBindingInfoTable(); |
| 918 | // try self.parseLazyBindingInfoTable(); |
| 926 | 919 | |
| 927 | | // Update the dylib ordinals. |
| 928 | | self.binding_info_table.dylib_ordinal = next_ordinal; |
| 929 | | for (self.lazy_binding_info_table.symbols.items) |*symbol| { |
| 930 | | symbol.dylib_ordinal = next_ordinal; |
| 931 | | } |
| 920 | // // Update the dylib ordinals. |
| 921 | // self.binding_info_table.dylib_ordinal = next_ordinal; |
| 922 | // for (self.lazy_binding_info_table.symbols.items) |*symbol| { |
| 923 | // symbol.dylib_ordinal = next_ordinal; |
| 924 | // } |
| 932 | 925 | |
| 933 | | // Write updated dyld info. |
| 934 | | const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 935 | | { |
| 936 | | const size = try self.binding_info_table.calcSize(); |
| 937 | | assert(dyld_info.bind_size >= size); |
| 926 | // // Write updated dyld info. |
| 927 | // const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 928 | // { |
| 929 | // const size = try self.binding_info_table.calcSize(); |
| 930 | // assert(dyld_info.bind_size >= size); |
| 938 | 931 | |
| 939 | | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 940 | | defer self.base.allocator.free(buffer); |
| 932 | // var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 933 | // defer self.base.allocator.free(buffer); |
| 941 | 934 | |
| 942 | | var stream = std.io.fixedBufferStream(buffer); |
| 943 | | try self.binding_info_table.write(stream.writer()); |
| 935 | // var stream = std.io.fixedBufferStream(buffer); |
| 936 | // try self.binding_info_table.write(stream.writer()); |
| 944 | 937 | |
| 945 | | try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); |
| 946 | | } |
| 947 | | { |
| 948 | | const size = try self.lazy_binding_info_table.calcSize(); |
| 949 | | assert(dyld_info.lazy_bind_size >= size); |
| 938 | // try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); |
| 939 | // } |
| 940 | // { |
| 941 | // const size = try self.lazy_binding_info_table.calcSize(); |
| 942 | // assert(dyld_info.lazy_bind_size >= size); |
| 950 | 943 | |
| 951 | | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 952 | | defer self.base.allocator.free(buffer); |
| 944 | // var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 945 | // defer self.base.allocator.free(buffer); |
| 953 | 946 | |
| 954 | | var stream = std.io.fixedBufferStream(buffer); |
| 955 | | try self.lazy_binding_info_table.write(stream.writer()); |
| 947 | // var stream = std.io.fixedBufferStream(buffer); |
| 948 | // try self.lazy_binding_info_table.write(stream.writer()); |
| 956 | 949 | |
| 957 | | try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); |
| 958 | | } |
| 950 | // try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); |
| 951 | // } |
| 959 | 952 | |
| 960 | 953 | // Write updated load commands and the header |
| 961 | 954 | try self.writeLoadCommands(); |
| ... | ... | @@ -1037,14 +1030,13 @@ pub fn deinit(self: *MachO) void { |
| 1037 | 1030 | if (self.d_sym) |*ds| { |
| 1038 | 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 | 1033 | self.pie_fixups.deinit(self.base.allocator); |
| 1043 | 1034 | self.text_block_free_list.deinit(self.base.allocator); |
| 1044 | 1035 | self.offset_table.deinit(self.base.allocator); |
| 1045 | 1036 | self.offset_table_free_list.deinit(self.base.allocator); |
| 1046 | 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 | 1040 | self.global_symbols.deinit(self.base.allocator); |
| 1049 | 1041 | self.global_symbol_free_list.deinit(self.base.allocator); |
| 1050 | 1042 | self.local_symbols.deinit(self.base.allocator); |
| ... | ... | @@ -1261,59 +1253,28 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1261 | 1253 | } |
| 1262 | 1254 | |
| 1263 | 1255 | // Resolve stubs (if any) |
| 1264 | | 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.?]; |
| 1256 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |
| 1268 | 1257 | for (self.stub_fixups.items) |fixup| { |
| 1269 | | // TODO increment offset for stub writing |
| 1270 | 1258 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; |
| 1271 | 1259 | const text_addr = symbol.n_value + fixup.start; |
| 1272 | 1260 | const displacement = @intCast(u32, stub_addr - text_addr); |
| 1273 | 1261 | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; |
| 1274 | | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32()); |
| 1275 | | |
| 1276 | | if (!fixup.exists) { |
| 1277 | | const stub_off = self.stub_helper_stubs_start_off.? + fixup.symbol * 3 * @sizeOf(u32); |
| 1278 | | const end = stub_h.addr + stub_off - stub_h.offset; |
| 1279 | | var buf: [@sizeOf(u64)]u8 = undefined; |
| 1280 | | mem.writeIntLittle(u64, &buf, end); |
| 1281 | | try self.base.file.?.pwriteAll(&buf, la_ptr.offset + fixup.symbol * @sizeOf(u64)); |
| 1282 | | |
| 1283 | | const la_ptr_addr = la_ptr.addr + fixup.symbol * @sizeOf(u64); |
| 1284 | | const displacement2 = la_ptr_addr - stub_addr; |
| 1285 | | var ccode: [2 * @sizeOf(u32)]u8 = undefined; |
| 1286 | | mem.writeIntLittle(u32, ccode[0..4], aarch64.Instruction.ldr(.x16, .{ |
| 1287 | | .literal = @intCast(u19, displacement2 / 4), |
| 1288 | | }).toU32()); |
| 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 | | }); |
| 1262 | switch (self.base.options.target.cpu.arch) { |
| 1263 | .x86_64 => return error.TODOImplementStubFixupsForx86_64, |
| 1264 | .aarch64 => { |
| 1265 | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32()); |
| 1266 | }, |
| 1267 | else => unreachable, |
| 1268 | } |
| 1269 | if (!fixup.already_defined) { |
| 1270 | try self.writeStub(fixup.symbol); |
| 1271 | try self.writeStubInStubHelper(fixup.symbol); |
| 1272 | try self.writeLazySymbolPointer(fixup.symbol); |
| 1273 | |
| 1274 | const extern_sym = &self.extern_lazy_symbols.items()[fixup.symbol].value; |
| 1275 | extern_sym.segment = self.data_segment_cmd_index.?; |
| 1276 | extern_sym.offset = fixup.symbol * @sizeOf(u64); |
| 1305 | 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 | 1278 | self.lazy_binding_info_dirty = true; |
| 1318 | 1279 | } |
| 1319 | 1280 | } |
| ... | ... | @@ -2080,51 +2041,51 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2080 | 2041 | self.header_dirty = true; |
| 2081 | 2042 | self.load_commands_dirty = true; |
| 2082 | 2043 | } |
| 2083 | | if (self.dyld_stub_binder_index == null) { |
| 2084 | | self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len); |
| 2085 | | const name = try self.makeString("dyld_stub_binder"); |
| 2086 | | try self.undef_symbols.append(self.base.allocator, .{ |
| 2087 | | .n_strx = name, |
| 2088 | | .n_type = macho.N_UNDF | macho.N_EXT, |
| 2089 | | .n_sect = 0, |
| 2090 | | .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, |
| 2091 | | .n_value = 0, |
| 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, |
| 2044 | if (!self.extern_nonlazy_symbols.contains("dyld_stub_binder")) { |
| 2045 | const index = @intCast(u32, self.extern_nonlazy_symbols.items().len); |
| 2046 | const name = try std.fmt.allocPrint(self.base.allocator, "dyld_stub_binder", .{}); |
| 2047 | try self.extern_nonlazy_symbols.putNoClobber(self.base.allocator, name, .{ |
| 2048 | .name = name, |
| 2049 | .dylib_ordinal = 1, // TODO this is currently hardcoded. |
| 2050 | .index = index, |
| 2051 | .segment = self.data_const_segment_cmd_index.?, |
| 2052 | .offset = index * @sizeOf(u64), |
| 2102 | 2053 | }); |
| 2103 | 2054 | self.binding_info_dirty = true; |
| 2104 | 2055 | } |
| 2105 | 2056 | if (self.stub_helper_stubs_start_off == null) { |
| 2106 | | const text = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2107 | | const sh = &text.sections.items[self.stub_helper_section_index.?]; |
| 2108 | | const data = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2109 | | const data_data = &data.sections.items[self.data_section_index.?]; |
| 2110 | | const displacement = data_data.addr - sh.addr; |
| 2111 | | var code: [4 * @sizeOf(u32)]u8 = undefined; |
| 2112 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, @intCast(i21, displacement)).toU32()); |
| 2113 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.stp( |
| 2114 | | .x16, |
| 2115 | | .x17, |
| 2116 | | aarch64.Register.sp, |
| 2117 | | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), |
| 2118 | | ).toU32()); |
| 2119 | | const dc = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2120 | | const got = &dc.sections.items[self.data_got_section_index.?]; |
| 2121 | | const displacement2 = got.addr - sh.addr - 2 * @sizeOf(u32); |
| 2122 | | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.ldr(.x16, .{ |
| 2123 | | .literal = @intCast(u19, displacement2 / 4), |
| 2124 | | }).toU32()); |
| 2125 | | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.br(.x16).toU32()); |
| 2126 | | self.stub_helper_stubs_start_off = sh.offset + 4 * @sizeOf(u32); |
| 2127 | | try self.base.file.?.pwriteAll(&code, sh.offset); |
| 2057 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2058 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| 2059 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2060 | const data = &data_segment.sections.items[self.data_section_index.?]; |
| 2061 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2062 | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; |
| 2063 | switch (self.base.options.target.cpu.arch) { |
| 2064 | .x86_64 => return error.TODOImplementStubHelperForX86_64, |
| 2065 | .aarch64 => { |
| 2066 | var code: [4 * @sizeOf(u32)]u8 = undefined; |
| 2067 | { |
| 2068 | const displacement = data.addr - stub_helper.addr; |
| 2069 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, @intCast(i21, displacement)).toU32()); |
| 2070 | } |
| 2071 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.stp( |
| 2072 | .x16, |
| 2073 | .x17, |
| 2074 | aarch64.Register.sp, |
| 2075 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), |
| 2076 | ).toU32()); |
| 2077 | { |
| 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 | 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 | 2486 | fn relocateSymbolTable(self: *MachO) !void { |
| 2464 | 2487 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2465 | 2488 | const nlocals = self.local_symbols.items.len; |
| 2466 | 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 | 2491 | const nsyms = nlocals + nglobals + nundefs; |
| 2469 | 2492 | |
| 2470 | 2493 | if (symtab.nsyms < nsyms) { |
| ... | ... | @@ -2509,7 +2532,31 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2509 | 2532 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2510 | 2533 | const nlocals = self.local_symbols.items.len; |
| 2511 | 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 | 2561 | const locals_off = symtab.symoff; |
| 2515 | 2562 | const locals_size = nlocals * @sizeOf(macho.nlist_64); |
| ... | ... | @@ -2521,8 +2568,8 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2521 | 2568 | |
| 2522 | 2569 | const undefs_off = globals_off + globals_size; |
| 2523 | 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 }); |
| 2525 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off); |
| 2571 | log.debug("writing extern symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); |
| 2572 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off); |
| 2526 | 2573 | |
| 2527 | 2574 | // Update dynamic symbol table. |
| 2528 | 2575 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| ... | ... | @@ -2546,42 +2593,33 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2546 | 2593 | |
| 2547 | 2594 | var buf: [@sizeOf(u32)]u8 = undefined; |
| 2548 | 2595 | var off = dysymtab.indirectsymoff; |
| 2549 | | var idx: u32 = 0; |
| 2550 | 2596 | |
| 2551 | 2597 | stubs.reserved1 = 0; |
| 2552 | | for (self.undef_symbols.items) |sym, i| { |
| 2553 | | if (i == self.dyld_stub_binder_index.?) { |
| 2554 | | continue; |
| 2555 | | } |
| 2556 | | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2598 | for (self.extern_lazy_symbols.items()) |entry| { |
| 2599 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index); |
| 2557 | 2600 | mem.writeIntLittle(u32, &buf, symtab_idx); |
| 2558 | 2601 | try self.base.file.?.pwriteAll(&buf, off); |
| 2559 | 2602 | off += @sizeOf(u32); |
| 2560 | 2603 | dysymtab.nindirectsyms += 1; |
| 2561 | | idx += 1; |
| 2562 | 2604 | } |
| 2563 | 2605 | |
| 2564 | | got.reserved1 = @intCast(u32, self.undef_symbols.items.len - 1); |
| 2565 | | if (self.dyld_stub_binder_index) |i| { |
| 2566 | | const symtab_idx = i + dysymtab.iundefsym; |
| 2606 | const base_id = @intCast(u32, self.extern_lazy_symbols.items().len); |
| 2607 | got.reserved1 = base_id; |
| 2608 | for (self.extern_nonlazy_symbols.items()) |entry| { |
| 2609 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index + base_id); |
| 2567 | 2610 | mem.writeIntLittle(u32, &buf, symtab_idx); |
| 2568 | 2611 | try self.base.file.?.pwriteAll(&buf, off); |
| 2569 | 2612 | off += @sizeOf(u32); |
| 2570 | 2613 | dysymtab.nindirectsyms += 1; |
| 2571 | | idx += 1; |
| 2572 | 2614 | } |
| 2573 | 2615 | |
| 2574 | | la.reserved1 = got.reserved1 + 1; |
| 2575 | | for (self.undef_symbols.items) |sym, i| { |
| 2576 | | if (i == self.dyld_stub_binder_index.?) { |
| 2577 | | continue; |
| 2578 | | } |
| 2579 | | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2616 | la.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len); |
| 2617 | for (self.extern_lazy_symbols.items()) |entry| { |
| 2618 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index); |
| 2580 | 2619 | mem.writeIntLittle(u32, &buf, symtab_idx); |
| 2581 | 2620 | try self.base.file.?.pwriteAll(&buf, off); |
| 2582 | 2621 | off += @sizeOf(u32); |
| 2583 | 2622 | dysymtab.nindirectsyms += 1; |
| 2584 | | idx += 1; |
| 2585 | 2623 | } |
| 2586 | 2624 | } |
| 2587 | 2625 | |
| ... | ... | @@ -2689,12 +2727,19 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2689 | 2727 | const tracy = trace(@src()); |
| 2690 | 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 | 2738 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2694 | 2739 | defer self.base.allocator.free(buffer); |
| 2695 | 2740 | |
| 2696 | 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 | 2744 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2700 | 2745 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| ... | ... | @@ -2720,12 +2765,19 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2720 | 2765 | const tracy = trace(@src()); |
| 2721 | 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 | 2776 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2725 | 2777 | defer self.base.allocator.free(buffer); |
| 2726 | 2778 | |
| 2727 | 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 | 2782 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2731 | 2783 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| ... | ... | @@ -2748,12 +2800,19 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2748 | 2800 | fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2749 | 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 | 2811 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2753 | 2812 | defer self.base.allocator.free(buffer); |
| 2754 | 2813 | |
| 2755 | 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 | 2817 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2759 | 2818 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| ... | ... | @@ -3001,7 +3060,7 @@ fn parseBindingInfoTable(self: *MachO) !void { |
| 3001 | 3060 | assert(nread == buffer.len); |
| 3002 | 3061 | |
| 3003 | 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 | 3066 | fn parseLazyBindingInfoTable(self: *MachO) !void { |
| ... | ... | @@ -3012,5 +3071,5 @@ fn parseLazyBindingInfoTable(self: *MachO) !void { |
| 3012 | 3071 | assert(nread == buffer.len); |
| 3013 | 3072 | |
| 3014 | 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 | } |