| ... | ... | @@ -15,7 +15,7 @@ const eh_frame = @import("eh_frame.zig"); |
| 15 | 15 | const fat = @import("fat.zig"); |
| 16 | 16 | const link = @import("../../link.zig"); |
| 17 | 17 | const load_commands = @import("load_commands.zig"); |
| 18 | | const stub_helpers = @import("stubs.zig"); |
| 18 | const stubs = @import("stubs.zig"); |
| 19 | 19 | const thunks = @import("thunks.zig"); |
| 20 | 20 | const trace = @import("../../tracy.zig").trace; |
| 21 | 21 | |
| ... | ... | @@ -67,8 +67,12 @@ pub const Zld = struct { |
| 67 | 67 | segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{}, |
| 68 | 68 | sections: std.MultiArrayList(Section) = .{}, |
| 69 | 69 | |
| 70 | text_section_index: ?u8 = null, |
| 70 | 71 | got_section_index: ?u8 = null, |
| 71 | 72 | tlv_ptr_section_index: ?u8 = null, |
| 73 | stubs_section_index: ?u8 = null, |
| 74 | stub_helper_section_index: ?u8 = null, |
| 75 | la_symbol_ptr_section_index: ?u8 = null, |
| 72 | 76 | |
| 73 | 77 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 74 | 78 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| ... | ... | @@ -78,17 +82,14 @@ pub const Zld = struct { |
| 78 | 82 | dso_handle_index: ?u32 = null, |
| 79 | 83 | dyld_stub_binder_index: ?u32 = null, |
| 80 | 84 | dyld_private_atom_index: ?Atom.Index = null, |
| 81 | | stub_helper_preamble_sym_index: ?u32 = null, |
| 82 | 85 | |
| 83 | 86 | strtab: StringTable(.strtab) = .{}, |
| 84 | 87 | |
| 85 | 88 | tlv_ptr_table: TableSection(SymbolWithLoc) = .{}, |
| 86 | 89 | got_table: TableSection(SymbolWithLoc) = .{}, |
| 90 | stubs_table: TableSection(SymbolWithLoc) = .{}, |
| 87 | 91 | |
| 88 | | stubs: std.ArrayListUnmanaged(IndirectPointer) = .{}, |
| 89 | | stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 90 | | |
| 91 | | thunk_table: std.AutoHashMapUnmanaged(AtomIndex, thunks.ThunkIndex) = .{}, |
| 92 | thunk_table: std.AutoHashMapUnmanaged(Atom.Index, thunks.Thunk.Index) = .{}, |
| 92 | 93 | thunks: std.ArrayListUnmanaged(thunks.Thunk) = .{}, |
| 93 | 94 | |
| 94 | 95 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| ... | ... | @@ -113,15 +114,18 @@ pub const Zld = struct { |
| 113 | 114 | } |
| 114 | 115 | |
| 115 | 116 | if (sect.isCode()) { |
| 116 | | break :blk self.getSectionByName("__TEXT", "__text") orelse try self.initSection( |
| 117 | | "__TEXT", |
| 118 | | "__text", |
| 119 | | .{ |
| 120 | | .flags = macho.S_REGULAR | |
| 121 | | macho.S_ATTR_PURE_INSTRUCTIONS | |
| 122 | | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 123 | | }, |
| 124 | | ); |
| 117 | if (self.text_section_index == null) { |
| 118 | self.text_section_index = try self.initSection( |
| 119 | "__TEXT", |
| 120 | "__text", |
| 121 | .{ |
| 122 | .flags = macho.S_REGULAR | |
| 123 | macho.S_ATTR_PURE_INSTRUCTIONS | |
| 124 | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 125 | }, |
| 126 | ); |
| 127 | } |
| 128 | break :blk self.text_section_index.?; |
| 125 | 129 | } |
| 126 | 130 | |
| 127 | 131 | if (sect.isDebug()) { |
| ... | ... | @@ -228,7 +232,7 @@ pub const Zld = struct { |
| 228 | 232 | return res; |
| 229 | 233 | } |
| 230 | 234 | |
| 231 | | pub fn addAtomToSection(self: *Zld, atom_index: AtomIndex) void { |
| 235 | pub fn addAtomToSection(self: *Zld, atom_index: Atom.Index) void { |
| 232 | 236 | const atom = self.getAtomPtr(atom_index); |
| 233 | 237 | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 234 | 238 | var section = self.sections.get(sym.n_sect - 1); |
| ... | ... | @@ -244,9 +248,9 @@ pub const Zld = struct { |
| 244 | 248 | self.sections.set(sym.n_sect - 1, section); |
| 245 | 249 | } |
| 246 | 250 | |
| 247 | | pub fn createEmptyAtom(self: *Zld, sym_index: u32, size: u64, alignment: u32) !AtomIndex { |
| 251 | pub fn createEmptyAtom(self: *Zld, sym_index: u32, size: u64, alignment: u32) !Atom.Index { |
| 248 | 252 | const gpa = self.gpa; |
| 249 | | const index = @as(AtomIndex, @intCast(self.atoms.items.len)); |
| 253 | const index = @as(Atom.Index, @intCast(self.atoms.items.len)); |
| 250 | 254 | const atom = try self.atoms.addOne(gpa); |
| 251 | 255 | atom.* = .{ |
| 252 | 256 | .sym_index = 0, |
| ... | ... | @@ -280,190 +284,6 @@ pub const Zld = struct { |
| 280 | 284 | self.addAtomToSection(atom_index); |
| 281 | 285 | } |
| 282 | 286 | |
| 283 | | fn createStubHelperPreambleAtom(self: *Zld) !void { |
| 284 | | if (self.dyld_stub_binder_index == null) return; |
| 285 | | |
| 286 | | const cpu_arch = self.options.target.cpu.arch; |
| 287 | | const size: u64 = switch (cpu_arch) { |
| 288 | | .x86_64 => 15, |
| 289 | | .aarch64 => 6 * @sizeOf(u32), |
| 290 | | else => unreachable, |
| 291 | | }; |
| 292 | | const alignment: u32 = switch (cpu_arch) { |
| 293 | | .x86_64 => 0, |
| 294 | | .aarch64 => 2, |
| 295 | | else => unreachable, |
| 296 | | }; |
| 297 | | const sym_index = try self.allocateSymbol(); |
| 298 | | const atom_index = try self.createEmptyAtom(sym_index, size, alignment); |
| 299 | | const sym = self.getSymbolPtr(.{ .sym_index = sym_index }); |
| 300 | | sym.n_type = macho.N_SECT; |
| 301 | | |
| 302 | | const sect_id = self.getSectionByName("__TEXT", "__stub_helper") orelse |
| 303 | | try self.initSection("__TEXT", "__stub_helper", .{ |
| 304 | | .flags = macho.S_REGULAR | |
| 305 | | macho.S_ATTR_PURE_INSTRUCTIONS | |
| 306 | | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 307 | | }); |
| 308 | | sym.n_sect = sect_id + 1; |
| 309 | | |
| 310 | | self.stub_helper_preamble_sym_index = sym_index; |
| 311 | | |
| 312 | | self.addAtomToSection(atom_index); |
| 313 | | } |
| 314 | | |
| 315 | | fn writeStubHelperPreambleCode(self: *Zld, writer: anytype) !void { |
| 316 | | const cpu_arch = self.options.target.cpu.arch; |
| 317 | | const source_addr = blk: { |
| 318 | | const sym = self.getSymbol(.{ .sym_index = self.stub_helper_preamble_sym_index.? }); |
| 319 | | break :blk sym.n_value; |
| 320 | | }; |
| 321 | | const dyld_private_addr = blk: { |
| 322 | | const atom = self.getAtom(self.dyld_private_atom_index.?); |
| 323 | | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 324 | | break :blk sym.n_value; |
| 325 | | }; |
| 326 | | const dyld_stub_binder_got_addr = blk: { |
| 327 | | const sym_loc = self.globals.items[self.dyld_stub_binder_index.?]; |
| 328 | | break :blk self.getGotEntryAddress(sym_loc).?; |
| 329 | | }; |
| 330 | | try stub_helpers.writeStubHelperPreambleCode(.{ |
| 331 | | .cpu_arch = cpu_arch, |
| 332 | | .source_addr = source_addr, |
| 333 | | .dyld_private_addr = dyld_private_addr, |
| 334 | | .dyld_stub_binder_got_addr = dyld_stub_binder_got_addr, |
| 335 | | }, writer); |
| 336 | | } |
| 337 | | |
| 338 | | pub fn createStubHelperAtom(self: *Zld) !AtomIndex { |
| 339 | | const cpu_arch = self.options.target.cpu.arch; |
| 340 | | const stub_size = stub_helpers.calcStubHelperEntrySize(cpu_arch); |
| 341 | | const alignment: u2 = switch (cpu_arch) { |
| 342 | | .x86_64 => 0, |
| 343 | | .aarch64 => 2, |
| 344 | | else => unreachable, |
| 345 | | }; |
| 346 | | |
| 347 | | const sym_index = try self.allocateSymbol(); |
| 348 | | const atom_index = try self.createEmptyAtom(sym_index, stub_size, alignment); |
| 349 | | const sym = self.getSymbolPtr(.{ .sym_index = sym_index }); |
| 350 | | sym.n_sect = macho.N_SECT; |
| 351 | | |
| 352 | | const sect_id = self.getSectionByName("__TEXT", "__stub_helper").?; |
| 353 | | sym.n_sect = sect_id + 1; |
| 354 | | |
| 355 | | self.addAtomToSection(atom_index); |
| 356 | | |
| 357 | | return atom_index; |
| 358 | | } |
| 359 | | |
| 360 | | fn writeStubHelperCode(self: *Zld, atom_index: AtomIndex, writer: anytype) !void { |
| 361 | | const cpu_arch = self.options.target.cpu.arch; |
| 362 | | const source_addr = blk: { |
| 363 | | const atom = self.getAtom(atom_index); |
| 364 | | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 365 | | break :blk sym.n_value; |
| 366 | | }; |
| 367 | | const target_addr = blk: { |
| 368 | | const sym = self.getSymbol(.{ .sym_index = self.stub_helper_preamble_sym_index.? }); |
| 369 | | break :blk sym.n_value; |
| 370 | | }; |
| 371 | | try stub_helpers.writeStubHelperCode(.{ |
| 372 | | .cpu_arch = cpu_arch, |
| 373 | | .source_addr = source_addr, |
| 374 | | .target_addr = target_addr, |
| 375 | | }, writer); |
| 376 | | } |
| 377 | | |
| 378 | | pub fn createLazyPointerAtom(self: *Zld) !AtomIndex { |
| 379 | | const sym_index = try self.allocateSymbol(); |
| 380 | | const atom_index = try self.createEmptyAtom(sym_index, @sizeOf(u64), 3); |
| 381 | | const sym = self.getSymbolPtr(.{ .sym_index = sym_index }); |
| 382 | | sym.n_type = macho.N_SECT; |
| 383 | | |
| 384 | | const sect_id = self.getSectionByName("__DATA", "__la_symbol_ptr") orelse |
| 385 | | try self.initSection("__DATA", "__la_symbol_ptr", .{ |
| 386 | | .flags = macho.S_LAZY_SYMBOL_POINTERS, |
| 387 | | }); |
| 388 | | sym.n_sect = sect_id + 1; |
| 389 | | |
| 390 | | self.addAtomToSection(atom_index); |
| 391 | | |
| 392 | | return atom_index; |
| 393 | | } |
| 394 | | |
| 395 | | fn writeLazyPointer(self: *Zld, stub_helper_index: u32, writer: anytype) !void { |
| 396 | | const target_addr = blk: { |
| 397 | | const sect_id = self.getSectionByName("__TEXT", "__stub_helper").?; |
| 398 | | var atom_index = self.sections.items(.first_atom_index)[sect_id].?; |
| 399 | | var count: u32 = 0; |
| 400 | | while (count < stub_helper_index + 1) : (count += 1) { |
| 401 | | const atom = self.getAtom(atom_index); |
| 402 | | if (atom.next_index) |next_index| { |
| 403 | | atom_index = next_index; |
| 404 | | } |
| 405 | | } |
| 406 | | const atom = self.getAtom(atom_index); |
| 407 | | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 408 | | break :blk sym.n_value; |
| 409 | | }; |
| 410 | | try writer.writeIntLittle(u64, target_addr); |
| 411 | | } |
| 412 | | |
| 413 | | pub fn createStubAtom(self: *Zld) !AtomIndex { |
| 414 | | const cpu_arch = self.options.target.cpu.arch; |
| 415 | | const alignment: u2 = switch (cpu_arch) { |
| 416 | | .x86_64 => 0, |
| 417 | | .aarch64 => 2, |
| 418 | | else => unreachable, // unhandled architecture type |
| 419 | | }; |
| 420 | | const stub_size = stub_helpers.calcStubEntrySize(cpu_arch); |
| 421 | | const sym_index = try self.allocateSymbol(); |
| 422 | | const atom_index = try self.createEmptyAtom(sym_index, stub_size, alignment); |
| 423 | | const sym = self.getSymbolPtr(.{ .sym_index = sym_index }); |
| 424 | | sym.n_type = macho.N_SECT; |
| 425 | | |
| 426 | | const sect_id = self.getSectionByName("__TEXT", "__stubs") orelse |
| 427 | | try self.initSection("__TEXT", "__stubs", .{ |
| 428 | | .flags = macho.S_SYMBOL_STUBS | |
| 429 | | macho.S_ATTR_PURE_INSTRUCTIONS | |
| 430 | | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 431 | | .reserved2 = stub_size, |
| 432 | | }); |
| 433 | | sym.n_sect = sect_id + 1; |
| 434 | | |
| 435 | | self.addAtomToSection(atom_index); |
| 436 | | |
| 437 | | return atom_index; |
| 438 | | } |
| 439 | | |
| 440 | | fn writeStubCode(self: *Zld, atom_index: AtomIndex, stub_index: u32, writer: anytype) !void { |
| 441 | | const cpu_arch = self.options.target.cpu.arch; |
| 442 | | const source_addr = blk: { |
| 443 | | const atom = self.getAtom(atom_index); |
| 444 | | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 445 | | break :blk sym.n_value; |
| 446 | | }; |
| 447 | | const target_addr = blk: { |
| 448 | | // TODO: cache this at stub atom creation; they always go in pairs anyhow |
| 449 | | const la_sect_id = self.getSectionByName("__DATA", "__la_symbol_ptr").?; |
| 450 | | var la_atom_index = self.sections.items(.first_atom_index)[la_sect_id].?; |
| 451 | | var count: u32 = 0; |
| 452 | | while (count < stub_index) : (count += 1) { |
| 453 | | const la_atom = self.getAtom(la_atom_index); |
| 454 | | la_atom_index = la_atom.next_index.?; |
| 455 | | } |
| 456 | | const atom = self.getAtom(la_atom_index); |
| 457 | | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 458 | | break :blk sym.n_value; |
| 459 | | }; |
| 460 | | try stub_helpers.writeStubCode(.{ |
| 461 | | .cpu_arch = cpu_arch, |
| 462 | | .source_addr = source_addr, |
| 463 | | .target_addr = target_addr, |
| 464 | | }, writer); |
| 465 | | } |
| 466 | | |
| 467 | 287 | fn createTentativeDefAtoms(self: *Zld) !void { |
| 468 | 288 | const gpa = self.gpa; |
| 469 | 289 | |
| ... | ... | @@ -818,7 +638,6 @@ pub const Zld = struct { |
| 818 | 638 | |
| 819 | 639 | self.tlv_ptr_table.deinit(gpa); |
| 820 | 640 | self.got_table.deinit(gpa); |
| 821 | | self.stubs.deinit(gpa); |
| 822 | 641 | self.stubs_table.deinit(gpa); |
| 823 | 642 | self.thunk_table.deinit(gpa); |
| 824 | 643 | |
| ... | ... | @@ -953,6 +772,27 @@ pub const Zld = struct { |
| 953 | 772 | } |
| 954 | 773 | } |
| 955 | 774 | |
| 775 | pub fn addStubEntry(self: *Zld, target: SymbolWithLoc) !void { |
| 776 | if (self.stubs_table.lookup.contains(target)) return; |
| 777 | _ = try self.stubs_table.allocateEntry(self.gpa, target); |
| 778 | if (self.stubs_section_index == null) { |
| 779 | self.stubs_section_index = try self.initSection("__TEXT", "__stubs", .{ |
| 780 | .flags = macho.S_SYMBOL_STUBS | |
| 781 | macho.S_ATTR_PURE_INSTRUCTIONS | |
| 782 | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 783 | .reserved2 = stubs.stubSize(self.options.target.cpu.arch), |
| 784 | }); |
| 785 | self.stub_helper_section_index = try self.initSection("__TEXT", "__stub_helper", .{ |
| 786 | .flags = macho.S_REGULAR | |
| 787 | macho.S_ATTR_PURE_INSTRUCTIONS | |
| 788 | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 789 | }); |
| 790 | self.la_symbol_ptr_section_index = try self.initSection("__DATA", "__la_symbol_ptr", .{ |
| 791 | .flags = macho.S_LAZY_SYMBOL_POINTERS, |
| 792 | }); |
| 793 | } |
| 794 | } |
| 795 | |
| 956 | 796 | fn allocateSpecialSymbols(self: *Zld) !void { |
| 957 | 797 | for (&[_]?u32{ |
| 958 | 798 | self.dso_handle_index, |
| ... | ... | @@ -984,88 +824,85 @@ pub const Zld = struct { |
| 984 | 824 | |
| 985 | 825 | var atom_index = first_atom_index orelse continue; |
| 986 | 826 | |
| 987 | | var buffer = std.ArrayList(u8).init(gpa); |
| 988 | | defer buffer.deinit(); |
| 989 | | try buffer.ensureTotalCapacity(math.cast(usize, header.size) orelse return error.Overflow); |
| 827 | var buffer = try gpa.alloc(u8, math.cast(usize, header.size) orelse return error.Overflow); |
| 828 | defer gpa.free(buffer); |
| 829 | @memset(buffer, 0); // TODO with NOPs |
| 990 | 830 | |
| 991 | 831 | log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() }); |
| 992 | 832 | |
| 993 | | var count: u32 = 0; |
| 994 | | while (true) : (count += 1) { |
| 833 | while (true) { |
| 995 | 834 | const atom = self.getAtom(atom_index); |
| 996 | | const this_sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 997 | | const padding_size: usize = if (atom.next_index) |next_index| blk: { |
| 998 | | const next_sym = self.getSymbol(self.getAtom(next_index).getSymbolWithLoc()); |
| 999 | | const size = next_sym.n_value - (this_sym.n_value + atom.size); |
| 1000 | | break :blk math.cast(usize, size) orelse return error.Overflow; |
| 1001 | | } else 0; |
| 1002 | | |
| 1003 | | log.debug(" (adding ATOM(%{d}, '{s}') from object({?}) to buffer)", .{ |
| 1004 | | atom.sym_index, |
| 1005 | | self.getSymbolName(atom.getSymbolWithLoc()), |
| 1006 | | atom.getFile(), |
| 1007 | | }); |
| 1008 | | if (padding_size > 0) { |
| 1009 | | log.debug(" (with padding {x})", .{padding_size}); |
| 1010 | | } |
| 1011 | | |
| 1012 | | const offset = buffer.items.len; |
| 1013 | | |
| 1014 | | // TODO: move writing synthetic sections into a separate function |
| 1015 | | if (atom_index == self.dyld_private_atom_index.?) { |
| 1016 | | buffer.appendSliceAssumeCapacity(&[_]u8{0} ** @sizeOf(u64)); |
| 1017 | | } else if (atom.getFile() == null) outer: { |
| 1018 | | switch (header.type()) { |
| 1019 | | macho.S_NON_LAZY_SYMBOL_POINTERS => unreachable, |
| 1020 | | macho.S_THREAD_LOCAL_VARIABLE_POINTERS => unreachable, |
| 1021 | | macho.S_LAZY_SYMBOL_POINTERS => { |
| 1022 | | try self.writeLazyPointer(count, buffer.writer()); |
| 1023 | | }, |
| 1024 | | else => { |
| 1025 | | if (self.stub_helper_preamble_sym_index) |sym_index| { |
| 1026 | | if (sym_index == atom.sym_index) { |
| 1027 | | try self.writeStubHelperPreambleCode(buffer.writer()); |
| 1028 | | break :outer; |
| 1029 | | } |
| 1030 | | } |
| 1031 | | if (header.type() == macho.S_SYMBOL_STUBS) { |
| 1032 | | try self.writeStubCode(atom_index, count, buffer.writer()); |
| 1033 | | } else if (mem.eql(u8, header.sectName(), "__stub_helper")) { |
| 1034 | | try self.writeStubHelperCode(atom_index, buffer.writer()); |
| 1035 | | } else if (header.isCode()) { |
| 1036 | | // A thunk |
| 1037 | | try thunks.writeThunkCode(self, atom_index, buffer.writer()); |
| 1038 | | } else unreachable; |
| 1039 | | }, |
| 835 | if (atom.getFile()) |file| { |
| 836 | const this_sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 837 | const padding_size: usize = if (atom.next_index) |next_index| blk: { |
| 838 | const next_sym = self.getSymbol(self.getAtom(next_index).getSymbolWithLoc()); |
| 839 | const size = next_sym.n_value - (this_sym.n_value + atom.size); |
| 840 | break :blk math.cast(usize, size) orelse return error.Overflow; |
| 841 | } else 0; |
| 842 | |
| 843 | log.debug(" (adding ATOM(%{d}, '{s}') from object({d}) to buffer)", .{ |
| 844 | atom.sym_index, |
| 845 | self.getSymbolName(atom.getSymbolWithLoc()), |
| 846 | file, |
| 847 | }); |
| 848 | if (padding_size > 0) { |
| 849 | log.debug(" (with padding {x})", .{padding_size}); |
| 1040 | 850 | } |
| 1041 | | } else { |
| 851 | |
| 852 | const offset = this_sym.n_value - header.addr; |
| 853 | log.debug(" (at offset 0x{x})", .{offset}); |
| 854 | |
| 1042 | 855 | const code = Atom.getAtomCode(self, atom_index); |
| 1043 | 856 | const relocs = Atom.getAtomRelocs(self, atom_index); |
| 1044 | 857 | const size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 1045 | | buffer.appendSliceAssumeCapacity(code); |
| 858 | @memcpy(buffer[offset .. offset + size], code); |
| 1046 | 859 | try Atom.resolveRelocs( |
| 1047 | 860 | self, |
| 1048 | 861 | atom_index, |
| 1049 | | buffer.items[offset..][0..size], |
| 862 | buffer[offset..][0..size], |
| 1050 | 863 | relocs, |
| 1051 | 864 | ); |
| 1052 | 865 | } |
| 1053 | 866 | |
| 1054 | | var i: usize = 0; |
| 1055 | | while (i < padding_size) : (i += 1) { |
| 1056 | | // TODO with NOPs |
| 1057 | | buffer.appendAssumeCapacity(0); |
| 1058 | | } |
| 1059 | | |
| 1060 | 867 | if (atom.next_index) |next_index| { |
| 1061 | 868 | atom_index = next_index; |
| 1062 | | } else { |
| 1063 | | assert(buffer.items.len == header.size); |
| 1064 | | log.debug(" (writing at file offset 0x{x})", .{header.offset}); |
| 1065 | | try self.file.pwriteAll(buffer.items, header.offset); |
| 1066 | | break; |
| 1067 | | } |
| 869 | } else break; |
| 1068 | 870 | } |
| 871 | |
| 872 | log.debug(" (writing at file offset 0x{x})", .{header.offset}); |
| 873 | try self.file.pwriteAll(buffer, header.offset); |
| 874 | } |
| 875 | } |
| 876 | |
| 877 | fn writeDyldPrivateAtom(self: *Zld) !void { |
| 878 | const atom_index = self.dyld_private_atom_index orelse return; |
| 879 | const atom = self.getAtom(atom_index); |
| 880 | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 881 | const sect_id = self.getSectionByName("__DATA", "__data").?; |
| 882 | const header = self.sections.items(.header)[sect_id]; |
| 883 | const offset = sym.n_value - header.addr + header.offset; |
| 884 | log.debug("writing __dyld_private at offset 0x{x}", .{offset}); |
| 885 | const buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); |
| 886 | try self.file.pwriteAll(&buffer, offset); |
| 887 | } |
| 888 | |
| 889 | fn writeThunks(self: *Zld) !void { |
| 890 | assert(self.requiresThunks()); |
| 891 | const gpa = self.gpa; |
| 892 | |
| 893 | const sect_id = self.text_section_index orelse return; |
| 894 | const header = self.sections.items(.header)[sect_id]; |
| 895 | |
| 896 | for (self.thunks.items, 0..) |*thunk, i| { |
| 897 | if (thunk.getSize() == 0) continue; |
| 898 | var buffer = try std.ArrayList(u8).initCapacity(gpa, thunk.getSize()); |
| 899 | defer buffer.deinit(); |
| 900 | try thunks.writeThunkCode(self, thunk, buffer.writer()); |
| 901 | const thunk_atom = self.getAtom(thunk.getStartAtomIndex()); |
| 902 | const thunk_sym = self.getSymbol(thunk_atom.getSymbolWithLoc()); |
| 903 | const offset = thunk_sym.n_value - header.addr + header.offset; |
| 904 | log.debug("writing thunk({d}) at offset 0x{x}", .{ i, offset }); |
| 905 | try self.file.pwriteAll(buffer.items, offset); |
| 1069 | 906 | } |
| 1070 | 907 | } |
| 1071 | 908 | |
| ... | ... | @@ -1077,10 +914,94 @@ pub const Zld = struct { |
| 1077 | 914 | const sym = self.getSymbol(entry); |
| 1078 | 915 | buffer.writer().writeIntLittle(u64, sym.n_value) catch unreachable; |
| 1079 | 916 | } |
| 1080 | | log.debug("writing .got contents at file offset 0x{x}", .{header.offset}); |
| 917 | log.debug("writing __DATA_CONST,__got contents at file offset 0x{x}", .{header.offset}); |
| 1081 | 918 | try self.file.pwriteAll(buffer.items, header.offset); |
| 1082 | 919 | } |
| 1083 | 920 | |
| 921 | fn writeStubs(self: *Zld) !void { |
| 922 | const gpa = self.gpa; |
| 923 | const cpu_arch = self.options.target.cpu.arch; |
| 924 | const stubs_header = self.sections.items(.header)[self.stubs_section_index.?]; |
| 925 | const la_symbol_ptr_header = self.sections.items(.header)[self.la_symbol_ptr_section_index.?]; |
| 926 | |
| 927 | var buffer = try std.ArrayList(u8).initCapacity(gpa, stubs_header.size); |
| 928 | defer buffer.deinit(); |
| 929 | |
| 930 | for (0..self.stubs_table.count()) |index| { |
| 931 | try stubs.writeStubCode(.{ |
| 932 | .cpu_arch = cpu_arch, |
| 933 | .source_addr = stubs_header.addr + stubs.stubSize(cpu_arch) * index, |
| 934 | .target_addr = la_symbol_ptr_header.addr + index * @sizeOf(u64), |
| 935 | }, buffer.writer()); |
| 936 | } |
| 937 | |
| 938 | log.debug("writing __TEXT,__stubs contents at file offset 0x{x}", .{stubs_header.offset}); |
| 939 | try self.file.pwriteAll(buffer.items, stubs_header.offset); |
| 940 | } |
| 941 | |
| 942 | fn writeStubHelpers(self: *Zld) !void { |
| 943 | const gpa = self.gpa; |
| 944 | const cpu_arch = self.options.target.cpu.arch; |
| 945 | const stub_helper_header = self.sections.items(.header)[self.stub_helper_section_index.?]; |
| 946 | |
| 947 | var buffer = try std.ArrayList(u8).initCapacity(gpa, stub_helper_header.size); |
| 948 | defer buffer.deinit(); |
| 949 | |
| 950 | { |
| 951 | const dyld_private_addr = blk: { |
| 952 | const atom = self.getAtom(self.dyld_private_atom_index.?); |
| 953 | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 954 | break :blk sym.n_value; |
| 955 | }; |
| 956 | const dyld_stub_binder_got_addr = blk: { |
| 957 | const sym_loc = self.globals.items[self.dyld_stub_binder_index.?]; |
| 958 | break :blk self.getGotEntryAddress(sym_loc).?; |
| 959 | }; |
| 960 | try stubs.writeStubHelperPreambleCode(.{ |
| 961 | .cpu_arch = cpu_arch, |
| 962 | .source_addr = stub_helper_header.addr, |
| 963 | .dyld_private_addr = dyld_private_addr, |
| 964 | .dyld_stub_binder_got_addr = dyld_stub_binder_got_addr, |
| 965 | }, buffer.writer()); |
| 966 | } |
| 967 | |
| 968 | for (0..self.stubs_table.count()) |index| { |
| 969 | const source_addr = stub_helper_header.addr + stubs.stubHelperPreambleSize(cpu_arch) + |
| 970 | stubs.stubHelperSize(cpu_arch) * index; |
| 971 | try stubs.writeStubHelperCode(.{ |
| 972 | .cpu_arch = cpu_arch, |
| 973 | .source_addr = source_addr, |
| 974 | .target_addr = stub_helper_header.addr, |
| 975 | }, buffer.writer()); |
| 976 | } |
| 977 | |
| 978 | log.debug("writing __TEXT,__stub_helper contents at file offset 0x{x}", .{ |
| 979 | stub_helper_header.offset, |
| 980 | }); |
| 981 | try self.file.pwriteAll(buffer.items, stub_helper_header.offset); |
| 982 | } |
| 983 | |
| 984 | fn writeLaSymbolPtrs(self: *Zld) !void { |
| 985 | const gpa = self.gpa; |
| 986 | const cpu_arch = self.options.target.cpu.arch; |
| 987 | const la_symbol_ptr_header = self.sections.items(.header)[self.la_symbol_ptr_section_index.?]; |
| 988 | const stub_helper_header = self.sections.items(.header)[self.stub_helper_section_index.?]; |
| 989 | |
| 990 | var buffer = try std.ArrayList(u8).initCapacity(gpa, la_symbol_ptr_header.size); |
| 991 | defer buffer.deinit(); |
| 992 | |
| 993 | for (0..self.stubs_table.count()) |index| { |
| 994 | const target_addr = stub_helper_header.addr + stubs.stubHelperPreambleSize(cpu_arch) + |
| 995 | stubs.stubHelperSize(cpu_arch) * index; |
| 996 | buffer.writer().writeIntLittle(u64, target_addr) catch unreachable; |
| 997 | } |
| 998 | |
| 999 | log.debug("writing __DATA,__la_symbol_ptr contents at file offset 0x{x}", .{ |
| 1000 | la_symbol_ptr_header.offset, |
| 1001 | }); |
| 1002 | try self.file.pwriteAll(buffer.items, la_symbol_ptr_header.offset); |
| 1003 | } |
| 1004 | |
| 1084 | 1005 | fn pruneAndSortSections(self: *Zld) !void { |
| 1085 | 1006 | const Entry = struct { |
| 1086 | 1007 | index: u8, |
| ... | ... | @@ -1105,6 +1026,18 @@ pub const Zld = struct { |
| 1105 | 1026 | section.header.sectName(), |
| 1106 | 1027 | section.first_atom_index, |
| 1107 | 1028 | }); |
| 1029 | for (&[_]*?u8{ |
| 1030 | &self.text_section_index, |
| 1031 | &self.got_section_index, |
| 1032 | &self.tlv_ptr_section_index, |
| 1033 | &self.stubs_section_index, |
| 1034 | &self.stub_helper_section_index, |
| 1035 | &self.la_symbol_ptr_section_index, |
| 1036 | }) |maybe_index| { |
| 1037 | if (maybe_index.* != null and maybe_index.*.? == index) { |
| 1038 | maybe_index.* = null; |
| 1039 | } |
| 1040 | } |
| 1108 | 1041 | continue; |
| 1109 | 1042 | } |
| 1110 | 1043 | entries.appendAssumeCapacity(.{ .index = @intCast(index) }); |
| ... | ... | @@ -1127,8 +1060,12 @@ pub const Zld = struct { |
| 1127 | 1060 | } |
| 1128 | 1061 | |
| 1129 | 1062 | for (&[_]*?u8{ |
| 1063 | &self.text_section_index, |
| 1130 | 1064 | &self.got_section_index, |
| 1131 | 1065 | &self.tlv_ptr_section_index, |
| 1066 | &self.stubs_section_index, |
| 1067 | &self.stub_helper_section_index, |
| 1068 | &self.la_symbol_ptr_section_index, |
| 1132 | 1069 | }) |maybe_index| { |
| 1133 | 1070 | if (maybe_index.*) |*index| { |
| 1134 | 1071 | index.* = backlinks[index.*]; |
| ... | ... | @@ -1140,8 +1077,8 @@ pub const Zld = struct { |
| 1140 | 1077 | const slice = self.sections.slice(); |
| 1141 | 1078 | for (slice.items(.header), 0..) |*header, sect_id| { |
| 1142 | 1079 | if (header.size == 0) continue; |
| 1143 | | if (self.requiresThunks()) { |
| 1144 | | if (header.isCode() and !(header.type() == macho.S_SYMBOL_STUBS) and !mem.eql(u8, header.sectName(), "__stub_helper")) continue; |
| 1080 | if (self.text_section_index) |txt| { |
| 1081 | if (txt == sect_id and self.requiresThunks()) continue; |
| 1145 | 1082 | } |
| 1146 | 1083 | |
| 1147 | 1084 | var atom_index = slice.items(.first_atom_index)[sect_id] orelse continue; |
| ... | ... | @@ -1167,15 +1104,9 @@ pub const Zld = struct { |
| 1167 | 1104 | } |
| 1168 | 1105 | } |
| 1169 | 1106 | |
| 1170 | | if (self.requiresThunks()) { |
| 1171 | | for (slice.items(.header), 0..) |header, sect_id| { |
| 1172 | | if (!header.isCode()) continue; |
| 1173 | | if (header.type() == macho.S_SYMBOL_STUBS) continue; |
| 1174 | | if (mem.eql(u8, header.sectName(), "__stub_helper")) continue; |
| 1175 | | |
| 1176 | | // Create jump/branch range extenders if needed. |
| 1177 | | try thunks.createThunks(self, @as(u8, @intCast(sect_id))); |
| 1178 | | } |
| 1107 | if (self.text_section_index != null and self.requiresThunks()) { |
| 1108 | // Create jump/branch range extenders if needed. |
| 1109 | try thunks.createThunks(self, self.text_section_index.?); |
| 1179 | 1110 | } |
| 1180 | 1111 | |
| 1181 | 1112 | // Update offsets of all symbols contained within each Atom. |
| ... | ... | @@ -1224,6 +1155,27 @@ pub const Zld = struct { |
| 1224 | 1155 | header.size = self.tlv_ptr_table.count() * @sizeOf(u64); |
| 1225 | 1156 | header.@"align" = 3; |
| 1226 | 1157 | } |
| 1158 | |
| 1159 | const cpu_arch = self.options.target.cpu.arch; |
| 1160 | |
| 1161 | if (self.stubs_section_index) |sect_id| { |
| 1162 | const header = &self.sections.items(.header)[sect_id]; |
| 1163 | header.size = self.stubs_table.count() * stubs.stubSize(cpu_arch); |
| 1164 | header.@"align" = stubs.stubAlignment(cpu_arch); |
| 1165 | } |
| 1166 | |
| 1167 | if (self.stub_helper_section_index) |sect_id| { |
| 1168 | const header = &self.sections.items(.header)[sect_id]; |
| 1169 | header.size = self.stubs_table.count() * stubs.stubHelperSize(cpu_arch) + |
| 1170 | stubs.stubHelperPreambleSize(cpu_arch); |
| 1171 | header.@"align" = stubs.stubAlignment(cpu_arch); |
| 1172 | } |
| 1173 | |
| 1174 | if (self.la_symbol_ptr_section_index) |sect_id| { |
| 1175 | const header = &self.sections.items(.header)[sect_id]; |
| 1176 | header.size = self.stubs_table.count() * @sizeOf(u64); |
| 1177 | header.@"align" = 3; |
| 1178 | } |
| 1227 | 1179 | } |
| 1228 | 1180 | |
| 1229 | 1181 | fn allocateSegments(self: *Zld) !void { |
| ... | ... | @@ -1453,36 +1405,13 @@ pub const Zld = struct { |
| 1453 | 1405 | try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.got_table); |
| 1454 | 1406 | } |
| 1455 | 1407 | |
| 1456 | | const slice = self.sections.slice(); |
| 1457 | | |
| 1458 | | // Next, unpact lazy pointers |
| 1459 | | // TODO: save la_ptr in a container so that we can re-use the helper |
| 1460 | | if (self.getSectionByName("__DATA", "__la_symbol_ptr")) |sect_id| { |
| 1461 | | const segment_index = slice.items(.segment_index)[sect_id]; |
| 1462 | | const seg = self.getSegment(sect_id); |
| 1463 | | var atom_index = slice.items(.first_atom_index)[sect_id].?; |
| 1464 | | |
| 1465 | | try rebase.entries.ensureUnusedCapacity(self.gpa, self.stubs.items.len); |
| 1466 | | |
| 1467 | | while (true) { |
| 1468 | | const atom = self.getAtom(atom_index); |
| 1469 | | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 1470 | | const base_offset = sym.n_value - seg.vmaddr; |
| 1471 | | |
| 1472 | | log.debug(" | rebase at {x}", .{base_offset}); |
| 1473 | | |
| 1474 | | rebase.entries.appendAssumeCapacity(.{ |
| 1475 | | .offset = base_offset, |
| 1476 | | .segment_id = segment_index, |
| 1477 | | }); |
| 1478 | | |
| 1479 | | if (atom.next_index) |next_index| { |
| 1480 | | atom_index = next_index; |
| 1481 | | } else break; |
| 1482 | | } |
| 1408 | // Next, unpack __la_symbol_ptr entries |
| 1409 | if (self.la_symbol_ptr_section_index) |sect_id| { |
| 1410 | try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.stubs_table); |
| 1483 | 1411 | } |
| 1484 | 1412 | |
| 1485 | 1413 | // Finally, unpack the rest. |
| 1414 | const slice = self.sections.slice(); |
| 1486 | 1415 | for (slice.items(.header), 0..) |header, sect_id| { |
| 1487 | 1416 | switch (header.type()) { |
| 1488 | 1417 | macho.S_LITERAL_POINTERS, |
| ... | ... | @@ -1679,51 +1608,8 @@ pub const Zld = struct { |
| 1679 | 1608 | } |
| 1680 | 1609 | |
| 1681 | 1610 | fn collectLazyBindData(self: *Zld, lazy_bind: *LazyBind) !void { |
| 1682 | | const sect_id = self.getSectionByName("__DATA", "__la_symbol_ptr") orelse return; |
| 1683 | | |
| 1684 | | log.debug("collecting lazy bind data", .{}); |
| 1685 | | |
| 1686 | | const slice = self.sections.slice(); |
| 1687 | | const segment_index = slice.items(.segment_index)[sect_id]; |
| 1688 | | const seg = self.getSegment(sect_id); |
| 1689 | | var atom_index = slice.items(.first_atom_index)[sect_id].?; |
| 1690 | | |
| 1691 | | // TODO: we actually don't need to store lazy pointer atoms as they are synthetically generated by the linker |
| 1692 | | try lazy_bind.entries.ensureUnusedCapacity(self.gpa, self.stubs.items.len); |
| 1693 | | |
| 1694 | | var count: u32 = 0; |
| 1695 | | while (true) : (count += 1) { |
| 1696 | | const atom = self.getAtom(atom_index); |
| 1697 | | |
| 1698 | | log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) }); |
| 1699 | | |
| 1700 | | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 1701 | | const base_offset = sym.n_value - seg.vmaddr; |
| 1702 | | |
| 1703 | | const stub_entry = self.stubs.items[count]; |
| 1704 | | const bind_sym = stub_entry.getTargetSymbol(self); |
| 1705 | | const bind_sym_name = stub_entry.getTargetSymbolName(self); |
| 1706 | | const dylib_ordinal = @divTrunc(@as(i16, @bitCast(bind_sym.n_desc)), macho.N_SYMBOL_RESOLVER); |
| 1707 | | log.debug(" | lazy bind at {x}, import('{s}') in dylib({d})", .{ |
| 1708 | | base_offset, |
| 1709 | | bind_sym_name, |
| 1710 | | dylib_ordinal, |
| 1711 | | }); |
| 1712 | | if (bind_sym.weakRef()) { |
| 1713 | | log.debug(" | marking as weak ref ", .{}); |
| 1714 | | } |
| 1715 | | lazy_bind.entries.appendAssumeCapacity(.{ |
| 1716 | | .target = stub_entry.target, |
| 1717 | | .offset = base_offset, |
| 1718 | | .segment_id = segment_index, |
| 1719 | | .addend = 0, |
| 1720 | | }); |
| 1721 | | |
| 1722 | | if (atom.next_index) |next_index| { |
| 1723 | | atom_index = next_index; |
| 1724 | | } else break; |
| 1725 | | } |
| 1726 | | |
| 1611 | const sect_id = self.la_symbol_ptr_section_index orelse return; |
| 1612 | try MachO.collectBindDataFromTableSection(self.gpa, self, sect_id, lazy_bind, self.stubs_table); |
| 1727 | 1613 | try lazy_bind.finalize(self.gpa, self); |
| 1728 | 1614 | } |
| 1729 | 1615 | |
| ... | ... | @@ -1828,7 +1714,12 @@ pub const Zld = struct { |
| 1828 | 1714 | }); |
| 1829 | 1715 | |
| 1830 | 1716 | try self.file.pwriteAll(buffer, rebase_off); |
| 1831 | | try self.populateLazyBindOffsetsInStubHelper(lazy_bind); |
| 1717 | try MachO.populateLazyBindOffsetsInStubHelper( |
| 1718 | self, |
| 1719 | self.options.target.cpu.arch, |
| 1720 | self.file, |
| 1721 | lazy_bind, |
| 1722 | ); |
| 1832 | 1723 | |
| 1833 | 1724 | self.dyld_info_cmd.rebase_off = @as(u32, @intCast(rebase_off)); |
| 1834 | 1725 | self.dyld_info_cmd.rebase_size = @as(u32, @intCast(rebase_size_aligned)); |
| ... | ... | @@ -1840,36 +1731,6 @@ pub const Zld = struct { |
| 1840 | 1731 | self.dyld_info_cmd.export_size = @as(u32, @intCast(export_size_aligned)); |
| 1841 | 1732 | } |
| 1842 | 1733 | |
| 1843 | | fn populateLazyBindOffsetsInStubHelper(self: *Zld, lazy_bind: LazyBind) !void { |
| 1844 | | if (lazy_bind.size() == 0) return; |
| 1845 | | |
| 1846 | | const stub_helper_section_index = self.getSectionByName("__TEXT", "__stub_helper").?; |
| 1847 | | assert(self.stub_helper_preamble_sym_index != null); |
| 1848 | | |
| 1849 | | const section = self.sections.get(stub_helper_section_index); |
| 1850 | | const stub_offset = stub_helpers.calcStubOffsetInStubHelper(self.options.target.cpu.arch); |
| 1851 | | const header = section.header; |
| 1852 | | var atom_index = section.first_atom_index.?; |
| 1853 | | atom_index = self.getAtom(atom_index).next_index.?; // skip preamble |
| 1854 | | |
| 1855 | | var index: usize = 0; |
| 1856 | | while (true) { |
| 1857 | | const atom = self.getAtom(atom_index); |
| 1858 | | const atom_sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 1859 | | const file_offset = header.offset + atom_sym.n_value - header.addr + stub_offset; |
| 1860 | | const bind_offset = lazy_bind.offsets.items[index]; |
| 1861 | | |
| 1862 | | log.debug("writing lazy bind offset 0x{x} in stub helper at 0x{x}", .{ bind_offset, file_offset }); |
| 1863 | | |
| 1864 | | try self.file.pwriteAll(mem.asBytes(&bind_offset), file_offset); |
| 1865 | | |
| 1866 | | if (atom.next_index) |next_index| { |
| 1867 | | atom_index = next_index; |
| 1868 | | index += 1; |
| 1869 | | } else break; |
| 1870 | | } |
| 1871 | | } |
| 1872 | | |
| 1873 | 1734 | const asc_u64 = std.sort.asc(u64); |
| 1874 | 1735 | |
| 1875 | 1736 | fn addSymbolToFunctionStarts(self: *Zld, sym_loc: SymbolWithLoc, addresses: *std.ArrayList(u64)) !void { |
| ... | ... | @@ -1973,7 +1834,7 @@ pub const Zld = struct { |
| 1973 | 1834 | var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.gpa); |
| 1974 | 1835 | defer out_dice.deinit(); |
| 1975 | 1836 | |
| 1976 | | const text_sect_id = self.getSectionByName("__TEXT", "__text") orelse return; |
| 1837 | const text_sect_id = self.text_section_index orelse return; |
| 1977 | 1838 | const text_sect_header = self.sections.items(.header)[text_sect_id]; |
| 1978 | 1839 | |
| 1979 | 1840 | for (self.objects.items) |object| { |
| ... | ... | @@ -2171,7 +2032,7 @@ pub const Zld = struct { |
| 2171 | 2032 | |
| 2172 | 2033 | fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void { |
| 2173 | 2034 | const gpa = self.gpa; |
| 2174 | | const nstubs = @as(u32, @intCast(self.stubs.items.len)); |
| 2035 | const nstubs = @as(u32, @intCast(self.stubs_table.lookup.count())); |
| 2175 | 2036 | const ngot_entries = @as(u32, @intCast(self.got_table.lookup.count())); |
| 2176 | 2037 | const nindirectsyms = nstubs * 2 + ngot_entries; |
| 2177 | 2038 | const iextdefsym = ctx.nlocalsym; |
| ... | ... | @@ -2191,19 +2052,20 @@ pub const Zld = struct { |
| 2191 | 2052 | try buf.ensureTotalCapacityPrecise(math.cast(usize, needed_size_aligned) orelse return error.Overflow); |
| 2192 | 2053 | const writer = buf.writer(); |
| 2193 | 2054 | |
| 2194 | | if (self.getSectionByName("__TEXT", "__stubs")) |sect_id| { |
| 2195 | | const stubs = &self.sections.items(.header)[sect_id]; |
| 2196 | | stubs.reserved1 = 0; |
| 2197 | | for (self.stubs.items) |entry| { |
| 2198 | | const target_sym = entry.getTargetSymbol(self); |
| 2055 | if (self.stubs_section_index) |sect_id| { |
| 2056 | const header = &self.sections.items(.header)[sect_id]; |
| 2057 | header.reserved1 = 0; |
| 2058 | for (self.stubs_table.entries.items) |entry| { |
| 2059 | if (!self.stubs_table.lookup.contains(entry)) continue; |
| 2060 | const target_sym = self.getSymbol(entry); |
| 2199 | 2061 | assert(target_sym.undf()); |
| 2200 | | try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?); |
| 2062 | try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?); |
| 2201 | 2063 | } |
| 2202 | 2064 | } |
| 2203 | 2065 | |
| 2204 | 2066 | if (self.got_section_index) |sect_id| { |
| 2205 | | const got = &self.sections.items(.header)[sect_id]; |
| 2206 | | got.reserved1 = nstubs; |
| 2067 | const header = &self.sections.items(.header)[sect_id]; |
| 2068 | header.reserved1 = nstubs; |
| 2207 | 2069 | for (self.got_table.entries.items) |entry| { |
| 2208 | 2070 | if (!self.got_table.lookup.contains(entry)) continue; |
| 2209 | 2071 | const target_sym = self.getSymbol(entry); |
| ... | ... | @@ -2215,13 +2077,14 @@ pub const Zld = struct { |
| 2215 | 2077 | } |
| 2216 | 2078 | } |
| 2217 | 2079 | |
| 2218 | | if (self.getSectionByName("__DATA", "__la_symbol_ptr")) |sect_id| { |
| 2219 | | const la_symbol_ptr = &self.sections.items(.header)[sect_id]; |
| 2220 | | la_symbol_ptr.reserved1 = nstubs + ngot_entries; |
| 2221 | | for (self.stubs.items) |entry| { |
| 2222 | | const target_sym = entry.getTargetSymbol(self); |
| 2080 | if (self.la_symbol_ptr_section_index) |sect_id| { |
| 2081 | const header = &self.sections.items(.header)[sect_id]; |
| 2082 | header.reserved1 = nstubs + ngot_entries; |
| 2083 | for (self.stubs_table.entries.items) |entry| { |
| 2084 | if (!self.stubs_table.lookup.contains(entry)) continue; |
| 2085 | const target_sym = self.getSymbol(entry); |
| 2223 | 2086 | assert(target_sym.undf()); |
| 2224 | | try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?); |
| 2087 | try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?); |
| 2225 | 2088 | } |
| 2226 | 2089 | } |
| 2227 | 2090 | |
| ... | ... | @@ -2343,12 +2206,12 @@ pub const Zld = struct { |
| 2343 | 2206 | return buf; |
| 2344 | 2207 | } |
| 2345 | 2208 | |
| 2346 | | pub fn getAtomPtr(self: *Zld, atom_index: AtomIndex) *Atom { |
| 2209 | pub fn getAtomPtr(self: *Zld, atom_index: Atom.Index) *Atom { |
| 2347 | 2210 | assert(atom_index < self.atoms.items.len); |
| 2348 | 2211 | return &self.atoms.items[atom_index]; |
| 2349 | 2212 | } |
| 2350 | 2213 | |
| 2351 | | pub fn getAtom(self: Zld, atom_index: AtomIndex) Atom { |
| 2214 | pub fn getAtom(self: Zld, atom_index: Atom.Index) Atom { |
| 2352 | 2215 | assert(atom_index < self.atoms.items.len); |
| 2353 | 2216 | return self.atoms.items[atom_index]; |
| 2354 | 2217 | } |
| ... | ... | @@ -2444,12 +2307,10 @@ pub const Zld = struct { |
| 2444 | 2307 | return header.addr + @sizeOf(u64) * index; |
| 2445 | 2308 | } |
| 2446 | 2309 | |
| 2447 | | /// Returns stubs atom that references `sym_with_loc` if one exists. |
| 2448 | | /// Returns null otherwise. |
| 2449 | | pub fn getStubsAtomIndexForSymbol(self: *Zld, sym_with_loc: SymbolWithLoc) ?AtomIndex { |
| 2450 | | const index = self.stubs_table.get(sym_with_loc) orelse return null; |
| 2451 | | const entry = self.stubs.items[index]; |
| 2452 | | return entry.atom_index; |
| 2310 | pub fn getStubsEntryAddress(self: *Zld, sym_with_loc: SymbolWithLoc) ?u64 { |
| 2311 | const index = self.stubs_table.lookup.get(sym_with_loc) orelse return null; |
| 2312 | const header = self.sections.items(.header)[self.stubs_section_index.?]; |
| 2313 | return header.addr + stubs.stubSize(self.options.target.cpu.arch) * index; |
| 2453 | 2314 | } |
| 2454 | 2315 | |
| 2455 | 2316 | /// Returns symbol location corresponding to the set entrypoint. |
| ... | ... | @@ -2581,7 +2442,7 @@ pub const Zld = struct { |
| 2581 | 2442 | |
| 2582 | 2443 | fn generateSymbolStabsForSymbol( |
| 2583 | 2444 | self: *Zld, |
| 2584 | | atom_index: AtomIndex, |
| 2445 | atom_index: Atom.Index, |
| 2585 | 2446 | sym_loc: SymbolWithLoc, |
| 2586 | 2447 | lookup: ?DwarfInfo.SubprogramLookupByName, |
| 2587 | 2448 | buf: *[4]macho.nlist_64, |
| ... | ... | @@ -2787,30 +2648,26 @@ pub const Zld = struct { |
| 2787 | 2648 | scoped_log.debug("{}", .{self.tlv_ptr_table}); |
| 2788 | 2649 | |
| 2789 | 2650 | scoped_log.debug("stubs entries:", .{}); |
| 2790 | | for (self.stubs.items, 0..) |entry, i| { |
| 2791 | | const atom_sym = entry.getAtomSymbol(self); |
| 2792 | | const target_sym = entry.getTargetSymbol(self); |
| 2793 | | const target_sym_name = entry.getTargetSymbolName(self); |
| 2794 | | assert(target_sym.undf()); |
| 2795 | | scoped_log.debug(" {d}@{x} => import('{s}')", .{ |
| 2796 | | i, |
| 2797 | | atom_sym.n_value, |
| 2798 | | target_sym_name, |
| 2799 | | }); |
| 2800 | | } |
| 2651 | scoped_log.debug("{}", .{self.stubs_table}); |
| 2801 | 2652 | |
| 2802 | 2653 | scoped_log.debug("thunks:", .{}); |
| 2803 | 2654 | for (self.thunks.items, 0..) |thunk, i| { |
| 2804 | 2655 | scoped_log.debug(" thunk({d})", .{i}); |
| 2805 | | for (thunk.lookup.keys(), 0..) |target, j| { |
| 2806 | | const target_sym = self.getSymbol(target); |
| 2807 | | const atom = self.getAtom(thunk.lookup.get(target).?); |
| 2656 | const slice = thunk.targets.slice(); |
| 2657 | for (slice.items(.tag), slice.items(.target), 0..) |tag, target, j| { |
| 2658 | const atom_index = @as(u32, @intCast(thunk.getStartAtomIndex() + j)); |
| 2659 | const atom = self.getAtom(atom_index); |
| 2808 | 2660 | const atom_sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 2809 | | scoped_log.debug(" {d}@{x} => thunk('{s}'@{x})", .{ |
| 2661 | const target_addr = switch (tag) { |
| 2662 | .stub => self.getStubsEntryAddress(target).?, |
| 2663 | .atom => self.getSymbol(target).n_value, |
| 2664 | }; |
| 2665 | scoped_log.debug(" {d}@{x} => {s}({s}@{x})", .{ |
| 2810 | 2666 | j, |
| 2811 | 2667 | atom_sym.n_value, |
| 2668 | @tagName(tag), |
| 2812 | 2669 | self.getSymbolName(target), |
| 2813 | | target_sym.n_value, |
| 2670 | target_addr, |
| 2814 | 2671 | }); |
| 2815 | 2672 | } |
| 2816 | 2673 | } |
| ... | ... | @@ -2836,7 +2693,7 @@ pub const Zld = struct { |
| 2836 | 2693 | } |
| 2837 | 2694 | } |
| 2838 | 2695 | |
| 2839 | | pub fn logAtom(self: *Zld, atom_index: AtomIndex, logger: anytype) void { |
| 2696 | pub fn logAtom(self: *Zld, atom_index: Atom.Index, logger: anytype) void { |
| 2840 | 2697 | if (!build_options.enable_logging) return; |
| 2841 | 2698 | |
| 2842 | 2699 | const atom = self.getAtom(atom_index); |
| ... | ... | @@ -2885,11 +2742,9 @@ pub const Zld = struct { |
| 2885 | 2742 | |
| 2886 | 2743 | pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1))); |
| 2887 | 2744 | |
| 2888 | | pub const AtomIndex = u32; |
| 2889 | | |
| 2890 | 2745 | const IndirectPointer = struct { |
| 2891 | 2746 | target: SymbolWithLoc, |
| 2892 | | atom_index: AtomIndex, |
| 2747 | atom_index: Atom.Index, |
| 2893 | 2748 | |
| 2894 | 2749 | pub fn getTargetSymbol(self: @This(), zld: *Zld) macho.nlist_64 { |
| 2895 | 2750 | return zld.getSymbol(self.target); |
| ... | ... | @@ -3321,7 +3176,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3321 | 3176 | |
| 3322 | 3177 | try zld.createDyldPrivateAtom(); |
| 3323 | 3178 | try zld.createTentativeDefAtoms(); |
| 3324 | | try zld.createStubHelperPreambleAtom(); |
| 3325 | 3179 | |
| 3326 | 3180 | if (zld.options.output_mode == .Exe) { |
| 3327 | 3181 | const global = zld.getEntryPoint(); |
| ... | ... | @@ -3329,7 +3183,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3329 | 3183 | // We do one additional check here in case the entry point was found in one of the dylibs. |
| 3330 | 3184 | // (I actually have no idea what this would imply but it is a possible outcome and so we |
| 3331 | 3185 | // support it.) |
| 3332 | | try Atom.addStub(&zld, global); |
| 3186 | try zld.addStubEntry(global); |
| 3333 | 3187 | } |
| 3334 | 3188 | } |
| 3335 | 3189 | |
| ... | ... | @@ -3373,7 +3227,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3373 | 3227 | } |
| 3374 | 3228 | |
| 3375 | 3229 | try zld.writeAtoms(); |
| 3230 | if (zld.requiresThunks()) try zld.writeThunks(); |
| 3231 | try zld.writeDyldPrivateAtom(); |
| 3376 | 3232 | |
| 3233 | if (zld.stubs_section_index) |_| { |
| 3234 | try zld.writeStubs(); |
| 3235 | try zld.writeStubHelpers(); |
| 3236 | try zld.writeLaSymbolPtrs(); |
| 3237 | } |
| 3377 | 3238 | if (zld.got_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.got_table); |
| 3378 | 3239 | if (zld.tlv_ptr_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.tlv_ptr_table); |
| 3379 | 3240 | |
| ... | ... | @@ -3444,14 +3305,12 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3444 | 3305 | const global = zld.getEntryPoint(); |
| 3445 | 3306 | const sym = zld.getSymbol(global); |
| 3446 | 3307 | |
| 3447 | | const addr: u64 = if (sym.undf()) blk: { |
| 3308 | const addr: u64 = if (sym.undf()) |
| 3448 | 3309 | // In this case, the symbol has been resolved in one of dylibs and so we point |
| 3449 | 3310 | // to the stub as its vmaddr value. |
| 3450 | | const stub_atom_index = zld.getStubsAtomIndexForSymbol(global).?; |
| 3451 | | const stub_atom = zld.getAtom(stub_atom_index); |
| 3452 | | const stub_sym = zld.getSymbol(stub_atom.getSymbolWithLoc()); |
| 3453 | | break :blk stub_sym.n_value; |
| 3454 | | } else sym.n_value; |
| 3311 | zld.getStubsEntryAddress(global).? |
| 3312 | else |
| 3313 | sym.n_value; |
| 3455 | 3314 | |
| 3456 | 3315 | try lc_writer.writeStruct(macho.entry_point_command{ |
| 3457 | 3316 | .entryoff = @as(u32, @intCast(addr - seg.vmaddr)), |