| ... | ... | @@ -11,6 +11,7 @@ const codegen = @import("../codegen.zig"); |
| 11 | 11 | const aarch64 = @import("../codegen/aarch64.zig"); |
| 12 | 12 | const math = std.math; |
| 13 | 13 | const mem = std.mem; |
| 14 | const meta = std.meta; |
| 14 | 15 | |
| 15 | 16 | const bind = @import("MachO/bind.zig"); |
| 16 | 17 | const trace = @import("../tracy.zig").trace; |
| ... | ... | @@ -87,14 +88,12 @@ code_signature_cmd_index: ?u16 = null, |
| 87 | 88 | |
| 88 | 89 | /// Index into __TEXT,__text section. |
| 89 | 90 | text_section_index: ?u16 = null, |
| 90 | | /// Index into __TEXT,__ziggot section. |
| 91 | | got_section_index: ?u16 = null, |
| 92 | 91 | /// Index into __TEXT,__stubs section. |
| 93 | 92 | stubs_section_index: ?u16 = null, |
| 94 | 93 | /// Index into __TEXT,__stub_helper section. |
| 95 | 94 | stub_helper_section_index: ?u16 = null, |
| 96 | 95 | /// Index into __DATA_CONST,__got section. |
| 97 | | data_got_section_index: ?u16 = null, |
| 96 | got_section_index: ?u16 = null, |
| 98 | 97 | /// Index into __DATA,__la_symbol_ptr section. |
| 99 | 98 | la_symbol_ptr_section_index: ?u16 = null, |
| 100 | 99 | /// Index into __DATA,__data section. |
| ... | ... | @@ -122,8 +121,8 @@ stub_helper_stubs_start_off: ?u64 = null, |
| 122 | 121 | string_table: std.ArrayListUnmanaged(u8) = .{}, |
| 123 | 122 | string_table_directory: std.StringHashMapUnmanaged(u32) = .{}, |
| 124 | 123 | |
| 125 | | /// Table of trampolines to the actual symbols in __text section. |
| 126 | | offset_table: std.ArrayListUnmanaged(u64) = .{}, |
| 124 | /// Table of GOT entries. |
| 125 | offset_table: std.ArrayListUnmanaged(GOTEntry) = .{}, |
| 127 | 126 | |
| 128 | 127 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 129 | 128 | |
| ... | ... | @@ -154,14 +153,19 @@ string_table_needs_relocation: bool = false, |
| 154 | 153 | /// allocate a fresh text block, which will have ideal capacity, and then grow it |
| 155 | 154 | /// by 1 byte. It will then have -1 overcapacity. |
| 156 | 155 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 156 | |
| 157 | 157 | /// Pointer to the last allocated text block |
| 158 | 158 | last_text_block: ?*TextBlock = null, |
| 159 | |
| 159 | 160 | /// A list of all PIE fixups required for this run of the linker. |
| 160 | 161 | /// Warning, this is currently NOT thread-safe. See the TODO below. |
| 161 | 162 | /// TODO Move this list inside `updateDecl` where it should be allocated |
| 162 | 163 | /// prior to calling `generateSymbol`, and then immediately deallocated |
| 163 | 164 | /// rather than sitting in the global scope. |
| 164 | | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 165 | /// TODO We should also rewrite this using generic relocations common to all |
| 166 | /// backends. |
| 167 | pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{}, |
| 168 | |
| 165 | 169 | /// A list of all stub (extern decls) fixups required for this run of the linker. |
| 166 | 170 | /// Warning, this is currently NOT thread-safe. See the TODO below. |
| 167 | 171 | /// TODO Move this list inside `updateDecl` where it should be allocated |
| ... | ... | @@ -169,6 +173,22 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 169 | 173 | /// rather than sitting in the global scope. |
| 170 | 174 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, |
| 171 | 175 | |
| 176 | pub const GOTEntry = struct { |
| 177 | /// GOT entry can either be a local pointer or an extern (nonlazy) import. |
| 178 | kind: enum { |
| 179 | Local, |
| 180 | Extern, |
| 181 | }, |
| 182 | |
| 183 | /// Id to the macho.nlist_64 from the respective table: either locals or nonlazy imports. |
| 184 | /// TODO I'm more and more inclined to just manage a single, max two symbol tables |
| 185 | /// rather than 4 as we currently do, but I'll follow up in the future PR. |
| 186 | symbol: u32, |
| 187 | |
| 188 | /// Index of this entry in the GOT. |
| 189 | index: u32, |
| 190 | }; |
| 191 | |
| 172 | 192 | pub const Import = struct { |
| 173 | 193 | /// MachO symbol table entry. |
| 174 | 194 | symbol: macho.nlist_64, |
| ... | ... | @@ -180,14 +200,15 @@ pub const Import = struct { |
| 180 | 200 | index: u32, |
| 181 | 201 | }; |
| 182 | 202 | |
| 183 | | pub const PieFixup = struct { |
| 184 | | /// Target address we wanted to address in absolute terms. |
| 185 | | address: u64, |
| 186 | | /// Where in the byte stream we should perform the fixup. |
| 187 | | start: usize, |
| 188 | | /// The length of the byte stream. For x86_64, this will be |
| 189 | | /// variable. For aarch64, it will be fixed at 4 bytes. |
| 190 | | len: usize, |
| 203 | pub const PIEFixup = struct { |
| 204 | /// Target VM address of this relocation. |
| 205 | target_addr: u64, |
| 206 | |
| 207 | /// Offset within the byte stream. |
| 208 | offset: usize, |
| 209 | |
| 210 | /// Size of the relocation. |
| 211 | size: usize, |
| 191 | 212 | }; |
| 192 | 213 | |
| 193 | 214 | pub const StubFixup = struct { |
| ... | ... | @@ -1132,11 +1153,14 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 1132 | 1153 | } |
| 1133 | 1154 | |
| 1134 | 1155 | if (self.offset_table_free_list.popOrNull()) |i| { |
| 1156 | log.debug("reusing offset table entry index {d} for {s}", .{ i, decl.name }); |
| 1135 | 1157 | decl.link.macho.offset_table_index = i; |
| 1136 | 1158 | } else { |
| 1159 | log.debug("allocating offset table entry index {d} for {s}", .{ self.offset_table.items.len, decl.name }); |
| 1137 | 1160 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); |
| 1138 | 1161 | _ = self.offset_table.addOneAssumeCapacity(); |
| 1139 | 1162 | self.offset_table_count_dirty = true; |
| 1163 | self.rebase_info_dirty = true; |
| 1140 | 1164 | } |
| 1141 | 1165 | |
| 1142 | 1166 | self.locals.items[decl.link.macho.local_sym_index] = .{ |
| ... | ... | @@ -1146,7 +1170,11 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 1146 | 1170 | .n_desc = 0, |
| 1147 | 1171 | .n_value = 0, |
| 1148 | 1172 | }; |
| 1149 | | self.offset_table.items[decl.link.macho.offset_table_index] = 0; |
| 1173 | self.offset_table.items[decl.link.macho.offset_table_index] = .{ |
| 1174 | .kind = .Local, |
| 1175 | .symbol = decl.link.macho.local_sym_index, |
| 1176 | .index = decl.link.macho.offset_table_index, |
| 1177 | }; |
| 1150 | 1178 | } |
| 1151 | 1179 | |
| 1152 | 1180 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| ... | ... | @@ -1189,8 +1217,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1189 | 1217 | .externally_managed => |x| x, |
| 1190 | 1218 | .appended => code_buffer.items, |
| 1191 | 1219 | .fail => |em| { |
| 1192 | | // Clear any PIE fixups and stub fixups for this decl. |
| 1220 | // Clear any PIE fixups for this decl. |
| 1193 | 1221 | self.pie_fixups.shrinkRetainingCapacity(0); |
| 1222 | // Clear any stub fixups for this decl. |
| 1194 | 1223 | self.stub_fixups.shrinkRetainingCapacity(0); |
| 1195 | 1224 | decl.analysis = .codegen_failure; |
| 1196 | 1225 | try module.failed_decls.put(module.gpa, decl, em); |
| ... | ... | @@ -1209,9 +1238,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1209 | 1238 | const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment); |
| 1210 | 1239 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr }); |
| 1211 | 1240 | if (vaddr != symbol.n_value) { |
| 1212 | | symbol.n_value = vaddr; |
| 1213 | 1241 | log.debug(" (writing new offset table entry)", .{}); |
| 1214 | | self.offset_table.items[decl.link.macho.offset_table_index] = vaddr; |
| 1242 | self.offset_table.items[decl.link.macho.offset_table_index] = .{ |
| 1243 | .kind = .Local, |
| 1244 | .symbol = decl.link.macho.local_sym_index, |
| 1245 | .index = decl.link.macho.offset_table_index, |
| 1246 | }; |
| 1215 | 1247 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1216 | 1248 | } |
| 1217 | 1249 | } else if (code.len < decl.link.macho.size) { |
| ... | ... | @@ -1240,7 +1272,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1240 | 1272 | .n_desc = 0, |
| 1241 | 1273 | .n_value = addr, |
| 1242 | 1274 | }; |
| 1243 | | self.offset_table.items[decl.link.macho.offset_table_index] = addr; |
| 1275 | self.offset_table.items[decl.link.macho.offset_table_index] = .{ |
| 1276 | .kind = .Local, |
| 1277 | .symbol = decl.link.macho.local_sym_index, |
| 1278 | .index = decl.link.macho.offset_table_index, |
| 1279 | }; |
| 1244 | 1280 | |
| 1245 | 1281 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); |
| 1246 | 1282 | if (self.d_sym) |*ds| |
| ... | ... | @@ -1248,30 +1284,48 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1248 | 1284 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1249 | 1285 | } |
| 1250 | 1286 | |
| 1251 | | // Perform PIE fixups (if any) |
| 1252 | | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1253 | | const got_section = text_segment.sections.items[self.got_section_index.?]; |
| 1287 | // Calculate displacements to target addr (if any). |
| 1254 | 1288 | while (self.pie_fixups.popOrNull()) |fixup| { |
| 1255 | | const target_addr = fixup.address; |
| 1256 | | const this_addr = symbol.n_value + fixup.start; |
| 1289 | assert(fixup.size == 4); |
| 1290 | const this_addr = symbol.n_value + fixup.offset; |
| 1291 | const target_addr = fixup.target_addr; |
| 1292 | |
| 1257 | 1293 | switch (self.base.options.target.cpu.arch) { |
| 1258 | 1294 | .x86_64 => { |
| 1259 | | assert(target_addr >= this_addr + fixup.len); |
| 1260 | | const displacement = try math.cast(u32, target_addr - this_addr - fixup.len); |
| 1261 | | var placeholder = code_buffer.items[fixup.start + fixup.len - @sizeOf(u32) ..][0..@sizeOf(u32)]; |
| 1262 | | mem.writeIntSliceLittle(u32, placeholder, displacement); |
| 1295 | const displacement = try math.cast(u32, target_addr - this_addr - 4); |
| 1296 | mem.writeIntLittle(u32, code_buffer.items[fixup.offset..][0..4], displacement); |
| 1263 | 1297 | }, |
| 1264 | 1298 | .aarch64 => { |
| 1265 | | assert(target_addr >= this_addr); |
| 1266 | | const displacement = try math.cast(u27, target_addr - this_addr); |
| 1267 | | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; |
| 1268 | | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.b(@as(i28, displacement)).toU32()); |
| 1299 | // TODO optimize instruction based on jump length (use ldr(literal) + nop if possible). |
| 1300 | { |
| 1301 | const inst = code_buffer.items[fixup.offset..][0..4]; |
| 1302 | var parsed = mem.bytesAsValue(meta.TagPayload( |
| 1303 | aarch64.Instruction, |
| 1304 | aarch64.Instruction.PCRelativeAddress, |
| 1305 | ), inst); |
| 1306 | const this_page = @intCast(i32, this_addr >> 12); |
| 1307 | const target_page = @intCast(i32, target_addr >> 12); |
| 1308 | const pages = @bitCast(u21, @intCast(i21, target_page - this_page)); |
| 1309 | parsed.immhi = @truncate(u19, pages >> 2); |
| 1310 | parsed.immlo = @truncate(u2, pages); |
| 1311 | } |
| 1312 | { |
| 1313 | const inst = code_buffer.items[fixup.offset + 4 ..][0..4]; |
| 1314 | var parsed = mem.bytesAsValue(meta.TagPayload( |
| 1315 | aarch64.Instruction, |
| 1316 | aarch64.Instruction.LoadStoreRegister, |
| 1317 | ), inst); |
| 1318 | const narrowed = @truncate(u12, target_addr); |
| 1319 | const offset = try math.divExact(u12, narrowed, 8); |
| 1320 | parsed.offset = offset; |
| 1321 | } |
| 1269 | 1322 | }, |
| 1270 | 1323 | else => unreachable, // unsupported target architecture |
| 1271 | 1324 | } |
| 1272 | 1325 | } |
| 1273 | 1326 | |
| 1274 | 1327 | // Resolve stubs (if any) |
| 1328 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1275 | 1329 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |
| 1276 | 1330 | for (self.stub_fixups.items) |fixup| { |
| 1277 | 1331 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; |
| ... | ... | @@ -1561,39 +1615,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1561 | 1615 | self.header_dirty = true; |
| 1562 | 1616 | self.load_commands_dirty = true; |
| 1563 | 1617 | } |
| 1564 | | if (self.got_section_index == null) { |
| 1565 | | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1566 | | self.got_section_index = @intCast(u16, text_segment.sections.items.len); |
| 1567 | | |
| 1568 | | const alignment: u2 = switch (self.base.options.target.cpu.arch) { |
| 1569 | | .x86_64 => 0, |
| 1570 | | .aarch64 => 2, |
| 1571 | | else => unreachable, // unhandled architecture type |
| 1572 | | }; |
| 1573 | | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 1574 | | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1575 | | const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad); |
| 1576 | | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. |
| 1577 | | |
| 1578 | | log.debug("found __ziggot section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 1579 | | |
| 1580 | | try text_segment.addSection(self.base.allocator, .{ |
| 1581 | | .sectname = makeStaticString("__ziggot"), |
| 1582 | | .segname = makeStaticString("__TEXT"), |
| 1583 | | .addr = text_segment.inner.vmaddr + off, |
| 1584 | | .size = needed_size, |
| 1585 | | .offset = @intCast(u32, off), |
| 1586 | | .@"align" = alignment, |
| 1587 | | .reloff = 0, |
| 1588 | | .nreloc = 0, |
| 1589 | | .flags = flags, |
| 1590 | | .reserved1 = 0, |
| 1591 | | .reserved2 = 0, |
| 1592 | | .reserved3 = 0, |
| 1593 | | }); |
| 1594 | | self.header_dirty = true; |
| 1595 | | self.load_commands_dirty = true; |
| 1596 | | } |
| 1597 | 1618 | if (self.stubs_section_index == null) { |
| 1598 | 1619 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1599 | 1620 | self.stubs_section_index = @intCast(u16, text_segment.sections.items.len); |
| ... | ... | @@ -1694,9 +1715,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1694 | 1715 | self.header_dirty = true; |
| 1695 | 1716 | self.load_commands_dirty = true; |
| 1696 | 1717 | } |
| 1697 | | if (self.data_got_section_index == null) { |
| 1718 | if (self.got_section_index == null) { |
| 1698 | 1719 | const dc_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 1699 | | self.data_got_section_index = @intCast(u16, dc_segment.sections.items.len); |
| 1720 | self.got_section_index = @intCast(u16, dc_segment.sections.items.len); |
| 1700 | 1721 | |
| 1701 | 1722 | const flags = macho.S_NON_LAZY_SYMBOL_POINTERS; |
| 1702 | 1723 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| ... | ... | @@ -2083,6 +2104,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2083 | 2104 | .dylib_ordinal = 1, // TODO this is currently hardcoded. |
| 2084 | 2105 | .index = index, |
| 2085 | 2106 | }); |
| 2107 | const off_index = @intCast(u32, self.offset_table.items.len); |
| 2108 | try self.offset_table.append(self.base.allocator, .{ |
| 2109 | .kind = .Extern, |
| 2110 | .symbol = index, |
| 2111 | .index = off_index, |
| 2112 | }); |
| 2113 | try self.writeOffsetTableEntry(off_index); |
| 2086 | 2114 | self.binding_info_dirty = true; |
| 2087 | 2115 | } |
| 2088 | 2116 | if (self.stub_helper_stubs_start_off == null) { |
| ... | ... | @@ -2412,41 +2440,29 @@ fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, sta |
| 2412 | 2440 | } |
| 2413 | 2441 | |
| 2414 | 2442 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 2415 | | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2416 | | const sect = &text_segment.sections.items[self.got_section_index.?]; |
| 2443 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2444 | const sect = &seg.sections.items[self.got_section_index.?]; |
| 2417 | 2445 | const off = sect.offset + @sizeOf(u64) * index; |
| 2418 | | const vmaddr = sect.addr + @sizeOf(u64) * index; |
| 2419 | 2446 | |
| 2420 | 2447 | if (self.offset_table_count_dirty) { |
| 2421 | 2448 | // TODO relocate. |
| 2422 | 2449 | self.offset_table_count_dirty = false; |
| 2423 | 2450 | } |
| 2424 | 2451 | |
| 2425 | | var code: [8]u8 = undefined; |
| 2426 | | switch (self.base.options.target.cpu.arch) { |
| 2427 | | .x86_64 => { |
| 2428 | | const pos_symbol_off = try math.cast(u31, vmaddr - self.offset_table.items[index] + 7); |
| 2429 | | const symbol_off = @bitCast(u32, @as(i32, pos_symbol_off) * -1); |
| 2430 | | // lea %rax, [rip - disp] |
| 2431 | | code[0] = 0x48; |
| 2432 | | code[1] = 0x8D; |
| 2433 | | code[2] = 0x5; |
| 2434 | | mem.writeIntLittle(u32, code[3..7], symbol_off); |
| 2435 | | // ret |
| 2436 | | code[7] = 0xC3; |
| 2437 | | }, |
| 2438 | | .aarch64 => { |
| 2439 | | const pos_symbol_off = try math.cast(u20, vmaddr - self.offset_table.items[index]); |
| 2440 | | const symbol_off = @as(i21, pos_symbol_off) * -1; |
| 2441 | | // adr x0, #-disp |
| 2442 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x0, symbol_off).toU32()); |
| 2443 | | // ret x28 |
| 2444 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ret(.x28).toU32()); |
| 2445 | | }, |
| 2446 | | else => unreachable, // unsupported target architecture |
| 2447 | | } |
| 2448 | | log.debug("writing offset table entry 0x{x} at 0x{x}", .{ self.offset_table.items[index], off }); |
| 2449 | | try self.base.file.?.pwriteAll(&code, off); |
| 2452 | const got_entry = self.offset_table.items[index]; |
| 2453 | const sym = blk: { |
| 2454 | switch (got_entry.kind) { |
| 2455 | .Local => { |
| 2456 | break :blk self.locals.items[got_entry.symbol]; |
| 2457 | }, |
| 2458 | .Extern => { |
| 2459 | break :blk self.nonlazy_imports.items()[got_entry.symbol].value.symbol; |
| 2460 | }, |
| 2461 | } |
| 2462 | }; |
| 2463 | const sym_name = self.getString(sym.n_strx); |
| 2464 | log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{ off, sym.n_value, sym_name }); |
| 2465 | try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off); |
| 2450 | 2466 | } |
| 2451 | 2467 | |
| 2452 | 2468 | fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| ... | ... | @@ -2473,7 +2489,7 @@ fn writeStubHelperPreamble(self: *MachO) !void { |
| 2473 | 2489 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2474 | 2490 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| 2475 | 2491 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2476 | | const got = &data_const_segment.sections.items[self.data_got_section_index.?]; |
| 2492 | const got = &data_const_segment.sections.items[self.got_section_index.?]; |
| 2477 | 2493 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2478 | 2494 | const data = &data_segment.sections.items[self.data_section_index.?]; |
| 2479 | 2495 | |
| ... | ... | @@ -2813,15 +2829,15 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2813 | 2829 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2814 | 2830 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; |
| 2815 | 2831 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2816 | | const got = &data_const_seg.sections.items[self.data_got_section_index.?]; |
| 2832 | const got = &data_const_seg.sections.items[self.got_section_index.?]; |
| 2817 | 2833 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2818 | 2834 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 2819 | 2835 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 2820 | 2836 | |
| 2821 | 2837 | const lazy = self.lazy_imports.items(); |
| 2822 | | const nonlazy = self.nonlazy_imports.items(); |
| 2838 | const got_entries = self.offset_table.items; |
| 2823 | 2839 | const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff); |
| 2824 | | const nindirectsyms = @intCast(u32, lazy.len * 2 + nonlazy.len); |
| 2840 | const nindirectsyms = @intCast(u32, lazy.len * 2 + got_entries.len); |
| 2825 | 2841 | const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32)); |
| 2826 | 2842 | |
| 2827 | 2843 | if (needed_size > allocated_size) { |
| ... | ... | @@ -2847,12 +2863,19 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2847 | 2863 | |
| 2848 | 2864 | const base_id = @intCast(u32, lazy.len); |
| 2849 | 2865 | got.reserved1 = base_id; |
| 2850 | | for (nonlazy) |_, i| { |
| 2851 | | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id); |
| 2852 | | try writer.writeIntLittle(u32, symtab_idx); |
| 2866 | for (got_entries) |entry| { |
| 2867 | switch (entry.kind) { |
| 2868 | .Local => { |
| 2869 | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| 2870 | }, |
| 2871 | .Extern => { |
| 2872 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.index + base_id); |
| 2873 | try writer.writeIntLittle(u32, symtab_idx); |
| 2874 | }, |
| 2875 | } |
| 2853 | 2876 | } |
| 2854 | 2877 | |
| 2855 | | la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len); |
| 2878 | la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, got_entries.len); |
| 2856 | 2879 | for (lazy) |_, i| { |
| 2857 | 2880 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2858 | 2881 | try writer.writeIntLittle(u32, symtab_idx); |
| ... | ... | @@ -2973,12 +2996,27 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2973 | 2996 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 2974 | 2997 | defer pointers.deinit(); |
| 2975 | 2998 | |
| 2999 | if (self.got_section_index) |idx| { |
| 3000 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 3001 | const sect = seg.sections.items[idx]; |
| 3002 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 3003 | const segment_id = self.data_const_segment_cmd_index.?; |
| 3004 | |
| 3005 | for (self.offset_table.items) |entry| { |
| 3006 | if (entry.kind == .Extern) continue; |
| 3007 | try pointers.append(.{ |
| 3008 | .offset = base_offset + entry.index * @sizeOf(u64), |
| 3009 | .segment_id = segment_id, |
| 3010 | }); |
| 3011 | } |
| 3012 | } |
| 3013 | |
| 2976 | 3014 | if (self.la_symbol_ptr_section_index) |idx| { |
| 2977 | 3015 | try pointers.ensureCapacity(pointers.items.len + self.lazy_imports.items().len); |
| 2978 | 3016 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2979 | 3017 | const sect = seg.sections.items[idx]; |
| 2980 | 3018 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2981 | | const segment_id = @intCast(u16, self.data_segment_cmd_index.?); |
| 3019 | const segment_id = self.data_segment_cmd_index.?; |
| 2982 | 3020 | |
| 2983 | 3021 | for (self.lazy_imports.items()) |entry| { |
| 2984 | 3022 | pointers.appendAssumeCapacity(.{ |
| ... | ... | @@ -3024,19 +3062,20 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 3024 | 3062 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 3025 | 3063 | defer pointers.deinit(); |
| 3026 | 3064 | |
| 3027 | | if (self.data_got_section_index) |idx| { |
| 3028 | | try pointers.ensureCapacity(pointers.items.len + self.nonlazy_imports.items().len); |
| 3065 | if (self.got_section_index) |idx| { |
| 3029 | 3066 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 3030 | 3067 | const sect = seg.sections.items[idx]; |
| 3031 | 3068 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 3032 | 3069 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 3033 | 3070 | |
| 3034 | | for (self.nonlazy_imports.items()) |entry| { |
| 3035 | | pointers.appendAssumeCapacity(.{ |
| 3036 | | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 3071 | for (self.offset_table.items) |entry| { |
| 3072 | if (entry.kind == .Local) continue; |
| 3073 | const import = self.nonlazy_imports.items()[entry.symbol]; |
| 3074 | try pointers.append(.{ |
| 3075 | .offset = base_offset + entry.index * @sizeOf(u64), |
| 3037 | 3076 | .segment_id = segment_id, |
| 3038 | | .dylib_ordinal = entry.value.dylib_ordinal, |
| 3039 | | .name = entry.key, |
| 3077 | .dylib_ordinal = import.value.dylib_ordinal, |
| 3078 | .name = import.key, |
| 3040 | 3079 | }); |
| 3041 | 3080 | } |
| 3042 | 3081 | } |