| ... | ... | @@ -40,7 +40,6 @@ const Liveness = @import("../Liveness.zig"); |
| 40 | 40 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 41 | 41 | const Module = @import("../Module.zig"); |
| 42 | 42 | const Relocation = @import("MachO/Relocation.zig"); |
| 43 | | const RelocationTable = Relocation.Table; |
| 44 | 43 | const StringTable = @import("strtab.zig").StringTable; |
| 45 | 44 | const Trie = @import("MachO/Trie.zig"); |
| 46 | 45 | const Type = @import("../type.zig").Type; |
| ... | ... | @@ -196,6 +195,21 @@ unnamed_const_atoms: UnnamedConstTable = .{}, |
| 196 | 195 | /// this will be a table indexed by index into the list of Atoms. |
| 197 | 196 | relocs: RelocationTable = .{}, |
| 198 | 197 | |
| 198 | /// A table of rebases indexed by the owning them `Atom`. |
| 199 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, |
| 200 | /// this will be a table indexed by index into the list of Atoms. |
| 201 | rebases: RebaseTable = .{}, |
| 202 | |
| 203 | /// A table of bindings indexed by the owning them `Atom`. |
| 204 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, |
| 205 | /// this will be a table indexed by index into the list of Atoms. |
| 206 | bindings: BindingTable = .{}, |
| 207 | |
| 208 | /// A table of lazy bindings indexed by the owning them `Atom`. |
| 209 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, |
| 210 | /// this will be a table indexed by index into the list of Atoms. |
| 211 | lazy_bindings: BindingTable = .{}, |
| 212 | |
| 199 | 213 | /// Table of Decls that are currently alive. |
| 200 | 214 | /// We store them here so that we can properly dispose of any allocated |
| 201 | 215 | /// memory within the atom in the incremental linker. |
| ... | ... | @@ -215,8 +229,8 @@ const Entry = struct { |
| 215 | 229 | return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null }); |
| 216 | 230 | } |
| 217 | 231 | |
| 218 | | pub fn getAtom(entry: Entry, macho_file: *MachO) *Atom { |
| 219 | | return macho_file.getAtomForSymbol(.{ .sym_index = entry.sym_index, .file = null }).?; |
| 232 | pub fn getAtom(entry: Entry, macho_file: *MachO) ?*Atom { |
| 233 | return macho_file.getAtomForSymbol(.{ .sym_index = entry.sym_index, .file = null }); |
| 220 | 234 | } |
| 221 | 235 | |
| 222 | 236 | pub fn getName(entry: Entry, macho_file: *MachO) []const u8 { |
| ... | ... | @@ -224,7 +238,10 @@ const Entry = struct { |
| 224 | 238 | } |
| 225 | 239 | }; |
| 226 | 240 | |
| 241 | const BindingTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Atom.Binding)); |
| 227 | 242 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| 243 | const RebaseTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); |
| 244 | const RelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation)); |
| 228 | 245 | |
| 229 | 246 | const PendingUpdate = union(enum) { |
| 230 | 247 | resolve_undef: u32, |
| ... | ... | @@ -238,6 +255,16 @@ pub const SymbolWithLoc = struct { |
| 238 | 255 | |
| 239 | 256 | // null means it's a synthetic global. |
| 240 | 257 | file: ?u32 = null, |
| 258 | |
| 259 | pub fn eql(this: SymbolWithLoc, other: SymbolWithLoc) bool { |
| 260 | if (this.file == null and other.file == null) { |
| 261 | return this.sym_index == other.sym_index; |
| 262 | } |
| 263 | if (this.file != null and other.file != null) { |
| 264 | return this.sym_index == other.sym_index and this.file.? == other.file.?; |
| 265 | } |
| 266 | return false; |
| 267 | } |
| 241 | 268 | }; |
| 242 | 269 | |
| 243 | 270 | /// When allocating, the ideal_capacity is calculated by |
| ... | ... | @@ -436,7 +463,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 436 | 463 | var libs = std.StringArrayHashMap(link.SystemLib).init(arena); |
| 437 | 464 | try self.resolveLibSystem(arena, comp, &.{}, &libs); |
| 438 | 465 | |
| 439 | | const id_symlink_basename = "zld.id"; |
| 466 | const id_symlink_basename = "link.id"; |
| 440 | 467 | |
| 441 | 468 | const cache_dir_handle = module.zig_cache_artifact_directory.handle; |
| 442 | 469 | var man: Cache.Manifest = undefined; |
| ... | ... | @@ -517,14 +544,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 517 | 544 | |
| 518 | 545 | try self.allocateSpecialSymbols(); |
| 519 | 546 | |
| 547 | { |
| 548 | var it = self.relocs.keyIterator(); |
| 549 | while (it.next()) |atom| { |
| 550 | try atom.*.resolveRelocations(self); |
| 551 | } |
| 552 | } |
| 553 | |
| 520 | 554 | if (build_options.enable_logging) { |
| 521 | 555 | self.logSymtab(); |
| 522 | 556 | self.logSections(); |
| 523 | 557 | self.logAtoms(); |
| 524 | 558 | } |
| 525 | 559 | |
| 526 | | try self.writeAtoms(); |
| 527 | | |
| 528 | 560 | var lc_buffer = std.ArrayList(u8).init(arena); |
| 529 | 561 | const lc_writer = lc_buffer.writer(); |
| 530 | 562 | var ncmds: u32 = 0; |
| ... | ... | @@ -1179,84 +1211,49 @@ pub fn createEmptyAtom(gpa: Allocator, sym_index: u32, size: u64, alignment: u32 |
| 1179 | 1211 | return atom; |
| 1180 | 1212 | } |
| 1181 | 1213 | |
| 1182 | | pub fn writeAtom(self: *MachO, atom: *Atom) !void { |
| 1214 | pub fn writeAtom(self: *MachO, atom: *Atom, code: []const u8) !void { |
| 1215 | // TODO: temporary sanity check |
| 1216 | assert(atom.code.items.len == 0); |
| 1217 | assert(atom.relocs.items.len == 0); |
| 1218 | assert(atom.rebases.items.len == 0); |
| 1219 | assert(atom.bindings.items.len == 0); |
| 1220 | assert(atom.lazy_bindings.items.len == 0); |
| 1221 | |
| 1183 | 1222 | const sym = atom.getSymbol(self); |
| 1184 | 1223 | const section = self.sections.get(sym.n_sect - 1); |
| 1185 | 1224 | const file_offset = section.header.offset + sym.n_value - section.header.addr; |
| 1186 | | try atom.resolveRelocs(self); |
| 1187 | 1225 | log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset }); |
| 1188 | | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 1226 | try self.base.file.?.pwriteAll(code, file_offset); |
| 1227 | try atom.resolveRelocations(self); |
| 1189 | 1228 | } |
| 1190 | 1229 | |
| 1191 | | // fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void { |
| 1192 | | // // TODO: reverse-lookup might come in handy here |
| 1193 | | // var it = self.relocs.valueIterator(); |
| 1194 | | // while (it.next()) |relocs| { |
| 1195 | | // for (relocs.items) |*reloc| { |
| 1196 | | // if (!reloc.target.eql(target)) continue; |
| 1197 | | // reloc.dirty = true; |
| 1198 | | // } |
| 1199 | | // } |
| 1200 | | // } |
| 1201 | | |
| 1202 | | // fn markRelocsDirtyByAddress(self: *MachO, addr: u32) void { |
| 1203 | | // var it = self.relocs.valueIterator(); |
| 1204 | | // while (it.next()) |relocs| { |
| 1205 | | // for (relocs.items) |*reloc| { |
| 1206 | | // const target_atom = reloc.getTargetAtom(self) orelse continue; |
| 1207 | | // const target_sym = target_atom.getSymbol(self); |
| 1208 | | // if (target_sym.value < addr) continue; |
| 1209 | | // reloc.dirty = true; |
| 1210 | | // } |
| 1211 | | // } |
| 1212 | | // } |
| 1213 | | |
| 1214 | | // fn resolveRelocs(self: *MachO, atom: *Atom) !void { |
| 1215 | | // const relocs = self.relocs.get(atom) orelse return; |
| 1216 | | // const source_sym = atom.getSymbol(self); |
| 1217 | | // const source_section = self.sections.get(@enumToInt(source_sym.section_number) - 1).header; |
| 1218 | | // const file_offset = section.offset + source_sym.n_value - section.addr; |
| 1219 | | |
| 1220 | | // log.debug("relocating '{s}'", .{atom.getName(self)}); |
| 1221 | | |
| 1222 | | // for (relocs.items) |*reloc| { |
| 1223 | | // if (!reloc.dirty) continue; |
| 1224 | | |
| 1225 | | // const target_atom = reloc.getTargetAtom(self) orelse continue; |
| 1226 | | // const target_vaddr = target_atom.getSymbol(self).value; |
| 1227 | | // const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| 1228 | | |
| 1229 | | // log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ |
| 1230 | | // source_sym.value + reloc.offset, |
| 1231 | | // target_vaddr_with_addend, |
| 1232 | | // self.getSymbolName(reloc.target), |
| 1233 | | // @tagName(reloc.@"type"), |
| 1234 | | // file_offset + reloc.offset, |
| 1235 | | // }); |
| 1236 | | |
| 1237 | | // reloc.dirty = false; |
| 1230 | fn writePtrWidthAtom(self: *MachO, atom: *Atom) !void { |
| 1231 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); |
| 1232 | try self.writeAtom(atom, &buffer); |
| 1233 | } |
| 1238 | 1234 | |
| 1239 | | // if (reloc.pcrel) { |
| 1240 | | // const source_vaddr = source_sym.value + reloc.offset; |
| 1241 | | // const disp = |
| 1242 | | // @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; |
| 1243 | | // try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); |
| 1244 | | // continue; |
| 1245 | | // } |
| 1235 | fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void { |
| 1236 | // TODO: reverse-lookup might come in handy here |
| 1237 | var it = self.relocs.valueIterator(); |
| 1238 | while (it.next()) |relocs| { |
| 1239 | for (relocs.items) |*reloc| { |
| 1240 | if (!reloc.target.eql(target)) continue; |
| 1241 | reloc.dirty = true; |
| 1242 | } |
| 1243 | } |
| 1244 | } |
| 1246 | 1245 | |
| 1247 | | // switch (reloc.length) { |
| 1248 | | // 2 => try self.base.file.?.pwriteAll( |
| 1249 | | // mem.asBytes(&@truncate(u32, target_vaddr_with_addend)), |
| 1250 | | // file_offset + reloc.offset, |
| 1251 | | // ), |
| 1252 | | // 3 => try self.base.file.?.pwriteAll( |
| 1253 | | // mem.asBytes(&(target_vaddr_with_addend)), |
| 1254 | | // file_offset + reloc.offset, |
| 1255 | | // ), |
| 1256 | | // else => unreachable, |
| 1257 | | // } |
| 1258 | | // } |
| 1259 | | // } |
| 1246 | fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void { |
| 1247 | var it = self.relocs.valueIterator(); |
| 1248 | while (it.next()) |relocs| { |
| 1249 | for (relocs.items) |*reloc| { |
| 1250 | const target_atom = reloc.getTargetAtom(self) orelse continue; |
| 1251 | const target_sym = target_atom.getSymbol(self); |
| 1252 | if (target_sym.n_value < addr) continue; |
| 1253 | reloc.dirty = true; |
| 1254 | } |
| 1255 | } |
| 1256 | } |
| 1260 | 1257 | |
| 1261 | 1258 | pub fn allocateSpecialSymbols(self: *MachO) !void { |
| 1262 | 1259 | for (&[_][]const u8{ |
| ... | ... | @@ -1277,74 +1274,92 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { |
| 1277 | 1274 | } |
| 1278 | 1275 | } |
| 1279 | 1276 | |
| 1280 | | fn writeAtoms(self: *MachO) !void { |
| 1281 | | assert(self.mode == .incremental); |
| 1282 | | |
| 1283 | | const slice = self.sections.slice(); |
| 1284 | | for (slice.items(.last_atom)) |last, i| { |
| 1285 | | var atom: *Atom = last orelse continue; |
| 1286 | | const sect_i = @intCast(u8, i); |
| 1287 | | const header = slice.items(.header)[sect_i]; |
| 1288 | | |
| 1289 | | if (header.isZerofill()) continue; |
| 1290 | | |
| 1291 | | log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() }); |
| 1292 | | |
| 1293 | | while (true) { |
| 1294 | | if (atom.dirty) { |
| 1295 | | try self.writeAtom(atom); |
| 1296 | | atom.dirty = false; |
| 1297 | | } |
| 1298 | | |
| 1299 | | if (atom.prev) |prev| { |
| 1300 | | atom = prev; |
| 1301 | | } else break; |
| 1302 | | } |
| 1303 | | } |
| 1304 | | } |
| 1305 | | |
| 1306 | 1277 | pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom { |
| 1307 | 1278 | const gpa = self.base.allocator; |
| 1279 | |
| 1308 | 1280 | const sym_index = try self.allocateSymbol(); |
| 1309 | | const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3); |
| 1281 | const atom = switch (self.mode) { |
| 1282 | .incremental => blk: { |
| 1283 | const atom = try gpa.create(Atom); |
| 1284 | atom.* = Atom.empty; |
| 1285 | atom.sym_index = sym_index; |
| 1286 | atom.size = @sizeOf(u64); |
| 1287 | atom.alignment = 3; |
| 1288 | break :blk atom; |
| 1289 | }, |
| 1290 | .one_shot => try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3), |
| 1291 | }; |
| 1292 | errdefer gpa.destroy(atom); |
| 1293 | |
| 1294 | try self.managed_atoms.append(gpa, atom); |
| 1295 | try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); |
| 1296 | |
| 1310 | 1297 | const sym = atom.getSymbolPtr(self); |
| 1311 | 1298 | sym.n_type = macho.N_SECT; |
| 1312 | 1299 | sym.n_sect = self.got_section_index.? + 1; |
| 1313 | 1300 | |
| 1314 | | try atom.relocs.append(gpa, .{ |
| 1315 | | .offset = 0, |
| 1316 | | .target = target, |
| 1317 | | .addend = 0, |
| 1318 | | .subtractor = null, |
| 1319 | | .pcrel = false, |
| 1320 | | .length = 3, |
| 1321 | | .@"type" = switch (self.base.options.target.cpu.arch) { |
| 1322 | | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| 1323 | | .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| 1324 | | else => unreachable, |
| 1325 | | }, |
| 1326 | | }); |
| 1301 | if (self.mode == .incremental) { |
| 1302 | sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); |
| 1327 | 1303 | |
| 1328 | | const target_sym = self.getSymbol(target); |
| 1329 | | if (target_sym.undf()) { |
| 1330 | | const global = self.getGlobal(self.getSymbolName(target)).?; |
| 1331 | | try atom.bindings.append(gpa, .{ |
| 1332 | | .target = global, |
| 1304 | log.debug("allocated GOT atom at 0x{x}", .{sym.n_value}); |
| 1305 | |
| 1306 | try atom.addRelocation(self, .{ |
| 1307 | .@"type" = switch (self.base.options.target.cpu.arch) { |
| 1308 | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| 1309 | .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| 1310 | else => unreachable, |
| 1311 | }, |
| 1312 | .target = target, |
| 1333 | 1313 | .offset = 0, |
| 1314 | .addend = 0, |
| 1315 | .pcrel = false, |
| 1316 | .length = 3, |
| 1334 | 1317 | }); |
| 1318 | |
| 1319 | const target_sym = self.getSymbol(target); |
| 1320 | if (target_sym.undf()) { |
| 1321 | try atom.addBinding(self, .{ |
| 1322 | .target = self.getGlobal(self.getSymbolName(target)).?, |
| 1323 | .offset = 0, |
| 1324 | }); |
| 1325 | } else { |
| 1326 | try atom.addRebase(self, 0); |
| 1327 | } |
| 1335 | 1328 | } else { |
| 1336 | | try atom.rebases.append(gpa, 0); |
| 1337 | | } |
| 1329 | try atom.relocs.append(gpa, .{ |
| 1330 | .offset = 0, |
| 1331 | .target = target, |
| 1332 | .addend = 0, |
| 1333 | .subtractor = null, |
| 1334 | .pcrel = false, |
| 1335 | .length = 3, |
| 1336 | .@"type" = switch (self.base.options.target.cpu.arch) { |
| 1337 | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| 1338 | .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| 1339 | else => unreachable, |
| 1340 | }, |
| 1341 | }); |
| 1338 | 1342 | |
| 1339 | | try self.managed_atoms.append(gpa, atom); |
| 1340 | | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); |
| 1343 | const target_sym = self.getSymbol(target); |
| 1344 | if (target_sym.undf()) { |
| 1345 | const global = self.getGlobal(self.getSymbolName(target)).?; |
| 1346 | try atom.bindings.append(gpa, .{ |
| 1347 | .target = global, |
| 1348 | .offset = 0, |
| 1349 | }); |
| 1350 | } else { |
| 1351 | try atom.rebases.append(gpa, 0); |
| 1352 | } |
| 1341 | 1353 | |
| 1342 | | try self.allocateAtomCommon(atom); |
| 1354 | try self.addAtomToSection(atom); |
| 1355 | } |
| 1343 | 1356 | |
| 1344 | 1357 | return atom; |
| 1345 | 1358 | } |
| 1346 | 1359 | |
| 1347 | 1360 | pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom { |
| 1361 | assert(self.mode == .one_shot); |
| 1362 | |
| 1348 | 1363 | const gpa = self.base.allocator; |
| 1349 | 1364 | const sym_index = try self.allocateSymbol(); |
| 1350 | 1365 | const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3); |
| ... | ... | @@ -1368,14 +1383,9 @@ pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom { |
| 1368 | 1383 | .sectname = makeStaticString("__thread_ptrs"), |
| 1369 | 1384 | .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS, |
| 1370 | 1385 | })).?; |
| 1371 | | if (self.mode == .incremental and !gop.found_existing) { |
| 1372 | | // TODO allocate section |
| 1373 | | const needed_size: u64 = self.page_size; |
| 1374 | | try self.allocateSection(gop.sect_id, needed_size, @alignOf(u64)); |
| 1375 | | } |
| 1376 | 1386 | sym.n_sect = gop.sect_id + 1; |
| 1377 | 1387 | |
| 1378 | | try self.allocateAtomCommon(atom); |
| 1388 | try self.addAtomToSection(atom); |
| 1379 | 1389 | |
| 1380 | 1390 | return atom; |
| 1381 | 1391 | } |
| ... | ... | @@ -1385,17 +1395,36 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1385 | 1395 | if (self.dyld_private_atom != null) return; |
| 1386 | 1396 | |
| 1387 | 1397 | const gpa = self.base.allocator; |
| 1398 | |
| 1388 | 1399 | const sym_index = try self.allocateSymbol(); |
| 1389 | | const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3); |
| 1400 | const atom = switch (self.mode) { |
| 1401 | .incremental => blk: { |
| 1402 | const atom = try gpa.create(Atom); |
| 1403 | atom.* = Atom.empty; |
| 1404 | atom.sym_index = sym_index; |
| 1405 | atom.size = @sizeOf(u64); |
| 1406 | atom.alignment = 3; |
| 1407 | break :blk atom; |
| 1408 | }, |
| 1409 | .one_shot => try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3), |
| 1410 | }; |
| 1411 | errdefer gpa.destroy(atom); |
| 1412 | |
| 1390 | 1413 | const sym = atom.getSymbolPtr(self); |
| 1391 | 1414 | sym.n_type = macho.N_SECT; |
| 1392 | 1415 | sym.n_sect = self.data_section_index.? + 1; |
| 1393 | 1416 | self.dyld_private_atom = atom; |
| 1394 | 1417 | |
| 1395 | | try self.allocateAtomCommon(atom); |
| 1396 | | |
| 1397 | 1418 | try self.managed_atoms.append(gpa, atom); |
| 1398 | 1419 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); |
| 1420 | |
| 1421 | if (self.mode == .incremental) { |
| 1422 | sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); |
| 1423 | log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); |
| 1424 | try self.writePtrWidthAtom(atom); |
| 1425 | } else { |
| 1426 | try self.addAtomToSection(atom); |
| 1427 | } |
| 1399 | 1428 | } |
| 1400 | 1429 | |
| 1401 | 1430 | pub fn createStubHelperPreambleAtom(self: *MachO) !void { |
| ... | ... | @@ -1415,118 +1444,196 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 1415 | 1444 | else => unreachable, |
| 1416 | 1445 | }; |
| 1417 | 1446 | const sym_index = try self.allocateSymbol(); |
| 1418 | | const atom = try MachO.createEmptyAtom(gpa, sym_index, size, alignment); |
| 1447 | const atom = switch (self.mode) { |
| 1448 | .incremental => blk: { |
| 1449 | const atom = try gpa.create(Atom); |
| 1450 | atom.* = Atom.empty; |
| 1451 | atom.sym_index = sym_index; |
| 1452 | atom.size = size; |
| 1453 | atom.alignment = alignment; |
| 1454 | break :blk atom; |
| 1455 | }, |
| 1456 | .one_shot => try MachO.createEmptyAtom(gpa, sym_index, size, alignment), |
| 1457 | }; |
| 1458 | errdefer gpa.destroy(atom); |
| 1459 | |
| 1419 | 1460 | const sym = atom.getSymbolPtr(self); |
| 1420 | 1461 | sym.n_type = macho.N_SECT; |
| 1421 | 1462 | sym.n_sect = self.stub_helper_section_index.? + 1; |
| 1422 | 1463 | |
| 1423 | 1464 | const dyld_private_sym_index = self.dyld_private_atom.?.sym_index; |
| 1465 | |
| 1466 | const code = try gpa.alloc(u8, size); |
| 1467 | defer gpa.free(code); |
| 1468 | mem.set(u8, code, 0); |
| 1469 | |
| 1424 | 1470 | switch (arch) { |
| 1425 | 1471 | .x86_64 => { |
| 1426 | | try atom.relocs.ensureUnusedCapacity(self.base.allocator, 2); |
| 1427 | 1472 | // lea %r11, [rip + disp] |
| 1428 | | atom.code.items[0] = 0x4c; |
| 1429 | | atom.code.items[1] = 0x8d; |
| 1430 | | atom.code.items[2] = 0x1d; |
| 1431 | | atom.relocs.appendAssumeCapacity(.{ |
| 1432 | | .offset = 3, |
| 1433 | | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1434 | | .addend = 0, |
| 1435 | | .subtractor = null, |
| 1436 | | .pcrel = true, |
| 1437 | | .length = 2, |
| 1438 | | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), |
| 1439 | | }); |
| 1473 | code[0] = 0x4c; |
| 1474 | code[1] = 0x8d; |
| 1475 | code[2] = 0x1d; |
| 1440 | 1476 | // push %r11 |
| 1441 | | atom.code.items[7] = 0x41; |
| 1442 | | atom.code.items[8] = 0x53; |
| 1477 | code[7] = 0x41; |
| 1478 | code[8] = 0x53; |
| 1443 | 1479 | // jmp [rip + disp] |
| 1444 | | atom.code.items[9] = 0xff; |
| 1445 | | atom.code.items[10] = 0x25; |
| 1446 | | atom.relocs.appendAssumeCapacity(.{ |
| 1447 | | .offset = 11, |
| 1448 | | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1449 | | .addend = 0, |
| 1450 | | .subtractor = null, |
| 1451 | | .pcrel = true, |
| 1452 | | .length = 2, |
| 1453 | | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT), |
| 1454 | | }); |
| 1480 | code[9] = 0xff; |
| 1481 | code[10] = 0x25; |
| 1482 | |
| 1483 | if (self.mode == .incremental) { |
| 1484 | try atom.addRelocations(self, 2, .{ .{ |
| 1485 | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), |
| 1486 | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1487 | .offset = 3, |
| 1488 | .addend = 0, |
| 1489 | .pcrel = true, |
| 1490 | .length = 2, |
| 1491 | }, .{ |
| 1492 | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT), |
| 1493 | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1494 | .offset = 11, |
| 1495 | .addend = 0, |
| 1496 | .pcrel = true, |
| 1497 | .length = 2, |
| 1498 | } }); |
| 1499 | } else { |
| 1500 | try atom.relocs.ensureUnusedCapacity(self.base.allocator, 2); |
| 1501 | atom.relocs.appendAssumeCapacity(.{ |
| 1502 | .offset = 3, |
| 1503 | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1504 | .addend = 0, |
| 1505 | .subtractor = null, |
| 1506 | .pcrel = true, |
| 1507 | .length = 2, |
| 1508 | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), |
| 1509 | }); |
| 1510 | atom.relocs.appendAssumeCapacity(.{ |
| 1511 | .offset = 11, |
| 1512 | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1513 | .addend = 0, |
| 1514 | .subtractor = null, |
| 1515 | .pcrel = true, |
| 1516 | .length = 2, |
| 1517 | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT), |
| 1518 | }); |
| 1519 | } |
| 1455 | 1520 | }, |
| 1521 | |
| 1456 | 1522 | .aarch64 => { |
| 1457 | | try atom.relocs.ensureUnusedCapacity(self.base.allocator, 4); |
| 1458 | 1523 | // adrp x17, 0 |
| 1459 | | mem.writeIntLittle(u32, atom.code.items[0..][0..4], aarch64.Instruction.adrp(.x17, 0).toU32()); |
| 1460 | | atom.relocs.appendAssumeCapacity(.{ |
| 1461 | | .offset = 0, |
| 1462 | | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1463 | | .addend = 0, |
| 1464 | | .subtractor = null, |
| 1465 | | .pcrel = true, |
| 1466 | | .length = 2, |
| 1467 | | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), |
| 1468 | | }); |
| 1524 | mem.writeIntLittle(u32, code[0..][0..4], aarch64.Instruction.adrp(.x17, 0).toU32()); |
| 1469 | 1525 | // add x17, x17, 0 |
| 1470 | | mem.writeIntLittle(u32, atom.code.items[4..][0..4], aarch64.Instruction.add(.x17, .x17, 0, false).toU32()); |
| 1471 | | atom.relocs.appendAssumeCapacity(.{ |
| 1472 | | .offset = 4, |
| 1473 | | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1474 | | .addend = 0, |
| 1475 | | .subtractor = null, |
| 1476 | | .pcrel = false, |
| 1477 | | .length = 2, |
| 1478 | | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), |
| 1479 | | }); |
| 1526 | mem.writeIntLittle(u32, code[4..][0..4], aarch64.Instruction.add(.x17, .x17, 0, false).toU32()); |
| 1480 | 1527 | // stp x16, x17, [sp, #-16]! |
| 1481 | | mem.writeIntLittle(u32, atom.code.items[8..][0..4], aarch64.Instruction.stp( |
| 1528 | mem.writeIntLittle(u32, code[8..][0..4], aarch64.Instruction.stp( |
| 1482 | 1529 | .x16, |
| 1483 | 1530 | .x17, |
| 1484 | 1531 | aarch64.Register.sp, |
| 1485 | 1532 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), |
| 1486 | 1533 | ).toU32()); |
| 1487 | 1534 | // adrp x16, 0 |
| 1488 | | mem.writeIntLittle(u32, atom.code.items[12..][0..4], aarch64.Instruction.adrp(.x16, 0).toU32()); |
| 1489 | | atom.relocs.appendAssumeCapacity(.{ |
| 1490 | | .offset = 12, |
| 1491 | | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1492 | | .addend = 0, |
| 1493 | | .subtractor = null, |
| 1494 | | .pcrel = true, |
| 1495 | | .length = 2, |
| 1496 | | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21), |
| 1497 | | }); |
| 1535 | mem.writeIntLittle(u32, code[12..][0..4], aarch64.Instruction.adrp(.x16, 0).toU32()); |
| 1498 | 1536 | // ldr x16, [x16, 0] |
| 1499 | | mem.writeIntLittle(u32, atom.code.items[16..][0..4], aarch64.Instruction.ldr( |
| 1537 | mem.writeIntLittle(u32, code[16..][0..4], aarch64.Instruction.ldr( |
| 1500 | 1538 | .x16, |
| 1501 | 1539 | .x16, |
| 1502 | 1540 | aarch64.Instruction.LoadStoreOffset.imm(0), |
| 1503 | 1541 | ).toU32()); |
| 1504 | | atom.relocs.appendAssumeCapacity(.{ |
| 1505 | | .offset = 16, |
| 1506 | | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1507 | | .addend = 0, |
| 1508 | | .subtractor = null, |
| 1509 | | .pcrel = false, |
| 1510 | | .length = 2, |
| 1511 | | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12), |
| 1512 | | }); |
| 1513 | 1542 | // br x16 |
| 1514 | | mem.writeIntLittle(u32, atom.code.items[20..][0..4], aarch64.Instruction.br(.x16).toU32()); |
| 1543 | mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32()); |
| 1544 | |
| 1545 | if (self.mode == .incremental) { |
| 1546 | try atom.addRelocations(self, 4, .{ .{ |
| 1547 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), |
| 1548 | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1549 | .offset = 0, |
| 1550 | .addend = 0, |
| 1551 | .pcrel = true, |
| 1552 | .length = 2, |
| 1553 | }, .{ |
| 1554 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), |
| 1555 | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1556 | .offset = 4, |
| 1557 | .addend = 0, |
| 1558 | .pcrel = false, |
| 1559 | .length = 2, |
| 1560 | }, .{ |
| 1561 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21), |
| 1562 | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1563 | .offset = 12, |
| 1564 | .addend = 0, |
| 1565 | .pcrel = true, |
| 1566 | .length = 2, |
| 1567 | }, .{ |
| 1568 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12), |
| 1569 | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1570 | .offset = 16, |
| 1571 | .addend = 0, |
| 1572 | .pcrel = false, |
| 1573 | .length = 2, |
| 1574 | } }); |
| 1575 | } else { |
| 1576 | try atom.relocs.ensureUnusedCapacity(gpa, 4); |
| 1577 | atom.relocs.appendAssumeCapacity(.{ |
| 1578 | .offset = 0, |
| 1579 | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1580 | .addend = 0, |
| 1581 | .subtractor = null, |
| 1582 | .pcrel = true, |
| 1583 | .length = 2, |
| 1584 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), |
| 1585 | }); |
| 1586 | atom.relocs.appendAssumeCapacity(.{ |
| 1587 | .offset = 4, |
| 1588 | .target = .{ .sym_index = dyld_private_sym_index, .file = null }, |
| 1589 | .addend = 0, |
| 1590 | .subtractor = null, |
| 1591 | .pcrel = false, |
| 1592 | .length = 2, |
| 1593 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), |
| 1594 | }); |
| 1595 | atom.relocs.appendAssumeCapacity(.{ |
| 1596 | .offset = 12, |
| 1597 | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1598 | .addend = 0, |
| 1599 | .subtractor = null, |
| 1600 | .pcrel = true, |
| 1601 | .length = 2, |
| 1602 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21), |
| 1603 | }); |
| 1604 | atom.relocs.appendAssumeCapacity(.{ |
| 1605 | .offset = 16, |
| 1606 | .target = .{ .sym_index = self.dyld_stub_binder_index.?, .file = null }, |
| 1607 | .addend = 0, |
| 1608 | .subtractor = null, |
| 1609 | .pcrel = false, |
| 1610 | .length = 2, |
| 1611 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12), |
| 1612 | }); |
| 1613 | } |
| 1515 | 1614 | }, |
| 1615 | |
| 1516 | 1616 | else => unreachable, |
| 1517 | 1617 | } |
| 1518 | 1618 | self.stub_helper_preamble_atom = atom; |
| 1519 | 1619 | |
| 1520 | | try self.allocateAtomCommon(atom); |
| 1521 | | |
| 1522 | 1620 | try self.managed_atoms.append(gpa, atom); |
| 1523 | 1621 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); |
| 1622 | |
| 1623 | if (self.mode == .incremental) { |
| 1624 | sym.n_value = try self.allocateAtom(atom, size, math.powi(u32, 2, alignment) catch unreachable); |
| 1625 | log.debug("allocated stub preamble atom at 0x{x}", .{sym.n_value}); |
| 1626 | try self.writeAtom(atom, code); |
| 1627 | } else { |
| 1628 | mem.copy(u8, atom.code.items, code); |
| 1629 | try self.addAtomToSection(atom); |
| 1630 | } |
| 1524 | 1631 | } |
| 1525 | 1632 | |
| 1526 | 1633 | pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 1527 | 1634 | const gpa = self.base.allocator; |
| 1528 | 1635 | const arch = self.base.options.target.cpu.arch; |
| 1529 | | const stub_size: u4 = switch (arch) { |
| 1636 | const size: u4 = switch (arch) { |
| 1530 | 1637 | .x86_64 => 10, |
| 1531 | 1638 | .aarch64 => 3 * @sizeOf(u32), |
| 1532 | 1639 | else => unreachable, |
| ... | ... | @@ -1537,52 +1644,92 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 1537 | 1644 | else => unreachable, |
| 1538 | 1645 | }; |
| 1539 | 1646 | const sym_index = try self.allocateSymbol(); |
| 1540 | | const atom = try MachO.createEmptyAtom(gpa, sym_index, stub_size, alignment); |
| 1647 | const atom = switch (self.mode) { |
| 1648 | .incremental => blk: { |
| 1649 | const atom = try gpa.create(Atom); |
| 1650 | atom.* = Atom.empty; |
| 1651 | atom.sym_index = sym_index; |
| 1652 | atom.size = size; |
| 1653 | atom.alignment = alignment; |
| 1654 | break :blk atom; |
| 1655 | }, |
| 1656 | .one_shot => try MachO.createEmptyAtom(gpa, sym_index, size, alignment), |
| 1657 | }; |
| 1658 | errdefer gpa.destroy(atom); |
| 1659 | |
| 1541 | 1660 | const sym = atom.getSymbolPtr(self); |
| 1542 | 1661 | sym.n_type = macho.N_SECT; |
| 1543 | 1662 | sym.n_sect = self.stub_helper_section_index.? + 1; |
| 1544 | 1663 | |
| 1545 | | try atom.relocs.ensureTotalCapacity(gpa, 1); |
| 1664 | const code = try gpa.alloc(u8, size); |
| 1665 | defer gpa.free(code); |
| 1666 | mem.set(u8, code, 0); |
| 1546 | 1667 | |
| 1547 | 1668 | switch (arch) { |
| 1548 | 1669 | .x86_64 => { |
| 1549 | 1670 | // pushq |
| 1550 | | atom.code.items[0] = 0x68; |
| 1671 | code[0] = 0x68; |
| 1551 | 1672 | // Next 4 bytes 1..4 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 1552 | 1673 | // jmpq |
| 1553 | | atom.code.items[5] = 0xe9; |
| 1554 | | atom.relocs.appendAssumeCapacity(.{ |
| 1555 | | .offset = 6, |
| 1556 | | .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, |
| 1557 | | .addend = 0, |
| 1558 | | .subtractor = null, |
| 1559 | | .pcrel = true, |
| 1560 | | .length = 2, |
| 1561 | | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), |
| 1562 | | }); |
| 1674 | code[5] = 0xe9; |
| 1675 | |
| 1676 | if (self.mode == .incremental) { |
| 1677 | try atom.addRelocation(self, .{ |
| 1678 | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), |
| 1679 | .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, |
| 1680 | .offset = 6, |
| 1681 | .addend = 0, |
| 1682 | .pcrel = true, |
| 1683 | .length = 2, |
| 1684 | }); |
| 1685 | } else { |
| 1686 | try atom.relocs.ensureTotalCapacity(gpa, 1); |
| 1687 | atom.relocs.appendAssumeCapacity(.{ |
| 1688 | .offset = 6, |
| 1689 | .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, |
| 1690 | .addend = 0, |
| 1691 | .subtractor = null, |
| 1692 | .pcrel = true, |
| 1693 | .length = 2, |
| 1694 | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), |
| 1695 | }); |
| 1696 | } |
| 1563 | 1697 | }, |
| 1564 | 1698 | .aarch64 => { |
| 1565 | 1699 | const literal = blk: { |
| 1566 | | const div_res = try math.divExact(u64, stub_size - @sizeOf(u32), 4); |
| 1700 | const div_res = try math.divExact(u64, size - @sizeOf(u32), 4); |
| 1567 | 1701 | break :blk math.cast(u18, div_res) orelse return error.Overflow; |
| 1568 | 1702 | }; |
| 1569 | 1703 | // ldr w16, literal |
| 1570 | | mem.writeIntLittle(u32, atom.code.items[0..4], aarch64.Instruction.ldrLiteral( |
| 1704 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldrLiteral( |
| 1571 | 1705 | .w16, |
| 1572 | 1706 | literal, |
| 1573 | 1707 | ).toU32()); |
| 1574 | 1708 | // b disp |
| 1575 | | mem.writeIntLittle(u32, atom.code.items[4..8], aarch64.Instruction.b(0).toU32()); |
| 1576 | | atom.relocs.appendAssumeCapacity(.{ |
| 1577 | | .offset = 4, |
| 1578 | | .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, |
| 1579 | | .addend = 0, |
| 1580 | | .subtractor = null, |
| 1581 | | .pcrel = true, |
| 1582 | | .length = 2, |
| 1583 | | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), |
| 1584 | | }); |
| 1709 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(0).toU32()); |
| 1585 | 1710 | // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 1711 | |
| 1712 | if (self.mode == .incremental) { |
| 1713 | try atom.addRelocation(self, .{ |
| 1714 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), |
| 1715 | .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, |
| 1716 | .offset = 4, |
| 1717 | .addend = 0, |
| 1718 | .pcrel = true, |
| 1719 | .length = 2, |
| 1720 | }); |
| 1721 | } else { |
| 1722 | try atom.relocs.ensureTotalCapacity(gpa, 1); |
| 1723 | atom.relocs.appendAssumeCapacity(.{ |
| 1724 | .offset = 4, |
| 1725 | .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, |
| 1726 | .addend = 0, |
| 1727 | .subtractor = null, |
| 1728 | .pcrel = true, |
| 1729 | .length = 2, |
| 1730 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), |
| 1731 | }); |
| 1732 | } |
| 1586 | 1733 | }, |
| 1587 | 1734 | else => unreachable, |
| 1588 | 1735 | } |
| ... | ... | @@ -1590,7 +1737,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 1590 | 1737 | try self.managed_atoms.append(gpa, atom); |
| 1591 | 1738 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); |
| 1592 | 1739 | |
| 1593 | | try self.allocateAtomCommon(atom); |
| 1740 | if (self.mode == .incremental) { |
| 1741 | sym.n_value = try self.allocateAtom(atom, size, math.powi(u32, 2, alignment) catch unreachable); |
| 1742 | log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value}); |
| 1743 | try self.writeAtom(atom, code); |
| 1744 | } else { |
| 1745 | mem.copy(u8, atom.code.items, code); |
| 1746 | try self.addAtomToSection(atom); |
| 1747 | } |
| 1594 | 1748 | |
| 1595 | 1749 | return atom; |
| 1596 | 1750 | } |
| ... | ... | @@ -1598,36 +1752,73 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 1598 | 1752 | pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom { |
| 1599 | 1753 | const gpa = self.base.allocator; |
| 1600 | 1754 | const sym_index = try self.allocateSymbol(); |
| 1601 | | const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3); |
| 1755 | const atom = switch (self.mode) { |
| 1756 | .incremental => blk: { |
| 1757 | const atom = try gpa.create(Atom); |
| 1758 | atom.* = Atom.empty; |
| 1759 | atom.sym_index = sym_index; |
| 1760 | atom.size = @sizeOf(u64); |
| 1761 | atom.alignment = 3; |
| 1762 | break :blk atom; |
| 1763 | }, |
| 1764 | .one_shot => try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3), |
| 1765 | }; |
| 1766 | errdefer gpa.destroy(atom); |
| 1767 | |
| 1602 | 1768 | const sym = atom.getSymbolPtr(self); |
| 1603 | 1769 | sym.n_type = macho.N_SECT; |
| 1604 | 1770 | sym.n_sect = self.la_symbol_ptr_section_index.? + 1; |
| 1605 | 1771 | |
| 1606 | | try atom.relocs.append(gpa, .{ |
| 1607 | | .offset = 0, |
| 1608 | | .target = .{ .sym_index = stub_sym_index, .file = null }, |
| 1609 | | .addend = 0, |
| 1610 | | .subtractor = null, |
| 1611 | | .pcrel = false, |
| 1612 | | .length = 3, |
| 1613 | | .@"type" = switch (self.base.options.target.cpu.arch) { |
| 1614 | | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| 1615 | | .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| 1616 | | else => unreachable, |
| 1617 | | }, |
| 1618 | | }); |
| 1619 | | try atom.rebases.append(gpa, 0); |
| 1620 | | |
| 1621 | | const global = self.getGlobal(self.getSymbolName(target)).?; |
| 1622 | | try atom.lazy_bindings.append(gpa, .{ |
| 1623 | | .target = global, |
| 1624 | | .offset = 0, |
| 1625 | | }); |
| 1772 | if (self.mode == .incremental) { |
| 1773 | try atom.addRelocation(self, .{ |
| 1774 | .@"type" = switch (self.base.options.target.cpu.arch) { |
| 1775 | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| 1776 | .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| 1777 | else => unreachable, |
| 1778 | }, |
| 1779 | .target = .{ .sym_index = stub_sym_index, .file = null }, |
| 1780 | .offset = 0, |
| 1781 | .addend = 0, |
| 1782 | .pcrel = false, |
| 1783 | .length = 3, |
| 1784 | }); |
| 1785 | try atom.addRebase(self, 0); |
| 1786 | try atom.addLazyBinding(self, .{ |
| 1787 | .target = self.getGlobal(self.getSymbolName(target)).?, |
| 1788 | .offset = 0, |
| 1789 | }); |
| 1790 | } else { |
| 1791 | try atom.relocs.append(gpa, .{ |
| 1792 | .offset = 0, |
| 1793 | .target = .{ .sym_index = stub_sym_index, .file = null }, |
| 1794 | .addend = 0, |
| 1795 | .subtractor = null, |
| 1796 | .pcrel = false, |
| 1797 | .length = 3, |
| 1798 | .@"type" = switch (self.base.options.target.cpu.arch) { |
| 1799 | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| 1800 | .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| 1801 | else => unreachable, |
| 1802 | }, |
| 1803 | }); |
| 1804 | try atom.rebases.append(gpa, 0); |
| 1805 | const global = self.getGlobal(self.getSymbolName(target)).?; |
| 1806 | try atom.lazy_bindings.append(gpa, .{ |
| 1807 | .target = global, |
| 1808 | .offset = 0, |
| 1809 | }); |
| 1810 | } |
| 1626 | 1811 | |
| 1627 | 1812 | try self.managed_atoms.append(gpa, atom); |
| 1628 | 1813 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); |
| 1629 | 1814 | |
| 1630 | | try self.allocateAtomCommon(atom); |
| 1815 | if (self.mode == .incremental) { |
| 1816 | sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); |
| 1817 | log.debug("allocated lazy pointer atom at 0x{x}", .{sym.n_value}); |
| 1818 | try self.writePtrWidthAtom(atom); |
| 1819 | } else { |
| 1820 | try self.addAtomToSection(atom); |
| 1821 | } |
| 1631 | 1822 | |
| 1632 | 1823 | return atom; |
| 1633 | 1824 | } |
| ... | ... | @@ -1640,62 +1831,112 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { |
| 1640 | 1831 | .aarch64 => 2, |
| 1641 | 1832 | else => unreachable, // unhandled architecture type |
| 1642 | 1833 | }; |
| 1643 | | const stub_size: u4 = switch (arch) { |
| 1834 | const size: u4 = switch (arch) { |
| 1644 | 1835 | .x86_64 => 6, |
| 1645 | 1836 | .aarch64 => 3 * @sizeOf(u32), |
| 1646 | 1837 | else => unreachable, // unhandled architecture type |
| 1647 | 1838 | }; |
| 1648 | 1839 | const sym_index = try self.allocateSymbol(); |
| 1649 | | const atom = try MachO.createEmptyAtom(gpa, sym_index, stub_size, alignment); |
| 1840 | const atom = switch (self.mode) { |
| 1841 | .incremental => blk: { |
| 1842 | const atom = try gpa.create(Atom); |
| 1843 | atom.* = Atom.empty; |
| 1844 | atom.sym_index = sym_index; |
| 1845 | atom.size = size; |
| 1846 | atom.alignment = alignment; |
| 1847 | break :blk atom; |
| 1848 | }, |
| 1849 | .one_shot => try MachO.createEmptyAtom(gpa, sym_index, size, alignment), |
| 1850 | }; |
| 1851 | errdefer gpa.destroy(atom); |
| 1852 | |
| 1650 | 1853 | const sym = atom.getSymbolPtr(self); |
| 1651 | 1854 | sym.n_type = macho.N_SECT; |
| 1652 | 1855 | sym.n_sect = self.stubs_section_index.? + 1; |
| 1653 | 1856 | |
| 1857 | const code = try gpa.alloc(u8, size); |
| 1858 | defer gpa.free(code); |
| 1859 | mem.set(u8, code, 0); |
| 1860 | |
| 1654 | 1861 | switch (arch) { |
| 1655 | 1862 | .x86_64 => { |
| 1656 | 1863 | // jmp |
| 1657 | | atom.code.items[0] = 0xff; |
| 1658 | | atom.code.items[1] = 0x25; |
| 1659 | | try atom.relocs.append(gpa, .{ |
| 1660 | | .offset = 2, |
| 1661 | | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1662 | | .addend = 0, |
| 1663 | | .subtractor = null, |
| 1664 | | .pcrel = true, |
| 1665 | | .length = 2, |
| 1666 | | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), |
| 1667 | | }); |
| 1864 | code[0] = 0xff; |
| 1865 | code[1] = 0x25; |
| 1866 | |
| 1867 | if (self.mode == .incremental) { |
| 1868 | try atom.addRelocation(self, .{ |
| 1869 | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), |
| 1870 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1871 | .offset = 2, |
| 1872 | .addend = 0, |
| 1873 | .pcrel = true, |
| 1874 | .length = 2, |
| 1875 | }); |
| 1876 | } else { |
| 1877 | try atom.relocs.append(gpa, .{ |
| 1878 | .offset = 2, |
| 1879 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1880 | .addend = 0, |
| 1881 | .subtractor = null, |
| 1882 | .pcrel = true, |
| 1883 | .length = 2, |
| 1884 | .@"type" = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), |
| 1885 | }); |
| 1886 | } |
| 1668 | 1887 | }, |
| 1669 | 1888 | .aarch64 => { |
| 1670 | | try atom.relocs.ensureTotalCapacity(gpa, 2); |
| 1671 | 1889 | // adrp x16, pages |
| 1672 | | mem.writeIntLittle(u32, atom.code.items[0..4], aarch64.Instruction.adrp(.x16, 0).toU32()); |
| 1673 | | atom.relocs.appendAssumeCapacity(.{ |
| 1674 | | .offset = 0, |
| 1675 | | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1676 | | .addend = 0, |
| 1677 | | .subtractor = null, |
| 1678 | | .pcrel = true, |
| 1679 | | .length = 2, |
| 1680 | | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), |
| 1681 | | }); |
| 1890 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x16, 0).toU32()); |
| 1682 | 1891 | // ldr x16, x16, offset |
| 1683 | | mem.writeIntLittle(u32, atom.code.items[4..8], aarch64.Instruction.ldr( |
| 1892 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr( |
| 1684 | 1893 | .x16, |
| 1685 | 1894 | .x16, |
| 1686 | 1895 | aarch64.Instruction.LoadStoreOffset.imm(0), |
| 1687 | 1896 | ).toU32()); |
| 1688 | | atom.relocs.appendAssumeCapacity(.{ |
| 1689 | | .offset = 4, |
| 1690 | | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1691 | | .addend = 0, |
| 1692 | | .subtractor = null, |
| 1693 | | .pcrel = false, |
| 1694 | | .length = 2, |
| 1695 | | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), |
| 1696 | | }); |
| 1697 | 1897 | // br x16 |
| 1698 | | mem.writeIntLittle(u32, atom.code.items[8..12], aarch64.Instruction.br(.x16).toU32()); |
| 1898 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); |
| 1899 | |
| 1900 | if (self.mode == .incremental) { |
| 1901 | try atom.addRelocations(self, 2, .{ |
| 1902 | .{ |
| 1903 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), |
| 1904 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1905 | .offset = 0, |
| 1906 | .addend = 0, |
| 1907 | .pcrel = true, |
| 1908 | .length = 2, |
| 1909 | }, |
| 1910 | .{ |
| 1911 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), |
| 1912 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1913 | .offset = 4, |
| 1914 | .addend = 0, |
| 1915 | .pcrel = false, |
| 1916 | .length = 2, |
| 1917 | }, |
| 1918 | }); |
| 1919 | } else { |
| 1920 | try atom.relocs.ensureTotalCapacity(gpa, 2); |
| 1921 | atom.relocs.appendAssumeCapacity(.{ |
| 1922 | .offset = 0, |
| 1923 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1924 | .addend = 0, |
| 1925 | .subtractor = null, |
| 1926 | .pcrel = true, |
| 1927 | .length = 2, |
| 1928 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), |
| 1929 | }); |
| 1930 | atom.relocs.appendAssumeCapacity(.{ |
| 1931 | .offset = 4, |
| 1932 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1933 | .addend = 0, |
| 1934 | .subtractor = null, |
| 1935 | .pcrel = false, |
| 1936 | .length = 2, |
| 1937 | .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), |
| 1938 | }); |
| 1939 | } |
| 1699 | 1940 | }, |
| 1700 | 1941 | else => unreachable, |
| 1701 | 1942 | } |
| ... | ... | @@ -1703,7 +1944,14 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { |
| 1703 | 1944 | try self.managed_atoms.append(gpa, atom); |
| 1704 | 1945 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); |
| 1705 | 1946 | |
| 1706 | | try self.allocateAtomCommon(atom); |
| 1947 | if (self.mode == .incremental) { |
| 1948 | sym.n_value = try self.allocateAtom(atom, size, math.powi(u32, 2, alignment) catch unreachable); |
| 1949 | log.debug("allocated stub atom at 0x{x}", .{sym.n_value}); |
| 1950 | try self.writeAtom(atom, code); |
| 1951 | } else { |
| 1952 | mem.copy(u8, atom.code.items, code); |
| 1953 | try self.addAtomToSection(atom); |
| 1954 | } |
| 1707 | 1955 | |
| 1708 | 1956 | return atom; |
| 1709 | 1957 | } |
| ... | ... | @@ -1976,6 +2224,7 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 1976 | 2224 | const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.sym_index, global); |
| 1977 | 2225 | const stub_atom = try self.createStubAtom(laptr_atom.sym_index); |
| 1978 | 2226 | self.stubs.items[stub_index].sym_index = stub_atom.sym_index; |
| 2227 | self.markRelocsDirtyByTarget(global); |
| 1979 | 2228 | } |
| 1980 | 2229 | |
| 1981 | 2230 | continue :loop; |
| ... | ... | @@ -2073,6 +2322,10 @@ pub fn resolveDyldStubBinder(self: *MachO) !void { |
| 2073 | 2322 | const got_index = try self.allocateGotEntry(global); |
| 2074 | 2323 | const got_atom = try self.createGotAtom(global); |
| 2075 | 2324 | self.got_entries.items[got_index].sym_index = got_atom.sym_index; |
| 2325 | |
| 2326 | if (self.mode == .incremental) { |
| 2327 | try self.writePtrWidthAtom(got_atom); |
| 2328 | } |
| 2076 | 2329 | } |
| 2077 | 2330 | |
| 2078 | 2331 | pub fn writeDylinkerLC(ncmds: *u32, lc_writer: anytype) !void { |
| ... | ... | @@ -2356,6 +2609,30 @@ pub fn deinit(self: *MachO) void { |
| 2356 | 2609 | } |
| 2357 | 2610 | self.relocs.deinit(gpa); |
| 2358 | 2611 | } |
| 2612 | |
| 2613 | { |
| 2614 | var it = self.rebases.valueIterator(); |
| 2615 | while (it.next()) |rebases| { |
| 2616 | rebases.deinit(gpa); |
| 2617 | } |
| 2618 | self.rebases.deinit(gpa); |
| 2619 | } |
| 2620 | |
| 2621 | { |
| 2622 | var it = self.bindings.valueIterator(); |
| 2623 | while (it.next()) |bindings| { |
| 2624 | bindings.deinit(gpa); |
| 2625 | } |
| 2626 | self.bindings.deinit(gpa); |
| 2627 | } |
| 2628 | |
| 2629 | { |
| 2630 | var it = self.lazy_bindings.valueIterator(); |
| 2631 | while (it.next()) |bindings| { |
| 2632 | bindings.deinit(gpa); |
| 2633 | } |
| 2634 | self.lazy_bindings.deinit(gpa); |
| 2635 | } |
| 2359 | 2636 | } |
| 2360 | 2637 | |
| 2361 | 2638 | fn freeAtom(self: *MachO, atom: *Atom, owns_atom: bool) void { |
| ... | ... | @@ -2363,6 +2640,8 @@ fn freeAtom(self: *MachO, atom: *Atom, owns_atom: bool) void { |
| 2363 | 2640 | if (!owns_atom) { |
| 2364 | 2641 | atom.deinit(self.base.allocator); |
| 2365 | 2642 | } |
| 2643 | // Remove any relocs and base relocs associated with this Atom |
| 2644 | self.freeRelocationsForAtom(atom); |
| 2366 | 2645 | |
| 2367 | 2646 | const sect_id = atom.getSymbol(self).n_sect - 1; |
| 2368 | 2647 | const free_list = &self.sections.items(.free_list)[sect_id]; |
| ... | ... | @@ -2569,13 +2848,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 2569 | 2848 | const decl_index = func.owner_decl; |
| 2570 | 2849 | const decl = module.declPtr(decl_index); |
| 2571 | 2850 | self.freeUnnamedConsts(decl_index); |
| 2572 | | |
| 2573 | | // TODO clearing the code and relocs buffer should probably be orchestrated |
| 2574 | | // in a different, smarter, more automatic way somewhere else, in a more centralised |
| 2575 | | // way than this. |
| 2576 | | // If we don't clear the buffers here, we are up for some nasty surprises when |
| 2577 | | // this atom is reused later on and was not freed by freeAtom(). |
| 2578 | | decl.link.macho.clearRetainingCapacity(); |
| 2851 | self.freeRelocationsForAtom(&decl.link.macho); |
| 2579 | 2852 | |
| 2580 | 2853 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2581 | 2854 | defer code_buffer.deinit(); |
| ... | ... | @@ -2593,18 +2866,16 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 2593 | 2866 | else |
| 2594 | 2867 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); |
| 2595 | 2868 | |
| 2596 | | switch (res) { |
| 2597 | | .appended => { |
| 2598 | | try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items); |
| 2599 | | }, |
| 2869 | const code = switch (res) { |
| 2870 | .appended => code_buffer.items, |
| 2600 | 2871 | .fail => |em| { |
| 2601 | 2872 | decl.analysis = .codegen_failure; |
| 2602 | 2873 | try module.failed_decls.put(module.gpa, decl_index, em); |
| 2603 | 2874 | return; |
| 2604 | 2875 | }, |
| 2605 | | } |
| 2876 | }; |
| 2606 | 2877 | |
| 2607 | | const addr = try self.placeDecl(decl_index, decl.link.macho.code.items.len); |
| 2878 | const addr = try self.updateDeclCode(decl_index, code); |
| 2608 | 2879 | |
| 2609 | 2880 | if (decl_state) |*ds| { |
| 2610 | 2881 | try self.d_sym.?.dwarf.commitDeclState( |
| ... | ... | @@ -2650,20 +2921,17 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 2650 | 2921 | |
| 2651 | 2922 | log.debug("allocating symbol indexes for {?s}", .{name}); |
| 2652 | 2923 | |
| 2653 | | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); |
| 2654 | | const sym_index = try self.allocateSymbol(); |
| 2655 | | const atom = try MachO.createEmptyAtom( |
| 2656 | | gpa, |
| 2657 | | sym_index, |
| 2658 | | @sizeOf(u64), |
| 2659 | | math.log2(required_alignment), |
| 2660 | | ); |
| 2924 | const atom = try gpa.create(Atom); |
| 2925 | errdefer gpa.destroy(atom); |
| 2926 | atom.* = Atom.empty; |
| 2927 | |
| 2928 | atom.sym_index = try self.allocateSymbol(); |
| 2661 | 2929 | |
| 2662 | 2930 | try self.managed_atoms.append(gpa, atom); |
| 2663 | | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); |
| 2931 | try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); |
| 2664 | 2932 | |
| 2665 | 2933 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{ |
| 2666 | | .parent_atom_index = sym_index, |
| 2934 | .parent_atom_index = atom.sym_index, |
| 2667 | 2935 | }); |
| 2668 | 2936 | const code = switch (res) { |
| 2669 | 2937 | .externally_managed => |x| x, |
| ... | ... | @@ -2676,9 +2944,9 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 2676 | 2944 | }, |
| 2677 | 2945 | }; |
| 2678 | 2946 | |
| 2679 | | atom.code.clearRetainingCapacity(); |
| 2680 | | try atom.code.appendSlice(gpa, code); |
| 2681 | | |
| 2947 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); |
| 2948 | atom.size = code.len; |
| 2949 | atom.alignment = math.log2(required_alignment); |
| 2682 | 2950 | const sect_id = try self.getOutputSectionAtom( |
| 2683 | 2951 | atom, |
| 2684 | 2952 | decl_name, |
| ... | ... | @@ -2691,13 +2959,14 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 2691 | 2959 | symbol.n_type = macho.N_SECT; |
| 2692 | 2960 | symbol.n_sect = sect_id + 1; |
| 2693 | 2961 | symbol.n_value = try self.allocateAtom(atom, code.len, required_alignment); |
| 2962 | errdefer self.freeAtom(atom, true); |
| 2963 | |
| 2964 | try unnamed_consts.append(gpa, atom); |
| 2694 | 2965 | |
| 2695 | 2966 | log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value }); |
| 2696 | 2967 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 2697 | 2968 | |
| 2698 | | errdefer self.freeAtom(atom, true); |
| 2699 | | |
| 2700 | | try unnamed_consts.append(gpa, atom); |
| 2969 | try self.writeAtom(atom, code); |
| 2701 | 2970 | |
| 2702 | 2971 | return atom.sym_index; |
| 2703 | 2972 | } |
| ... | ... | @@ -2724,6 +2993,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2724 | 2993 | } |
| 2725 | 2994 | } |
| 2726 | 2995 | |
| 2996 | self.freeRelocationsForAtom(&decl.link.macho); |
| 2997 | |
| 2727 | 2998 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2728 | 2999 | defer code_buffer.deinit(); |
| 2729 | 3000 | |
| ... | ... | @@ -2751,27 +3022,16 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2751 | 3022 | .parent_atom_index = decl.link.macho.sym_index, |
| 2752 | 3023 | }); |
| 2753 | 3024 | |
| 2754 | | const code = blk: { |
| 2755 | | switch (res) { |
| 2756 | | .externally_managed => |x| break :blk x, |
| 2757 | | .appended => { |
| 2758 | | // TODO clearing the code and relocs buffer should probably be orchestrated |
| 2759 | | // in a different, smarter, more automatic way somewhere else, in a more centralised |
| 2760 | | // way than this. |
| 2761 | | // If we don't clear the buffers here, we are up for some nasty surprises when |
| 2762 | | // this atom is reused later on and was not freed by freeAtom(). |
| 2763 | | decl.link.macho.code.clearAndFree(self.base.allocator); |
| 2764 | | try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items); |
| 2765 | | break :blk decl.link.macho.code.items; |
| 2766 | | }, |
| 2767 | | .fail => |em| { |
| 2768 | | decl.analysis = .codegen_failure; |
| 2769 | | try module.failed_decls.put(module.gpa, decl_index, em); |
| 2770 | | return; |
| 2771 | | }, |
| 2772 | | } |
| 3025 | const code = switch (res) { |
| 3026 | .externally_managed => |x| x, |
| 3027 | .appended => code_buffer.items, |
| 3028 | .fail => |em| { |
| 3029 | decl.analysis = .codegen_failure; |
| 3030 | try module.failed_decls.put(module.gpa, decl_index, em); |
| 3031 | return; |
| 3032 | }, |
| 2773 | 3033 | }; |
| 2774 | | const addr = try self.placeDecl(decl_index, code.len); |
| 3034 | const addr = try self.updateDeclCode(decl_index, code); |
| 2775 | 3035 | |
| 2776 | 3036 | if (decl_state) |*ds| { |
| 2777 | 3037 | try self.d_sym.?.dwarf.commitDeclState( |
| ... | ... | @@ -2936,19 +3196,22 @@ fn getOutputSectionAtom( |
| 2936 | 3196 | return sect_id; |
| 2937 | 3197 | } |
| 2938 | 3198 | |
| 2939 | | fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64 { |
| 2940 | | const module = self.base.options.module.?; |
| 2941 | | const decl = module.declPtr(decl_index); |
| 3199 | fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) !u64 { |
| 3200 | const gpa = self.base.allocator; |
| 3201 | const mod = self.base.options.module.?; |
| 3202 | const decl = mod.declPtr(decl_index); |
| 3203 | |
| 2942 | 3204 | const required_alignment = decl.getAlignment(self.base.options.target); |
| 2943 | 3205 | assert(decl.link.macho.sym_index != 0); // Caller forgot to call allocateDeclIndexes() |
| 2944 | 3206 | |
| 2945 | | const sym_name = try decl.getFullyQualifiedName(module); |
| 3207 | const sym_name = try decl.getFullyQualifiedName(mod); |
| 2946 | 3208 | defer self.base.allocator.free(sym_name); |
| 2947 | 3209 | |
| 3210 | const atom = &decl.link.macho; |
| 2948 | 3211 | const decl_ptr = self.decls.getPtr(decl_index).?; |
| 2949 | 3212 | if (decl_ptr.* == null) { |
| 2950 | 3213 | decl_ptr.* = try self.getOutputSectionAtom( |
| 2951 | | &decl.link.macho, |
| 3214 | atom, |
| 2952 | 3215 | sym_name, |
| 2953 | 3216 | decl.ty, |
| 2954 | 3217 | decl.val, |
| ... | ... | @@ -2956,55 +3219,63 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64 |
| 2956 | 3219 | ); |
| 2957 | 3220 | } |
| 2958 | 3221 | const sect_id = decl_ptr.*.?; |
| 3222 | const code_len = code.len; |
| 2959 | 3223 | |
| 2960 | | if (decl.link.macho.size != 0) { |
| 2961 | | const symbol = decl.link.macho.getSymbolPtr(self); |
| 2962 | | symbol.n_strx = try self.strtab.insert(self.base.allocator, sym_name); |
| 2963 | | symbol.n_type = macho.N_SECT; |
| 2964 | | symbol.n_sect = sect_id + 1; |
| 2965 | | symbol.n_desc = 0; |
| 3224 | if (atom.size != 0) { |
| 3225 | const sym = atom.getSymbolPtr(self); |
| 3226 | sym.n_strx = try self.strtab.insert(gpa, sym_name); |
| 3227 | sym.n_type = macho.N_SECT; |
| 3228 | sym.n_sect = sect_id + 1; |
| 3229 | sym.n_desc = 0; |
| 2966 | 3230 | |
| 2967 | 3231 | const capacity = decl.link.macho.capacity(self); |
| 2968 | | const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment); |
| 3232 | const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment); |
| 2969 | 3233 | |
| 2970 | 3234 | if (need_realloc) { |
| 2971 | | const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment); |
| 2972 | | log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, symbol.n_value, vaddr }); |
| 3235 | const vaddr = try self.growAtom(atom, code_len, required_alignment); |
| 3236 | log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, sym.n_value, vaddr }); |
| 2973 | 3237 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 2974 | | symbol.n_value = vaddr; |
| 2975 | | |
| 2976 | | const got_atom = self.getGotAtomForSymbol(.{ |
| 2977 | | .sym_index = decl.link.macho.sym_index, |
| 2978 | | .file = null, |
| 2979 | | }).?; |
| 2980 | | got_atom.dirty = true; |
| 2981 | | } else if (code_len < decl.link.macho.size) { |
| 2982 | | self.shrinkAtom(&decl.link.macho, code_len); |
| 2983 | | } |
| 2984 | 3238 | |
| 2985 | | decl.link.macho.size = code_len; |
| 2986 | | decl.link.macho.dirty = true; |
| 3239 | if (vaddr != sym.n_value) { |
| 3240 | sym.n_value = vaddr; |
| 3241 | log.debug(" (updating GOT entry)", .{}); |
| 3242 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 3243 | const got_atom = self.getGotAtomForSymbol(got_target).?; |
| 3244 | self.markRelocsDirtyByTarget(got_target); |
| 3245 | try self.writePtrWidthAtom(got_atom); |
| 3246 | } |
| 3247 | } else if (code_len < atom.size) { |
| 3248 | self.shrinkAtom(atom, code_len); |
| 3249 | } |
| 3250 | atom.size = code_len; |
| 2987 | 3251 | } else { |
| 2988 | | const name_str_index = try self.strtab.insert(self.base.allocator, sym_name); |
| 2989 | | const symbol = decl.link.macho.getSymbolPtr(self); |
| 2990 | | symbol.n_strx = name_str_index; |
| 2991 | | symbol.n_type = macho.N_SECT; |
| 2992 | | symbol.n_sect = sect_id + 1; |
| 2993 | | symbol.n_desc = 0; |
| 2994 | | symbol.n_value = try self.allocateAtom(&decl.link.macho, code_len, required_alignment); |
| 2995 | | |
| 2996 | | log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, symbol.n_value }); |
| 3252 | const name_str_index = try self.strtab.insert(gpa, sym_name); |
| 3253 | const sym = atom.getSymbolPtr(self); |
| 3254 | sym.n_strx = name_str_index; |
| 3255 | sym.n_type = macho.N_SECT; |
| 3256 | sym.n_sect = sect_id + 1; |
| 3257 | sym.n_desc = 0; |
| 3258 | |
| 3259 | const vaddr = try self.allocateAtom(atom, code_len, required_alignment); |
| 3260 | errdefer self.freeAtom(atom, false); |
| 3261 | |
| 3262 | log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, vaddr }); |
| 2997 | 3263 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 2998 | 3264 | |
| 2999 | | errdefer self.freeAtom(&decl.link.macho, false); |
| 3265 | atom.size = code_len; |
| 3266 | sym.n_value = vaddr; |
| 3000 | 3267 | |
| 3001 | | const got_target = SymbolWithLoc{ .sym_index = decl.link.macho.sym_index, .file = null }; |
| 3268 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 3002 | 3269 | const got_index = try self.allocateGotEntry(got_target); |
| 3003 | 3270 | const got_atom = try self.createGotAtom(got_target); |
| 3004 | 3271 | self.got_entries.items[got_index].sym_index = got_atom.sym_index; |
| 3272 | try self.writePtrWidthAtom(got_atom); |
| 3005 | 3273 | } |
| 3006 | 3274 | |
| 3007 | | return decl.link.macho.getSymbol(self).n_value; |
| 3275 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); |
| 3276 | try self.writeAtom(atom, code); |
| 3277 | |
| 3278 | return atom.getSymbol(self).n_value; |
| 3008 | 3279 | } |
| 3009 | 3280 | |
| 3010 | 3281 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void { |
| ... | ... | @@ -3152,17 +3423,25 @@ pub fn deleteExport(self: *MachO, exp: Export) void { |
| 3152 | 3423 | } |
| 3153 | 3424 | } |
| 3154 | 3425 | |
| 3426 | fn freeRelocationsForAtom(self: *MachO, atom: *Atom) void { |
| 3427 | _ = self.relocs.remove(atom); |
| 3428 | _ = self.rebases.remove(atom); |
| 3429 | _ = self.bindings.remove(atom); |
| 3430 | _ = self.lazy_bindings.remove(atom); |
| 3431 | } |
| 3432 | |
| 3155 | 3433 | fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void { |
| 3434 | const gpa = self.base.allocator; |
| 3156 | 3435 | const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; |
| 3157 | 3436 | for (unnamed_consts.items) |atom| { |
| 3158 | 3437 | self.freeAtom(atom, true); |
| 3159 | | self.locals_free_list.append(self.base.allocator, atom.sym_index) catch {}; |
| 3438 | self.locals_free_list.append(gpa, atom.sym_index) catch {}; |
| 3160 | 3439 | self.locals.items[atom.sym_index].n_type = 0; |
| 3161 | 3440 | _ = self.atom_by_index_table.remove(atom.sym_index); |
| 3162 | 3441 | log.debug(" adding local symbol index {d} to free list", .{atom.sym_index}); |
| 3163 | 3442 | atom.sym_index = 0; |
| 3164 | 3443 | } |
| 3165 | | unnamed_consts.clearAndFree(self.base.allocator); |
| 3444 | unnamed_consts.clearAndFree(gpa); |
| 3166 | 3445 | } |
| 3167 | 3446 | |
| 3168 | 3447 | pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { |
| ... | ... | @@ -3171,20 +3450,25 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { |
| 3171 | 3450 | } |
| 3172 | 3451 | const mod = self.base.options.module.?; |
| 3173 | 3452 | const decl = mod.declPtr(decl_index); |
| 3453 | |
| 3174 | 3454 | log.debug("freeDecl {*}", .{decl}); |
| 3455 | |
| 3175 | 3456 | const kv = self.decls.fetchSwapRemove(decl_index); |
| 3176 | 3457 | if (kv.?.value) |_| { |
| 3177 | 3458 | self.freeAtom(&decl.link.macho, false); |
| 3178 | 3459 | self.freeUnnamedConsts(decl_index); |
| 3179 | 3460 | } |
| 3461 | |
| 3180 | 3462 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 3181 | | if (decl.link.macho.sym_index != 0) { |
| 3182 | | self.locals_free_list.append(self.base.allocator, decl.link.macho.sym_index) catch {}; |
| 3463 | const gpa = self.base.allocator; |
| 3464 | const sym_index = decl.link.macho.sym_index; |
| 3465 | if (sym_index != 0) { |
| 3466 | self.locals_free_list.append(gpa, sym_index) catch {}; |
| 3183 | 3467 | |
| 3184 | 3468 | // Try freeing GOT atom if this decl had one |
| 3185 | | const got_target = SymbolWithLoc{ .sym_index = decl.link.macho.sym_index, .file = null }; |
| 3469 | const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 3186 | 3470 | if (self.got_entries_table.get(got_target)) |got_index| { |
| 3187 | | self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {}; |
| 3471 | self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {}; |
| 3188 | 3472 | self.got_entries.items[got_index] = .{ |
| 3189 | 3473 | .target = .{ .sym_index = 0, .file = null }, |
| 3190 | 3474 | .sym_index = 0, |
| ... | ... | @@ -3192,20 +3476,18 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { |
| 3192 | 3476 | _ = self.got_entries_table.remove(got_target); |
| 3193 | 3477 | |
| 3194 | 3478 | if (self.d_sym) |*d_sym| { |
| 3195 | | d_sym.swapRemoveRelocs(decl.link.macho.sym_index); |
| 3479 | d_sym.swapRemoveRelocs(sym_index); |
| 3196 | 3480 | } |
| 3197 | 3481 | |
| 3198 | | log.debug(" adding GOT index {d} to free list (target local@{d})", .{ |
| 3199 | | got_index, |
| 3200 | | decl.link.macho.sym_index, |
| 3201 | | }); |
| 3482 | log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); |
| 3202 | 3483 | } |
| 3203 | 3484 | |
| 3204 | | self.locals.items[decl.link.macho.sym_index].n_type = 0; |
| 3205 | | _ = self.atom_by_index_table.remove(decl.link.macho.sym_index); |
| 3206 | | log.debug(" adding local symbol index {d} to free list", .{decl.link.macho.sym_index}); |
| 3485 | self.locals.items[sym_index].n_type = 0; |
| 3486 | _ = self.atom_by_index_table.remove(sym_index); |
| 3487 | log.debug(" adding local symbol index {d} to free list", .{sym_index}); |
| 3207 | 3488 | decl.link.macho.sym_index = 0; |
| 3208 | 3489 | } |
| 3490 | |
| 3209 | 3491 | if (self.d_sym) |*d_sym| { |
| 3210 | 3492 | d_sym.dwarf.freeDecl(decl); |
| 3211 | 3493 | } |
| ... | ... | @@ -3218,21 +3500,20 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil |
| 3218 | 3500 | assert(self.llvm_object == null); |
| 3219 | 3501 | assert(decl.link.macho.sym_index != 0); |
| 3220 | 3502 | |
| 3221 | | const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?; |
| 3222 | | try atom.relocs.append(self.base.allocator, .{ |
| 3223 | | .offset = @intCast(u32, reloc_info.offset), |
| 3224 | | .target = .{ .sym_index = decl.link.macho.sym_index, .file = null }, |
| 3225 | | .addend = reloc_info.addend, |
| 3226 | | .subtractor = null, |
| 3227 | | .pcrel = false, |
| 3228 | | .length = 3, |
| 3503 | const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; |
| 3504 | try atom.addRelocation(self, .{ |
| 3229 | 3505 | .@"type" = switch (self.base.options.target.cpu.arch) { |
| 3230 | 3506 | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| 3231 | 3507 | .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| 3232 | 3508 | else => unreachable, |
| 3233 | 3509 | }, |
| 3510 | .target = .{ .sym_index = decl.link.macho.sym_index, .file = null }, |
| 3511 | .offset = @intCast(u32, reloc_info.offset), |
| 3512 | .addend = reloc_info.addend, |
| 3513 | .pcrel = false, |
| 3514 | .length = 3, |
| 3234 | 3515 | }); |
| 3235 | | try atom.rebases.append(self.base.allocator, reloc_info.offset); |
| 3516 | try atom.addRebase(self, @intCast(u32, reloc_info.offset)); |
| 3236 | 3517 | |
| 3237 | 3518 | return 0; |
| 3238 | 3519 | } |
| ... | ... | @@ -3575,6 +3856,7 @@ fn allocateSection(self: *MachO, sect_id: u8, size: u64, alignment: u32) !void { |
| 3575 | 3856 | |
| 3576 | 3857 | if (size > max_size) { |
| 3577 | 3858 | try self.growSection(sect_id, @intCast(u32, size)); |
| 3859 | self.markRelocsDirtyByAddress(header.addr + size); |
| 3578 | 3860 | } |
| 3579 | 3861 | |
| 3580 | 3862 | log.debug("allocating {s},{s} section at 0x{x}", .{ header.segName(), header.sectName(), off }); |
| ... | ... | @@ -3885,7 +4167,13 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! |
| 3885 | 4167 | const header = &self.sections.items(.header)[sect_id]; |
| 3886 | 4168 | const free_list = &self.sections.items(.free_list)[sect_id]; |
| 3887 | 4169 | const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; |
| 3888 | | const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size; |
| 4170 | const requires_padding = blk: { |
| 4171 | if (!header.isCode()) break :blk false; |
| 4172 | if (mem.eql(u8, "__stubs", header.sectName())) break :blk false; |
| 4173 | if (mem.eql(u8, "__stub_helper", header.sectName())) break :blk false; |
| 4174 | break :blk true; |
| 4175 | }; |
| 4176 | const new_atom_ideal_capacity = if (requires_padding) padToIdeal(new_atom_size) else new_atom_size; |
| 3889 | 4177 | |
| 3890 | 4178 | // We use these to indicate our intention to update metadata, placing the new atom, |
| 3891 | 4179 | // and possibly removing a free list node. |
| ... | ... | @@ -3905,7 +4193,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! |
| 3905 | 4193 | // Is it enough that we could fit this new atom? |
| 3906 | 4194 | const sym = big_atom.getSymbol(self); |
| 3907 | 4195 | const capacity = big_atom.capacity(self); |
| 3908 | | const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity; |
| 4196 | const ideal_capacity = if (requires_padding) padToIdeal(capacity) else capacity; |
| 3909 | 4197 | const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity; |
| 3910 | 4198 | const capacity_end_vaddr = sym.n_value + capacity; |
| 3911 | 4199 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; |
| ... | ... | @@ -3935,7 +4223,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! |
| 3935 | 4223 | break :blk new_start_vaddr; |
| 3936 | 4224 | } else if (maybe_last_atom.*) |last| { |
| 3937 | 4225 | const last_symbol = last.getSymbol(self); |
| 3938 | | const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size; |
| 4226 | const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size; |
| 3939 | 4227 | const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity; |
| 3940 | 4228 | const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); |
| 3941 | 4229 | atom_placement = last; |
| ... | ... | @@ -3949,6 +4237,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! |
| 3949 | 4237 | if (expand_section) { |
| 3950 | 4238 | const needed_size = @intCast(u32, (vaddr + new_atom_size) - header.addr); |
| 3951 | 4239 | try self.growSection(sect_id, needed_size); |
| 4240 | self.markRelocsDirtyByAddress(header.addr + needed_size); |
| 3952 | 4241 | maybe_last_atom.* = atom; |
| 3953 | 4242 | header.size = needed_size; |
| 3954 | 4243 | } |
| ... | ... | @@ -4105,64 +4394,70 @@ pub fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4105 | 4394 | const sym = atom.getSymbol(self); |
| 4106 | 4395 | const base_offset = sym.n_value - seg.vmaddr; |
| 4107 | 4396 | |
| 4108 | | for (atom.rebases.items) |offset| { |
| 4109 | | log.debug(" | rebase at {x}", .{base_offset + offset}); |
| 4110 | | try rebase_pointers.append(.{ |
| 4111 | | .offset = base_offset + offset, |
| 4112 | | .segment_id = segment_index, |
| 4113 | | }); |
| 4397 | if (self.rebases.get(atom)) |rebases| { |
| 4398 | for (rebases.items) |offset| { |
| 4399 | log.debug(" | rebase at {x}", .{base_offset + offset}); |
| 4400 | try rebase_pointers.append(.{ |
| 4401 | .offset = base_offset + offset, |
| 4402 | .segment_id = segment_index, |
| 4403 | }); |
| 4404 | } |
| 4114 | 4405 | } |
| 4115 | 4406 | |
| 4116 | | for (atom.bindings.items) |binding| { |
| 4117 | | const bind_sym = self.getSymbol(binding.target); |
| 4118 | | const bind_sym_name = self.getSymbolName(binding.target); |
| 4119 | | const dylib_ordinal = @divTrunc( |
| 4120 | | @bitCast(i16, bind_sym.n_desc), |
| 4121 | | macho.N_SYMBOL_RESOLVER, |
| 4122 | | ); |
| 4123 | | var flags: u4 = 0; |
| 4124 | | log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{ |
| 4125 | | binding.offset + base_offset, |
| 4126 | | bind_sym_name, |
| 4127 | | dylib_ordinal, |
| 4128 | | }); |
| 4129 | | if (bind_sym.weakRef()) { |
| 4130 | | log.debug(" | marking as weak ref ", .{}); |
| 4131 | | flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT); |
| 4407 | if (self.bindings.get(atom)) |bindings| { |
| 4408 | for (bindings.items) |binding| { |
| 4409 | const bind_sym = self.getSymbol(binding.target); |
| 4410 | const bind_sym_name = self.getSymbolName(binding.target); |
| 4411 | const dylib_ordinal = @divTrunc( |
| 4412 | @bitCast(i16, bind_sym.n_desc), |
| 4413 | macho.N_SYMBOL_RESOLVER, |
| 4414 | ); |
| 4415 | var flags: u4 = 0; |
| 4416 | log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{ |
| 4417 | binding.offset + base_offset, |
| 4418 | bind_sym_name, |
| 4419 | dylib_ordinal, |
| 4420 | }); |
| 4421 | if (bind_sym.weakRef()) { |
| 4422 | log.debug(" | marking as weak ref ", .{}); |
| 4423 | flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT); |
| 4424 | } |
| 4425 | try bind_pointers.append(.{ |
| 4426 | .offset = binding.offset + base_offset, |
| 4427 | .segment_id = segment_index, |
| 4428 | .dylib_ordinal = dylib_ordinal, |
| 4429 | .name = bind_sym_name, |
| 4430 | .bind_flags = flags, |
| 4431 | }); |
| 4132 | 4432 | } |
| 4133 | | try bind_pointers.append(.{ |
| 4134 | | .offset = binding.offset + base_offset, |
| 4135 | | .segment_id = segment_index, |
| 4136 | | .dylib_ordinal = dylib_ordinal, |
| 4137 | | .name = bind_sym_name, |
| 4138 | | .bind_flags = flags, |
| 4139 | | }); |
| 4140 | 4433 | } |
| 4141 | 4434 | |
| 4142 | | for (atom.lazy_bindings.items) |binding| { |
| 4143 | | const bind_sym = self.getSymbol(binding.target); |
| 4144 | | const bind_sym_name = self.getSymbolName(binding.target); |
| 4145 | | const dylib_ordinal = @divTrunc( |
| 4146 | | @bitCast(i16, bind_sym.n_desc), |
| 4147 | | macho.N_SYMBOL_RESOLVER, |
| 4148 | | ); |
| 4149 | | var flags: u4 = 0; |
| 4150 | | log.debug(" | lazy bind at {x} import('{s}') ord({d})", .{ |
| 4151 | | binding.offset + base_offset, |
| 4152 | | bind_sym_name, |
| 4153 | | dylib_ordinal, |
| 4154 | | }); |
| 4155 | | if (bind_sym.weakRef()) { |
| 4156 | | log.debug(" | marking as weak ref ", .{}); |
| 4157 | | flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT); |
| 4435 | if (self.lazy_bindings.get(atom)) |lazy_bindings| { |
| 4436 | for (lazy_bindings.items) |binding| { |
| 4437 | const bind_sym = self.getSymbol(binding.target); |
| 4438 | const bind_sym_name = self.getSymbolName(binding.target); |
| 4439 | const dylib_ordinal = @divTrunc( |
| 4440 | @bitCast(i16, bind_sym.n_desc), |
| 4441 | macho.N_SYMBOL_RESOLVER, |
| 4442 | ); |
| 4443 | var flags: u4 = 0; |
| 4444 | log.debug(" | lazy bind at {x} import('{s}') ord({d})", .{ |
| 4445 | binding.offset + base_offset, |
| 4446 | bind_sym_name, |
| 4447 | dylib_ordinal, |
| 4448 | }); |
| 4449 | if (bind_sym.weakRef()) { |
| 4450 | log.debug(" | marking as weak ref ", .{}); |
| 4451 | flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT); |
| 4452 | } |
| 4453 | try lazy_bind_pointers.append(.{ |
| 4454 | .offset = binding.offset + base_offset, |
| 4455 | .segment_id = segment_index, |
| 4456 | .dylib_ordinal = dylib_ordinal, |
| 4457 | .name = bind_sym_name, |
| 4458 | .bind_flags = flags, |
| 4459 | }); |
| 4158 | 4460 | } |
| 4159 | | try lazy_bind_pointers.append(.{ |
| 4160 | | .offset = binding.offset + base_offset, |
| 4161 | | .segment_id = segment_index, |
| 4162 | | .dylib_ordinal = dylib_ordinal, |
| 4163 | | .name = bind_sym_name, |
| 4164 | | .bind_flags = flags, |
| 4165 | | }); |
| 4166 | 4461 | } |
| 4167 | 4462 | |
| 4168 | 4463 | if (atom.prev) |prev| { |
| ... | ... | @@ -4387,25 +4682,25 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 4387 | 4682 | |
| 4388 | 4683 | const asc_u64 = std.sort.asc(u64); |
| 4389 | 4684 | |
| 4390 | | fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4685 | pub fn writeFunctionStarts(macho_file: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4391 | 4686 | const tracy = trace(@src()); |
| 4392 | 4687 | defer tracy.end(); |
| 4393 | 4688 | |
| 4394 | | const text_seg_index = self.text_segment_cmd_index orelse return; |
| 4395 | | const text_sect_index = self.text_section_index orelse return; |
| 4396 | | const text_seg = self.segments.items[text_seg_index]; |
| 4689 | const text_seg_index = macho_file.text_segment_cmd_index orelse return; |
| 4690 | const text_sect_index = macho_file.text_section_index orelse return; |
| 4691 | const text_seg = macho_file.segments.items[text_seg_index]; |
| 4397 | 4692 | |
| 4398 | | const gpa = self.base.allocator; |
| 4693 | const gpa = macho_file.base.allocator; |
| 4399 | 4694 | |
| 4400 | 4695 | // We need to sort by address first |
| 4401 | 4696 | var addresses = std.ArrayList(u64).init(gpa); |
| 4402 | 4697 | defer addresses.deinit(); |
| 4403 | | try addresses.ensureTotalCapacityPrecise(self.globals.items.len); |
| 4698 | try addresses.ensureTotalCapacityPrecise(macho_file.globals.items.len); |
| 4404 | 4699 | |
| 4405 | | for (self.globals.items) |global| { |
| 4406 | | const sym = self.getSymbol(global); |
| 4700 | for (macho_file.globals.items) |global| { |
| 4701 | const sym = macho_file.getSymbol(global); |
| 4407 | 4702 | if (sym.undf()) continue; |
| 4408 | | if (sym.n_desc == N_DESC_GCED) continue; |
| 4703 | if (sym.n_desc == MachO.N_DESC_GCED) continue; |
| 4409 | 4704 | const sect_id = sym.n_sect - 1; |
| 4410 | 4705 | if (sect_id != text_sect_index) continue; |
| 4411 | 4706 | |
| ... | ... | @@ -4439,14 +4734,14 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4439 | 4734 | try std.leb.writeULEB128(buffer.writer(), offset); |
| 4440 | 4735 | } |
| 4441 | 4736 | |
| 4442 | | const link_seg = &self.segments.items[self.linkedit_segment_cmd_index.?]; |
| 4737 | const link_seg = &macho_file.segments.items[macho_file.linkedit_segment_cmd_index.?]; |
| 4443 | 4738 | const offset = mem.alignForwardGeneric(u64, link_seg.fileoff + link_seg.filesize, @alignOf(u64)); |
| 4444 | 4739 | const needed_size = buffer.items.len; |
| 4445 | 4740 | link_seg.filesize = offset + needed_size - link_seg.fileoff; |
| 4446 | 4741 | |
| 4447 | 4742 | log.debug("writing function starts info from 0x{x} to 0x{x}", .{ offset, offset + needed_size }); |
| 4448 | 4743 | |
| 4449 | | try self.base.file.?.pwriteAll(buffer.items, offset); |
| 4744 | try macho_file.base.file.?.pwriteAll(buffer.items, offset); |
| 4450 | 4745 | |
| 4451 | 4746 | try lc_writer.writeStruct(macho.linkedit_data_command{ |
| 4452 | 4747 | .cmd = .FUNCTION_STARTS, |
| ... | ... | @@ -4465,8 +4760,8 @@ fn filterDataInCode( |
| 4465 | 4760 | const Predicate = struct { |
| 4466 | 4761 | addr: u64, |
| 4467 | 4762 | |
| 4468 | | pub fn predicate(self: @This(), dice: macho.data_in_code_entry) bool { |
| 4469 | | return dice.offset >= self.addr; |
| 4763 | pub fn predicate(macho_file: @This(), dice: macho.data_in_code_entry) bool { |
| 4764 | return dice.offset >= macho_file.addr; |
| 4470 | 4765 | } |
| 4471 | 4766 | }; |
| 4472 | 4767 | |
| ... | ... | @@ -4476,26 +4771,26 @@ fn filterDataInCode( |
| 4476 | 4771 | return dices[start..end]; |
| 4477 | 4772 | } |
| 4478 | 4773 | |
| 4479 | | fn writeDataInCode(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4774 | pub fn writeDataInCode(macho_file: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4480 | 4775 | const tracy = trace(@src()); |
| 4481 | 4776 | defer tracy.end(); |
| 4482 | 4777 | |
| 4483 | | var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.base.allocator); |
| 4778 | var out_dice = std.ArrayList(macho.data_in_code_entry).init(macho_file.base.allocator); |
| 4484 | 4779 | defer out_dice.deinit(); |
| 4485 | 4780 | |
| 4486 | | const text_sect_id = self.text_section_index orelse return; |
| 4487 | | const text_sect_header = self.sections.items(.header)[text_sect_id]; |
| 4781 | const text_sect_id = macho_file.text_section_index orelse return; |
| 4782 | const text_sect_header = macho_file.sections.items(.header)[text_sect_id]; |
| 4488 | 4783 | |
| 4489 | | for (self.objects.items) |object| { |
| 4784 | for (macho_file.objects.items) |object| { |
| 4490 | 4785 | const dice = object.parseDataInCode() orelse continue; |
| 4491 | 4786 | try out_dice.ensureUnusedCapacity(dice.len); |
| 4492 | 4787 | |
| 4493 | 4788 | for (object.managed_atoms.items) |atom| { |
| 4494 | | const sym = atom.getSymbol(self); |
| 4495 | | if (sym.n_desc == N_DESC_GCED) continue; |
| 4789 | const sym = atom.getSymbol(macho_file); |
| 4790 | if (sym.n_desc == MachO.N_DESC_GCED) continue; |
| 4496 | 4791 | |
| 4497 | 4792 | const sect_id = sym.n_sect - 1; |
| 4498 | | if (sect_id != self.text_section_index.?) { |
| 4793 | if (sect_id != macho_file.text_section_index.?) { |
| 4499 | 4794 | continue; |
| 4500 | 4795 | } |
| 4501 | 4796 | |
| ... | ... | @@ -4516,14 +4811,14 @@ fn writeDataInCode(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4516 | 4811 | } |
| 4517 | 4812 | } |
| 4518 | 4813 | |
| 4519 | | const seg = &self.segments.items[self.linkedit_segment_cmd_index.?]; |
| 4814 | const seg = &macho_file.segments.items[macho_file.linkedit_segment_cmd_index.?]; |
| 4520 | 4815 | const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64)); |
| 4521 | 4816 | const needed_size = out_dice.items.len * @sizeOf(macho.data_in_code_entry); |
| 4522 | 4817 | seg.filesize = offset + needed_size - seg.fileoff; |
| 4523 | 4818 | |
| 4524 | 4819 | log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ offset, offset + needed_size }); |
| 4525 | 4820 | |
| 4526 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(out_dice.items), offset); |
| 4821 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(out_dice.items), offset); |
| 4527 | 4822 | try lc_writer.writeStruct(macho.linkedit_data_command{ |
| 4528 | 4823 | .cmd = .DATA_IN_CODE, |
| 4529 | 4824 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| ... | ... | @@ -4533,7 +4828,7 @@ fn writeDataInCode(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4533 | 4828 | ncmds.* += 1; |
| 4534 | 4829 | } |
| 4535 | 4830 | |
| 4536 | | fn writeSymtabs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4831 | pub fn writeSymtabs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4537 | 4832 | var symtab_cmd = macho.symtab_command{ |
| 4538 | 4833 | .cmdsize = @sizeOf(macho.symtab_command), |
| 4539 | 4834 | .symoff = 0, |
| ... | ... | @@ -4571,7 +4866,7 @@ fn writeSymtabs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4571 | 4866 | ncmds.* += 2; |
| 4572 | 4867 | } |
| 4573 | 4868 | |
| 4574 | | fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx { |
| 4869 | pub fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx { |
| 4575 | 4870 | const gpa = self.base.allocator; |
| 4576 | 4871 | |
| 4577 | 4872 | var locals = std.ArrayList(macho.nlist_64).init(gpa); |
| ... | ... | @@ -5485,7 +5780,7 @@ pub fn logSymtab(self: *MachO) void { |
| 5485 | 5780 | const def_index = if (sym.undf() and !sym.tentative()) |
| 5486 | 5781 | @divTrunc(sym.n_desc, macho.N_SYMBOL_RESOLVER) |
| 5487 | 5782 | else |
| 5488 | | sym.n_sect; |
| 5783 | sym.n_sect + 1; |
| 5489 | 5784 | log.debug(" %{d}: {s} @{x} in {s}({d}), {s}", .{ |
| 5490 | 5785 | sym_id, |
| 5491 | 5786 | object.getString(sym.n_strx), |
| ... | ... | @@ -5502,7 +5797,7 @@ pub fn logSymtab(self: *MachO) void { |
| 5502 | 5797 | const def_index = if (sym.undf() and !sym.tentative()) |
| 5503 | 5798 | @divTrunc(sym.n_desc, macho.N_SYMBOL_RESOLVER) |
| 5504 | 5799 | else |
| 5505 | | sym.n_sect; |
| 5800 | sym.n_sect + 1; |
| 5506 | 5801 | log.debug(" %{d}: {?s} @{x} in {s}({d}), {s}", .{ |
| 5507 | 5802 | sym_id, |
| 5508 | 5803 | self.strtab.get(sym.n_strx), |
| ... | ... | @@ -5633,6 +5928,6 @@ pub fn copyRangeAllOverlappingAlloc( |
| 5633 | 5928 | ) !void { |
| 5634 | 5929 | const buf = try allocator.alloc(u8, len); |
| 5635 | 5930 | defer allocator.free(buf); |
| 5636 | | _ = try file.preadAll(buf, in_offset); |
| 5637 | | try file.pwriteAll(buf, out_offset); |
| 5931 | const amt = try file.preadAll(buf, in_offset); |
| 5932 | try file.pwriteAll(buf[0..amt], out_offset); |
| 5638 | 5933 | } |