| ... | @@ -11,6 +11,7 @@ const codegen = @import("../codegen.zig"); | ... | @@ -11,6 +11,7 @@ const codegen = @import("../codegen.zig"); |
| 11 | const aarch64 = @import("../codegen/aarch64.zig"); | 11 | const aarch64 = @import("../codegen/aarch64.zig"); |
| 12 | const math = std.math; | 12 | const math = std.math; |
| 13 | const mem = std.mem; | 13 | const mem = std.mem; |
| | 14 | const meta = std.meta; |
| 14 | | 15 | |
| 15 | const bind = @import("MachO/bind.zig"); | 16 | const bind = @import("MachO/bind.zig"); |
| 16 | const trace = @import("../tracy.zig").trace; | 17 | const trace = @import("../tracy.zig").trace; |
| ... | @@ -87,14 +88,12 @@ code_signature_cmd_index: ?u16 = null, | ... | @@ -87,14 +88,12 @@ code_signature_cmd_index: ?u16 = null, |
| 87 | | 88 | |
| 88 | /// Index into __TEXT,__text section. | 89 | /// Index into __TEXT,__text section. |
| 89 | text_section_index: ?u16 = null, | 90 | text_section_index: ?u16 = null, |
| 90 | /// Index into __TEXT,__ziggot section. | | |
| 91 | got_section_index: ?u16 = null, | | |
| 92 | /// Index into __TEXT,__stubs section. | 91 | /// Index into __TEXT,__stubs section. |
| 93 | stubs_section_index: ?u16 = null, | 92 | stubs_section_index: ?u16 = null, |
| 94 | /// Index into __TEXT,__stub_helper section. | 93 | /// Index into __TEXT,__stub_helper section. |
| 95 | stub_helper_section_index: ?u16 = null, | 94 | stub_helper_section_index: ?u16 = null, |
| 96 | /// Index into __DATA_CONST,__got section. | 95 | /// Index into __DATA_CONST,__got section. |
| 97 | data_got_section_index: ?u16 = null, | 96 | got_section_index: ?u16 = null, |
| 98 | /// Index into __DATA,__la_symbol_ptr section. | 97 | /// Index into __DATA,__la_symbol_ptr section. |
| 99 | la_symbol_ptr_section_index: ?u16 = null, | 98 | la_symbol_ptr_section_index: ?u16 = null, |
| 100 | /// Index into __DATA,__data section. | 99 | /// Index into __DATA,__data section. |
| ... | @@ -122,8 +121,8 @@ stub_helper_stubs_start_off: ?u64 = null, | ... | @@ -122,8 +121,8 @@ stub_helper_stubs_start_off: ?u64 = null, |
| 122 | string_table: std.ArrayListUnmanaged(u8) = .{}, | 121 | string_table: std.ArrayListUnmanaged(u8) = .{}, |
| 123 | string_table_directory: std.StringHashMapUnmanaged(u32) = .{}, | 122 | string_table_directory: std.StringHashMapUnmanaged(u32) = .{}, |
| 124 | | 123 | |
| 125 | /// Table of trampolines to the actual symbols in __text section. | 124 | /// Table of GOT entries. |
| 126 | offset_table: std.ArrayListUnmanaged(u64) = .{}, | 125 | offset_table: std.ArrayListUnmanaged(GOTEntry) = .{}, |
| 127 | | 126 | |
| 128 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 127 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 129 | | 128 | |
| ... | @@ -154,14 +153,19 @@ string_table_needs_relocation: bool = false, | ... | @@ -154,14 +153,19 @@ string_table_needs_relocation: bool = false, |
| 154 | /// allocate a fresh text block, which will have ideal capacity, and then grow it | 153 | /// allocate a fresh text block, which will have ideal capacity, and then grow it |
| 155 | /// by 1 byte. It will then have -1 overcapacity. | 154 | /// by 1 byte. It will then have -1 overcapacity. |
| 156 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, | 155 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| | 156 | |
| 157 | /// Pointer to the last allocated text block | 157 | /// Pointer to the last allocated text block |
| 158 | last_text_block: ?*TextBlock = null, | 158 | last_text_block: ?*TextBlock = null, |
| | 159 | |
| 159 | /// A list of all PIE fixups required for this run of the linker. | 160 | /// A list of all PIE fixups required for this run of the linker. |
| 160 | /// Warning, this is currently NOT thread-safe. See the TODO below. | 161 | /// Warning, this is currently NOT thread-safe. See the TODO below. |
| 161 | /// TODO Move this list inside `updateDecl` where it should be allocated | 162 | /// TODO Move this list inside `updateDecl` where it should be allocated |
| 162 | /// prior to calling `generateSymbol`, and then immediately deallocated | 163 | /// prior to calling `generateSymbol`, and then immediately deallocated |
| 163 | /// rather than sitting in the global scope. | 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 | /// A list of all stub (extern decls) fixups required for this run of the linker. | 169 | /// A list of all stub (extern decls) fixups required for this run of the linker. |
| 166 | /// Warning, this is currently NOT thread-safe. See the TODO below. | 170 | /// Warning, this is currently NOT thread-safe. See the TODO below. |
| 167 | /// TODO Move this list inside `updateDecl` where it should be allocated | 171 | /// TODO Move this list inside `updateDecl` where it should be allocated |
| ... | @@ -169,6 +173,22 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, | ... | @@ -169,6 +173,22 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 169 | /// rather than sitting in the global scope. | 173 | /// rather than sitting in the global scope. |
| 170 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, | 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 | pub const Import = struct { | 192 | pub const Import = struct { |
| 173 | /// MachO symbol table entry. | 193 | /// MachO symbol table entry. |
| 174 | symbol: macho.nlist_64, | 194 | symbol: macho.nlist_64, |
| ... | @@ -180,14 +200,15 @@ pub const Import = struct { | ... | @@ -180,14 +200,15 @@ pub const Import = struct { |
| 180 | index: u32, | 200 | index: u32, |
| 181 | }; | 201 | }; |
| 182 | | 202 | |
| 183 | pub const PieFixup = struct { | 203 | pub const PIEFixup = struct { |
| 184 | /// Target address we wanted to address in absolute terms. | 204 | /// Target VM address of this relocation. |
| 185 | address: u64, | 205 | target_addr: u64, |
| 186 | /// Where in the byte stream we should perform the fixup. | 206 | |
| 187 | start: usize, | 207 | /// Offset within the byte stream. |
| 188 | /// The length of the byte stream. For x86_64, this will be | 208 | offset: usize, |
| 189 | /// variable. For aarch64, it will be fixed at 4 bytes. | 209 | |
| 190 | len: usize, | 210 | /// Size of the relocation. |
| | 211 | size: usize, |
| 191 | }; | 212 | }; |
| 192 | | 213 | |
| 193 | pub const StubFixup = struct { | 214 | pub const StubFixup = struct { |
| ... | @@ -1132,11 +1153,14 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | ... | @@ -1132,11 +1153,14 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 1132 | } | 1153 | } |
| 1133 | | 1154 | |
| 1134 | if (self.offset_table_free_list.popOrNull()) |i| { | 1155 | if (self.offset_table_free_list.popOrNull()) |i| { |
| | 1156 | log.debug("reusing offset table entry index {d} for {s}", .{ i, decl.name }); |
| 1135 | decl.link.macho.offset_table_index = i; | 1157 | decl.link.macho.offset_table_index = i; |
| 1136 | } else { | 1158 | } else { |
| | 1159 | log.debug("allocating offset table entry index {d} for {s}", .{ self.offset_table.items.len, decl.name }); |
| 1137 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); | 1160 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); |
| 1138 | _ = self.offset_table.addOneAssumeCapacity(); | 1161 | _ = self.offset_table.addOneAssumeCapacity(); |
| 1139 | self.offset_table_count_dirty = true; | 1162 | self.offset_table_count_dirty = true; |
| | 1163 | self.rebase_info_dirty = true; |
| 1140 | } | 1164 | } |
| 1141 | | 1165 | |
| 1142 | self.locals.items[decl.link.macho.local_sym_index] = .{ | 1166 | self.locals.items[decl.link.macho.local_sym_index] = .{ |
| ... | @@ -1146,7 +1170,11 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | ... | @@ -1146,7 +1170,11 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 1146 | .n_desc = 0, | 1170 | .n_desc = 0, |
| 1147 | .n_value = 0, | 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 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | 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,8 +1217,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1189 | .externally_managed => |x| x, | 1217 | .externally_managed => |x| x, |
| 1190 | .appended => code_buffer.items, | 1218 | .appended => code_buffer.items, |
| 1191 | .fail => |em| { | 1219 | .fail => |em| { |
| 1192 | // Clear any PIE fixups and stub fixups for this decl. | 1220 | // Clear any PIE fixups for this decl. |
| 1193 | self.pie_fixups.shrinkRetainingCapacity(0); | 1221 | self.pie_fixups.shrinkRetainingCapacity(0); |
| | 1222 | // Clear any stub fixups for this decl. |
| 1194 | self.stub_fixups.shrinkRetainingCapacity(0); | 1223 | self.stub_fixups.shrinkRetainingCapacity(0); |
| 1195 | decl.analysis = .codegen_failure; | 1224 | decl.analysis = .codegen_failure; |
| 1196 | try module.failed_decls.put(module.gpa, decl, em); | 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,9 +1238,12 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1209 | const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment); | 1238 | const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment); |
| 1210 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr }); | 1239 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr }); |
| 1211 | if (vaddr != symbol.n_value) { | 1240 | if (vaddr != symbol.n_value) { |
| 1212 | symbol.n_value = vaddr; | | |
| 1213 | log.debug(" (writing new offset table entry)", .{}); | 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 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); | 1247 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1216 | } | 1248 | } |
| 1217 | } else if (code.len < decl.link.macho.size) { | 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,7 +1272,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1240 | .n_desc = 0, | 1272 | .n_desc = 0, |
| 1241 | .n_value = addr, | 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 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); | 1281 | try self.writeLocalSymbol(decl.link.macho.local_sym_index); |
| 1246 | if (self.d_sym) |*ds| | 1282 | if (self.d_sym) |*ds| |
| ... | @@ -1248,30 +1284,48 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1248,30 +1284,48 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1248 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); | 1284 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1249 | } | 1285 | } |
| 1250 | | 1286 | |
| 1251 | // Perform PIE fixups (if any) | 1287 | // Calculate displacements to target addr (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.?]; | | |
| 1254 | while (self.pie_fixups.popOrNull()) |fixup| { | 1288 | while (self.pie_fixups.popOrNull()) |fixup| { |
| 1255 | const target_addr = fixup.address; | 1289 | assert(fixup.size == 4); |
| 1256 | const this_addr = symbol.n_value + fixup.start; | 1290 | const this_addr = symbol.n_value + fixup.offset; |
| | 1291 | const target_addr = fixup.target_addr; |
| | 1292 | |
| 1257 | switch (self.base.options.target.cpu.arch) { | 1293 | switch (self.base.options.target.cpu.arch) { |
| 1258 | .x86_64 => { | 1294 | .x86_64 => { |
| 1259 | assert(target_addr >= this_addr + fixup.len); | 1295 | const displacement = try math.cast(u32, target_addr - this_addr - 4); |
| 1260 | const displacement = try math.cast(u32, target_addr - this_addr - fixup.len); | 1296 | mem.writeIntLittle(u32, code_buffer.items[fixup.offset..][0..4], displacement); |
| 1261 | var placeholder = code_buffer.items[fixup.start + fixup.len - @sizeOf(u32) ..][0..@sizeOf(u32)]; | | |
| 1262 | mem.writeIntSliceLittle(u32, placeholder, displacement); | | |
| 1263 | }, | 1297 | }, |
| 1264 | .aarch64 => { | 1298 | .aarch64 => { |
| 1265 | assert(target_addr >= this_addr); | 1299 | // TODO optimize instruction based on jump length (use ldr(literal) + nop if possible). |
| 1266 | const displacement = try math.cast(u27, target_addr - this_addr); | 1300 | { |
| 1267 | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; | 1301 | const inst = code_buffer.items[fixup.offset..][0..4]; |
| 1268 | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.b(@as(i28, displacement)).toU32()); | 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 | else => unreachable, // unsupported target architecture | 1323 | else => unreachable, // unsupported target architecture |
| 1271 | } | 1324 | } |
| 1272 | } | 1325 | } |
| 1273 | | 1326 | |
| 1274 | // Resolve stubs (if any) | 1327 | // Resolve stubs (if any) |
| | 1328 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1275 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; | 1329 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |
| 1276 | for (self.stub_fixups.items) |fixup| { | 1330 | for (self.stub_fixups.items) |fixup| { |
| 1277 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; | 1331 | const stub_addr = stubs.addr + fixup.symbol * stubs.reserved2; |
| ... | @@ -1561,39 +1615,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1561,39 +1615,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1561 | self.header_dirty = true; | 1615 | self.header_dirty = true; |
| 1562 | self.load_commands_dirty = true; | 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 | if (self.stubs_section_index == null) { | 1618 | if (self.stubs_section_index == null) { |
| 1598 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1619 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1599 | self.stubs_section_index = @intCast(u16, text_segment.sections.items.len); | 1620 | self.stubs_section_index = @intCast(u16, text_segment.sections.items.len); |
| ... | @@ -1694,9 +1715,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1694,9 +1715,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1694 | self.header_dirty = true; | 1715 | self.header_dirty = true; |
| 1695 | self.load_commands_dirty = true; | 1716 | self.load_commands_dirty = true; |
| 1696 | } | 1717 | } |
| 1697 | if (self.data_got_section_index == null) { | 1718 | if (self.got_section_index == null) { |
| 1698 | const dc_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 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 | const flags = macho.S_NON_LAZY_SYMBOL_POINTERS; | 1722 | const flags = macho.S_NON_LAZY_SYMBOL_POINTERS; |
| 1702 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | 1723 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| ... | @@ -2083,6 +2104,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -2083,6 +2104,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2083 | .dylib_ordinal = 1, // TODO this is currently hardcoded. | 2104 | .dylib_ordinal = 1, // TODO this is currently hardcoded. |
| 2084 | .index = index, | 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 | self.binding_info_dirty = true; | 2114 | self.binding_info_dirty = true; |
| 2087 | } | 2115 | } |
| 2088 | if (self.stub_helper_stubs_start_off == null) { | 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,41 +2440,29 @@ fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, sta |
| 2412 | } | 2440 | } |
| 2413 | | 2441 | |
| 2414 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | 2442 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 2415 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2443 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2416 | const sect = &text_segment.sections.items[self.got_section_index.?]; | 2444 | const sect = &seg.sections.items[self.got_section_index.?]; |
| 2417 | const off = sect.offset + @sizeOf(u64) * index; | 2445 | const off = sect.offset + @sizeOf(u64) * index; |
| 2418 | const vmaddr = sect.addr + @sizeOf(u64) * index; | | |
| 2419 | | 2446 | |
| 2420 | if (self.offset_table_count_dirty) { | 2447 | if (self.offset_table_count_dirty) { |
| 2421 | // TODO relocate. | 2448 | // TODO relocate. |
| 2422 | self.offset_table_count_dirty = false; | 2449 | self.offset_table_count_dirty = false; |
| 2423 | } | 2450 | } |
| 2424 | | 2451 | |
| 2425 | var code: [8]u8 = undefined; | 2452 | const got_entry = self.offset_table.items[index]; |
| 2426 | switch (self.base.options.target.cpu.arch) { | 2453 | const sym = blk: { |
| 2427 | .x86_64 => { | 2454 | switch (got_entry.kind) { |
| 2428 | const pos_symbol_off = try math.cast(u31, vmaddr - self.offset_table.items[index] + 7); | 2455 | .Local => { |
| 2429 | const symbol_off = @bitCast(u32, @as(i32, pos_symbol_off) * -1); | 2456 | break :blk self.locals.items[got_entry.symbol]; |
| 2430 | // lea %rax, [rip - disp] | 2457 | }, |
| 2431 | code[0] = 0x48; | 2458 | .Extern => { |
| 2432 | code[1] = 0x8D; | 2459 | break :blk self.nonlazy_imports.items()[got_entry.symbol].value.symbol; |
| 2433 | code[2] = 0x5; | 2460 | }, |
| 2434 | mem.writeIntLittle(u32, code[3..7], symbol_off); | 2461 | } |
| 2435 | // ret | 2462 | }; |
| 2436 | code[7] = 0xC3; | 2463 | const sym_name = self.getString(sym.n_strx); |
| 2437 | }, | 2464 | log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{ off, sym.n_value, sym_name }); |
| 2438 | .aarch64 => { | 2465 | try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off); |
| 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); | | |
| 2450 | } | 2466 | } |
| 2451 | | 2467 | |
| 2452 | fn writeLazySymbolPointer(self: *MachO, index: u32) !void { | 2468 | fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| ... | @@ -2473,7 +2489,7 @@ fn writeStubHelperPreamble(self: *MachO) !void { | ... | @@ -2473,7 +2489,7 @@ fn writeStubHelperPreamble(self: *MachO) !void { |
| 2473 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2489 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2474 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | 2490 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| 2475 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 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 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 2493 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2478 | const data = &data_segment.sections.items[self.data_section_index.?]; | 2494 | const data = &data_segment.sections.items[self.data_section_index.?]; |
| 2479 | | 2495 | |
| ... | @@ -2813,15 +2829,15 @@ fn writeIndirectSymbolTable(self: *MachO) !void { | ... | @@ -2813,15 +2829,15 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2813 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2829 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2814 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; | 2830 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; |
| 2815 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 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 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 2833 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2818 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; | 2834 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 2819 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | 2835 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 2820 | | 2836 | |
| 2821 | const lazy = self.lazy_imports.items(); | 2837 | const lazy = self.lazy_imports.items(); |
| 2822 | const nonlazy = self.nonlazy_imports.items(); | 2838 | const got_entries = self.offset_table.items; |
| 2823 | const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff); | 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 | const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32)); | 2841 | const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32)); |
| 2826 | | 2842 | |
| 2827 | if (needed_size > allocated_size) { | 2843 | if (needed_size > allocated_size) { |
| ... | @@ -2847,12 +2863,19 @@ fn writeIndirectSymbolTable(self: *MachO) !void { | ... | @@ -2847,12 +2863,19 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2847 | | 2863 | |
| 2848 | const base_id = @intCast(u32, lazy.len); | 2864 | const base_id = @intCast(u32, lazy.len); |
| 2849 | got.reserved1 = base_id; | 2865 | got.reserved1 = base_id; |
| 2850 | for (nonlazy) |_, i| { | 2866 | for (got_entries) |entry| { |
| 2851 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id); | 2867 | switch (entry.kind) { |
| 2852 | try writer.writeIntLittle(u32, symtab_idx); | 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 | for (lazy) |_, i| { | 2879 | for (lazy) |_, i| { |
| 2857 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); | 2880 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2858 | try writer.writeIntLittle(u32, symtab_idx); | 2881 | try writer.writeIntLittle(u32, symtab_idx); |
| ... | @@ -2973,12 +2996,27 @@ fn writeRebaseInfoTable(self: *MachO) !void { | ... | @@ -2973,12 +2996,27 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2973 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); | 2996 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 2974 | defer pointers.deinit(); | 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 | if (self.la_symbol_ptr_section_index) |idx| { | 3014 | if (self.la_symbol_ptr_section_index) |idx| { |
| 2977 | try pointers.ensureCapacity(pointers.items.len + self.lazy_imports.items().len); | 3015 | try pointers.ensureCapacity(pointers.items.len + self.lazy_imports.items().len); |
| 2978 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 3016 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2979 | const sect = seg.sections.items[idx]; | 3017 | const sect = seg.sections.items[idx]; |
| 2980 | const base_offset = sect.addr - seg.inner.vmaddr; | 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 | for (self.lazy_imports.items()) |entry| { | 3021 | for (self.lazy_imports.items()) |entry| { |
| 2984 | pointers.appendAssumeCapacity(.{ | 3022 | pointers.appendAssumeCapacity(.{ |
| ... | @@ -3024,19 +3062,20 @@ fn writeBindingInfoTable(self: *MachO) !void { | ... | @@ -3024,19 +3062,20 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 3024 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); | 3062 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 3025 | defer pointers.deinit(); | 3063 | defer pointers.deinit(); |
| 3026 | | 3064 | |
| 3027 | if (self.data_got_section_index) |idx| { | 3065 | if (self.got_section_index) |idx| { |
| 3028 | try pointers.ensureCapacity(pointers.items.len + self.nonlazy_imports.items().len); | | |
| 3029 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 3066 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 3030 | const sect = seg.sections.items[idx]; | 3067 | const sect = seg.sections.items[idx]; |
| 3031 | const base_offset = sect.addr - seg.inner.vmaddr; | 3068 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 3032 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); | 3069 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 3033 | | 3070 | |
| 3034 | for (self.nonlazy_imports.items()) |entry| { | 3071 | for (self.offset_table.items) |entry| { |
| 3035 | pointers.appendAssumeCapacity(.{ | 3072 | if (entry.kind == .Local) continue; |
| 3036 | .offset = base_offset + entry.value.index * @sizeOf(u64), | 3073 | const import = self.nonlazy_imports.items()[entry.symbol]; |
| | 3074 | try pointers.append(.{ |
| | 3075 | .offset = base_offset + entry.index * @sizeOf(u64), |
| 3037 | .segment_id = segment_id, | 3076 | .segment_id = segment_id, |
| 3038 | .dylib_ordinal = entry.value.dylib_ordinal, | 3077 | .dylib_ordinal = import.value.dylib_ordinal, |
| 3039 | .name = entry.key, | 3078 | .name = import.key, |
| 3040 | }); | 3079 | }); |
| 3041 | } | 3080 | } |
| 3042 | } | 3081 | } |