| ... | @@ -15,7 +15,7 @@ const eh_frame = @import("eh_frame.zig"); | ... | @@ -15,7 +15,7 @@ const eh_frame = @import("eh_frame.zig"); |
| 15 | const fat = @import("fat.zig"); | 15 | const fat = @import("fat.zig"); |
| 16 | const link = @import("../../link.zig"); | 16 | const link = @import("../../link.zig"); |
| 17 | const load_commands = @import("load_commands.zig"); | 17 | const load_commands = @import("load_commands.zig"); |
| 18 | const stub_helpers = @import("stubs.zig"); | 18 | const stubs = @import("stubs.zig"); |
| 19 | const thunks = @import("thunks.zig"); | 19 | const thunks = @import("thunks.zig"); |
| 20 | const trace = @import("../../tracy.zig").trace; | 20 | const trace = @import("../../tracy.zig").trace; |
| 21 | | 21 | |
| ... | @@ -67,8 +67,12 @@ pub const Zld = struct { | ... | @@ -67,8 +67,12 @@ pub const Zld = struct { |
| 67 | segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{}, | 67 | segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{}, |
| 68 | sections: std.MultiArrayList(Section) = .{}, | 68 | sections: std.MultiArrayList(Section) = .{}, |
| 69 | | 69 | |
| | 70 | text_section_index: ?u8 = null, |
| 70 | got_section_index: ?u8 = null, | 71 | got_section_index: ?u8 = null, |
| 71 | tlv_ptr_section_index: ?u8 = null, | 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 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 77 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 74 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, | 78 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| ... | @@ -78,17 +82,14 @@ pub const Zld = struct { | ... | @@ -78,17 +82,14 @@ pub const Zld = struct { |
| 78 | dso_handle_index: ?u32 = null, | 82 | dso_handle_index: ?u32 = null, |
| 79 | dyld_stub_binder_index: ?u32 = null, | 83 | dyld_stub_binder_index: ?u32 = null, |
| 80 | dyld_private_atom_index: ?Atom.Index = null, | 84 | dyld_private_atom_index: ?Atom.Index = null, |
| 81 | stub_helper_preamble_sym_index: ?u32 = null, | | |
| 82 | | 85 | |
| 83 | strtab: StringTable(.strtab) = .{}, | 86 | strtab: StringTable(.strtab) = .{}, |
| 84 | | 87 | |
| 85 | tlv_ptr_table: TableSection(SymbolWithLoc) = .{}, | 88 | tlv_ptr_table: TableSection(SymbolWithLoc) = .{}, |
| 86 | got_table: TableSection(SymbolWithLoc) = .{}, | 89 | got_table: TableSection(SymbolWithLoc) = .{}, |
| | 90 | stubs_table: TableSection(SymbolWithLoc) = .{}, |
| 87 | | 91 | |
| 88 | stubs: std.ArrayListUnmanaged(IndirectPointer) = .{}, | 92 | thunk_table: std.AutoHashMapUnmanaged(Atom.Index, thunks.Thunk.Index) = .{}, |
| 89 | stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, | | |
| 90 | | | |
| 91 | thunk_table: std.AutoHashMapUnmanaged(AtomIndex, thunks.ThunkIndex) = .{}, | | |
| 92 | thunks: std.ArrayListUnmanaged(thunks.Thunk) = .{}, | 93 | thunks: std.ArrayListUnmanaged(thunks.Thunk) = .{}, |
| 93 | | 94 | |
| 94 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | 95 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| ... | @@ -113,15 +114,18 @@ pub const Zld = struct { | ... | @@ -113,15 +114,18 @@ pub const Zld = struct { |
| 113 | } | 114 | } |
| 114 | | 115 | |
| 115 | if (sect.isCode()) { | 116 | if (sect.isCode()) { |
| 116 | break :blk self.getSectionByName("__TEXT", "__text") orelse try self.initSection( | 117 | if (self.text_section_index == null) { |
| 117 | "__TEXT", | 118 | self.text_section_index = try self.initSection( |
| 118 | "__text", | 119 | "__TEXT", |
| 119 | .{ | 120 | "__text", |
| 120 | .flags = macho.S_REGULAR | | 121 | .{ |
| 121 | macho.S_ATTR_PURE_INSTRUCTIONS | | 122 | .flags = macho.S_REGULAR | |
| 122 | macho.S_ATTR_SOME_INSTRUCTIONS, | 123 | macho.S_ATTR_PURE_INSTRUCTIONS | |
| 123 | }, | 124 | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 124 | ); | 125 | }, |
| | 126 | ); |
| | 127 | } |
| | 128 | break :blk self.text_section_index.?; |
| 125 | } | 129 | } |
| 126 | | 130 | |
| 127 | if (sect.isDebug()) { | 131 | if (sect.isDebug()) { |
| ... | @@ -228,7 +232,7 @@ pub const Zld = struct { | ... | @@ -228,7 +232,7 @@ pub const Zld = struct { |
| 228 | return res; | 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 | const atom = self.getAtomPtr(atom_index); | 236 | const atom = self.getAtomPtr(atom_index); |
| 233 | const sym = self.getSymbol(atom.getSymbolWithLoc()); | 237 | const sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 234 | var section = self.sections.get(sym.n_sect - 1); | 238 | var section = self.sections.get(sym.n_sect - 1); |
| ... | @@ -244,9 +248,9 @@ pub const Zld = struct { | ... | @@ -244,9 +248,9 @@ pub const Zld = struct { |
| 244 | self.sections.set(sym.n_sect - 1, section); | 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 | const gpa = self.gpa; | 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 | const atom = try self.atoms.addOne(gpa); | 254 | const atom = try self.atoms.addOne(gpa); |
| 251 | atom.* = .{ | 255 | atom.* = .{ |
| 252 | .sym_index = 0, | 256 | .sym_index = 0, |
| ... | @@ -280,190 +284,6 @@ pub const Zld = struct { | ... | @@ -280,190 +284,6 @@ pub const Zld = struct { |
| 280 | self.addAtomToSection(atom_index); | 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 | fn createTentativeDefAtoms(self: *Zld) !void { | 287 | fn createTentativeDefAtoms(self: *Zld) !void { |
| 468 | const gpa = self.gpa; | 288 | const gpa = self.gpa; |
| 469 | | 289 | |
| ... | @@ -818,7 +638,6 @@ pub const Zld = struct { | ... | @@ -818,7 +638,6 @@ pub const Zld = struct { |
| 818 | | 638 | |
| 819 | self.tlv_ptr_table.deinit(gpa); | 639 | self.tlv_ptr_table.deinit(gpa); |
| 820 | self.got_table.deinit(gpa); | 640 | self.got_table.deinit(gpa); |
| 821 | self.stubs.deinit(gpa); | | |
| 822 | self.stubs_table.deinit(gpa); | 641 | self.stubs_table.deinit(gpa); |
| 823 | self.thunk_table.deinit(gpa); | 642 | self.thunk_table.deinit(gpa); |
| 824 | | 643 | |
| ... | @@ -953,6 +772,27 @@ pub const Zld = struct { | ... | @@ -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 | fn allocateSpecialSymbols(self: *Zld) !void { | 796 | fn allocateSpecialSymbols(self: *Zld) !void { |
| 957 | for (&[_]?u32{ | 797 | for (&[_]?u32{ |
| 958 | self.dso_handle_index, | 798 | self.dso_handle_index, |
| ... | @@ -984,88 +824,85 @@ pub const Zld = struct { | ... | @@ -984,88 +824,85 @@ pub const Zld = struct { |
| 984 | | 824 | |
| 985 | var atom_index = first_atom_index orelse continue; | 825 | var atom_index = first_atom_index orelse continue; |
| 986 | | 826 | |
| 987 | var buffer = std.ArrayList(u8).init(gpa); | 827 | var buffer = try gpa.alloc(u8, math.cast(usize, header.size) orelse return error.Overflow); |
| 988 | defer buffer.deinit(); | 828 | defer gpa.free(buffer); |
| 989 | try buffer.ensureTotalCapacity(math.cast(usize, header.size) orelse return error.Overflow); | 829 | @memset(buffer, 0); // TODO with NOPs |
| 990 | | 830 | |
| 991 | log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() }); | 831 | log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() }); |
| 992 | | 832 | |
| 993 | var count: u32 = 0; | 833 | while (true) { |
| 994 | while (true) : (count += 1) { | | |
| 995 | const atom = self.getAtom(atom_index); | 834 | const atom = self.getAtom(atom_index); |
| 996 | const this_sym = self.getSymbol(atom.getSymbolWithLoc()); | 835 | if (atom.getFile()) |file| { |
| 997 | const padding_size: usize = if (atom.next_index) |next_index| blk: { | 836 | const this_sym = self.getSymbol(atom.getSymbolWithLoc()); |
| 998 | const next_sym = self.getSymbol(self.getAtom(next_index).getSymbolWithLoc()); | 837 | const padding_size: usize = if (atom.next_index) |next_index| blk: { |
| 999 | const size = next_sym.n_value - (this_sym.n_value + atom.size); | 838 | const next_sym = self.getSymbol(self.getAtom(next_index).getSymbolWithLoc()); |
| 1000 | break :blk math.cast(usize, size) orelse return error.Overflow; | 839 | const size = next_sym.n_value - (this_sym.n_value + atom.size); |
| 1001 | } else 0; | 840 | break :blk math.cast(usize, size) orelse return error.Overflow; |
| 1002 | | 841 | } else 0; |
| 1003 | log.debug(" (adding ATOM(%{d}, '{s}') from object({?}) to buffer)", .{ | 842 | |
| 1004 | atom.sym_index, | 843 | log.debug(" (adding ATOM(%{d}, '{s}') from object({d}) to buffer)", .{ |
| 1005 | self.getSymbolName(atom.getSymbolWithLoc()), | 844 | atom.sym_index, |
| 1006 | atom.getFile(), | 845 | self.getSymbolName(atom.getSymbolWithLoc()), |
| 1007 | }); | 846 | file, |
| 1008 | if (padding_size > 0) { | 847 | }); |
| 1009 | log.debug(" (with padding {x})", .{padding_size}); | 848 | if (padding_size > 0) { |
| 1010 | } | 849 | log.debug(" (with padding {x})", .{padding_size}); |
| 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 | }, | | |
| 1040 | } | 850 | } |
| 1041 | } else { | 851 | |
| | 852 | const offset = this_sym.n_value - header.addr; |
| | 853 | log.debug(" (at offset 0x{x})", .{offset}); |
| | 854 | |
| 1042 | const code = Atom.getAtomCode(self, atom_index); | 855 | const code = Atom.getAtomCode(self, atom_index); |
| 1043 | const relocs = Atom.getAtomRelocs(self, atom_index); | 856 | const relocs = Atom.getAtomRelocs(self, atom_index); |
| 1044 | const size = math.cast(usize, atom.size) orelse return error.Overflow; | 857 | const size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 1045 | buffer.appendSliceAssumeCapacity(code); | 858 | @memcpy(buffer[offset .. offset + size], code); |
| 1046 | try Atom.resolveRelocs( | 859 | try Atom.resolveRelocs( |
| 1047 | self, | 860 | self, |
| 1048 | atom_index, | 861 | atom_index, |
| 1049 | buffer.items[offset..][0..size], | 862 | buffer[offset..][0..size], |
| 1050 | relocs, | 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 | if (atom.next_index) |next_index| { | 867 | if (atom.next_index) |next_index| { |
| 1061 | atom_index = next_index; | 868 | atom_index = next_index; |
| 1062 | } else { | 869 | } else break; |
| 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 | } | | |
| 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,10 +914,94 @@ pub const Zld = struct { |
| 1077 | const sym = self.getSymbol(entry); | 914 | const sym = self.getSymbol(entry); |
| 1078 | buffer.writer().writeIntLittle(u64, sym.n_value) catch unreachable; | 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 | try self.file.pwriteAll(buffer.items, header.offset); | 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 | fn pruneAndSortSections(self: *Zld) !void { | 1005 | fn pruneAndSortSections(self: *Zld) !void { |
| 1085 | const Entry = struct { | 1006 | const Entry = struct { |
| 1086 | index: u8, | 1007 | index: u8, |
| ... | @@ -1105,6 +1026,18 @@ pub const Zld = struct { | ... | @@ -1105,6 +1026,18 @@ pub const Zld = struct { |
| 1105 | section.header.sectName(), | 1026 | section.header.sectName(), |
| 1106 | section.first_atom_index, | 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 | continue; | 1041 | continue; |
| 1109 | } | 1042 | } |
| 1110 | entries.appendAssumeCapacity(.{ .index = @intCast(index) }); | 1043 | entries.appendAssumeCapacity(.{ .index = @intCast(index) }); |
| ... | @@ -1127,8 +1060,12 @@ pub const Zld = struct { | ... | @@ -1127,8 +1060,12 @@ pub const Zld = struct { |
| 1127 | } | 1060 | } |
| 1128 | | 1061 | |
| 1129 | for (&[_]*?u8{ | 1062 | for (&[_]*?u8{ |
| | 1063 | &self.text_section_index, |
| 1130 | &self.got_section_index, | 1064 | &self.got_section_index, |
| 1131 | &self.tlv_ptr_section_index, | 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 | }) |maybe_index| { | 1069 | }) |maybe_index| { |
| 1133 | if (maybe_index.*) |*index| { | 1070 | if (maybe_index.*) |*index| { |
| 1134 | index.* = backlinks[index.*]; | 1071 | index.* = backlinks[index.*]; |
| ... | @@ -1140,8 +1077,8 @@ pub const Zld = struct { | ... | @@ -1140,8 +1077,8 @@ pub const Zld = struct { |
| 1140 | const slice = self.sections.slice(); | 1077 | const slice = self.sections.slice(); |
| 1141 | for (slice.items(.header), 0..) |*header, sect_id| { | 1078 | for (slice.items(.header), 0..) |*header, sect_id| { |
| 1142 | if (header.size == 0) continue; | 1079 | if (header.size == 0) continue; |
| 1143 | if (self.requiresThunks()) { | 1080 | if (self.text_section_index) |txt| { |
| 1144 | if (header.isCode() and !(header.type() == macho.S_SYMBOL_STUBS) and !mem.eql(u8, header.sectName(), "__stub_helper")) continue; | 1081 | if (txt == sect_id and self.requiresThunks()) continue; |
| 1145 | } | 1082 | } |
| 1146 | | 1083 | |
| 1147 | var atom_index = slice.items(.first_atom_index)[sect_id] orelse continue; | 1084 | var atom_index = slice.items(.first_atom_index)[sect_id] orelse continue; |
| ... | @@ -1167,15 +1104,9 @@ pub const Zld = struct { | ... | @@ -1167,15 +1104,9 @@ pub const Zld = struct { |
| 1167 | } | 1104 | } |
| 1168 | } | 1105 | } |
| 1169 | | 1106 | |
| 1170 | if (self.requiresThunks()) { | 1107 | if (self.text_section_index != null and self.requiresThunks()) { |
| 1171 | for (slice.items(.header), 0..) |header, sect_id| { | 1108 | // Create jump/branch range extenders if needed. |
| 1172 | if (!header.isCode()) continue; | 1109 | try thunks.createThunks(self, self.text_section_index.?); |
| 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 | } | | |
| 1179 | } | 1110 | } |
| 1180 | | 1111 | |
| 1181 | // Update offsets of all symbols contained within each Atom. | 1112 | // Update offsets of all symbols contained within each Atom. |
| ... | @@ -1224,6 +1155,27 @@ pub const Zld = struct { | ... | @@ -1224,6 +1155,27 @@ pub const Zld = struct { |
| 1224 | header.size = self.tlv_ptr_table.count() * @sizeOf(u64); | 1155 | header.size = self.tlv_ptr_table.count() * @sizeOf(u64); |
| 1225 | header.@"align" = 3; | 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 | fn allocateSegments(self: *Zld) !void { | 1181 | fn allocateSegments(self: *Zld) !void { |
| ... | @@ -1453,36 +1405,13 @@ pub const Zld = struct { | ... | @@ -1453,36 +1405,13 @@ pub const Zld = struct { |
| 1453 | try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.got_table); | 1405 | try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.got_table); |
| 1454 | } | 1406 | } |
| 1455 | | 1407 | |
| 1456 | const slice = self.sections.slice(); | 1408 | // Next, unpack __la_symbol_ptr entries |
| 1457 | | 1409 | if (self.la_symbol_ptr_section_index) |sect_id| { |
| 1458 | // Next, unpact lazy pointers | 1410 | try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.stubs_table); |
| 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 | } | | |
| 1483 | } | 1411 | } |
| 1484 | | 1412 | |
| 1485 | // Finally, unpack the rest. | 1413 | // Finally, unpack the rest. |
| | 1414 | const slice = self.sections.slice(); |
| 1486 | for (slice.items(.header), 0..) |header, sect_id| { | 1415 | for (slice.items(.header), 0..) |header, sect_id| { |
| 1487 | switch (header.type()) { | 1416 | switch (header.type()) { |
| 1488 | macho.S_LITERAL_POINTERS, | 1417 | macho.S_LITERAL_POINTERS, |
| ... | @@ -1679,51 +1608,8 @@ pub const Zld = struct { | ... | @@ -1679,51 +1608,8 @@ pub const Zld = struct { |
| 1679 | } | 1608 | } |
| 1680 | | 1609 | |
| 1681 | fn collectLazyBindData(self: *Zld, lazy_bind: *LazyBind) !void { | 1610 | fn collectLazyBindData(self: *Zld, lazy_bind: *LazyBind) !void { |
| 1682 | const sect_id = self.getSectionByName("__DATA", "__la_symbol_ptr") orelse return; | 1611 | const sect_id = self.la_symbol_ptr_section_index orelse return; |
| 1683 | | 1612 | try MachO.collectBindDataFromTableSection(self.gpa, self, sect_id, lazy_bind, self.stubs_table); |
| 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 | | | |
| 1727 | try lazy_bind.finalize(self.gpa, self); | 1613 | try lazy_bind.finalize(self.gpa, self); |
| 1728 | } | 1614 | } |
| 1729 | | 1615 | |
| ... | @@ -1828,7 +1714,12 @@ pub const Zld = struct { | ... | @@ -1828,7 +1714,12 @@ pub const Zld = struct { |
| 1828 | }); | 1714 | }); |
| 1829 | | 1715 | |
| 1830 | try self.file.pwriteAll(buffer, rebase_off); | 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 | self.dyld_info_cmd.rebase_off = @as(u32, @intCast(rebase_off)); | 1724 | self.dyld_info_cmd.rebase_off = @as(u32, @intCast(rebase_off)); |
| 1834 | self.dyld_info_cmd.rebase_size = @as(u32, @intCast(rebase_size_aligned)); | 1725 | self.dyld_info_cmd.rebase_size = @as(u32, @intCast(rebase_size_aligned)); |
| ... | @@ -1840,36 +1731,6 @@ pub const Zld = struct { | ... | @@ -1840,36 +1731,6 @@ pub const Zld = struct { |
| 1840 | self.dyld_info_cmd.export_size = @as(u32, @intCast(export_size_aligned)); | 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 | const asc_u64 = std.sort.asc(u64); | 1734 | const asc_u64 = std.sort.asc(u64); |
| 1874 | | 1735 | |
| 1875 | fn addSymbolToFunctionStarts(self: *Zld, sym_loc: SymbolWithLoc, addresses: *std.ArrayList(u64)) !void { | 1736 | fn addSymbolToFunctionStarts(self: *Zld, sym_loc: SymbolWithLoc, addresses: *std.ArrayList(u64)) !void { |
| ... | @@ -1973,7 +1834,7 @@ pub const Zld = struct { | ... | @@ -1973,7 +1834,7 @@ pub const Zld = struct { |
| 1973 | var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.gpa); | 1834 | var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.gpa); |
| 1974 | defer out_dice.deinit(); | 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 | const text_sect_header = self.sections.items(.header)[text_sect_id]; | 1838 | const text_sect_header = self.sections.items(.header)[text_sect_id]; |
| 1978 | | 1839 | |
| 1979 | for (self.objects.items) |object| { | 1840 | for (self.objects.items) |object| { |
| ... | @@ -2171,7 +2032,7 @@ pub const Zld = struct { | ... | @@ -2171,7 +2032,7 @@ pub const Zld = struct { |
| 2171 | | 2032 | |
| 2172 | fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void { | 2033 | fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void { |
| 2173 | const gpa = self.gpa; | 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 | const ngot_entries = @as(u32, @intCast(self.got_table.lookup.count())); | 2036 | const ngot_entries = @as(u32, @intCast(self.got_table.lookup.count())); |
| 2176 | const nindirectsyms = nstubs * 2 + ngot_entries; | 2037 | const nindirectsyms = nstubs * 2 + ngot_entries; |
| 2177 | const iextdefsym = ctx.nlocalsym; | 2038 | const iextdefsym = ctx.nlocalsym; |
| ... | @@ -2191,19 +2052,20 @@ pub const Zld = struct { | ... | @@ -2191,19 +2052,20 @@ pub const Zld = struct { |
| 2191 | try buf.ensureTotalCapacityPrecise(math.cast(usize, needed_size_aligned) orelse return error.Overflow); | 2052 | try buf.ensureTotalCapacityPrecise(math.cast(usize, needed_size_aligned) orelse return error.Overflow); |
| 2192 | const writer = buf.writer(); | 2053 | const writer = buf.writer(); |
| 2193 | | 2054 | |
| 2194 | if (self.getSectionByName("__TEXT", "__stubs")) |sect_id| { | 2055 | if (self.stubs_section_index) |sect_id| { |
| 2195 | const stubs = &self.sections.items(.header)[sect_id]; | 2056 | const header = &self.sections.items(.header)[sect_id]; |
| 2196 | stubs.reserved1 = 0; | 2057 | header.reserved1 = 0; |
| 2197 | for (self.stubs.items) |entry| { | 2058 | for (self.stubs_table.entries.items) |entry| { |
| 2198 | const target_sym = entry.getTargetSymbol(self); | 2059 | if (!self.stubs_table.lookup.contains(entry)) continue; |
| | 2060 | const target_sym = self.getSymbol(entry); |
| 2199 | assert(target_sym.undf()); | 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 | if (self.got_section_index) |sect_id| { | 2066 | if (self.got_section_index) |sect_id| { |
| 2205 | const got = &self.sections.items(.header)[sect_id]; | 2067 | const header = &self.sections.items(.header)[sect_id]; |
| 2206 | got.reserved1 = nstubs; | 2068 | header.reserved1 = nstubs; |
| 2207 | for (self.got_table.entries.items) |entry| { | 2069 | for (self.got_table.entries.items) |entry| { |
| 2208 | if (!self.got_table.lookup.contains(entry)) continue; | 2070 | if (!self.got_table.lookup.contains(entry)) continue; |
| 2209 | const target_sym = self.getSymbol(entry); | 2071 | const target_sym = self.getSymbol(entry); |
| ... | @@ -2215,13 +2077,14 @@ pub const Zld = struct { | ... | @@ -2215,13 +2077,14 @@ pub const Zld = struct { |
| 2215 | } | 2077 | } |
| 2216 | } | 2078 | } |
| 2217 | | 2079 | |
| 2218 | if (self.getSectionByName("__DATA", "__la_symbol_ptr")) |sect_id| { | 2080 | if (self.la_symbol_ptr_section_index) |sect_id| { |
| 2219 | const la_symbol_ptr = &self.sections.items(.header)[sect_id]; | 2081 | const header = &self.sections.items(.header)[sect_id]; |
| 2220 | la_symbol_ptr.reserved1 = nstubs + ngot_entries; | 2082 | header.reserved1 = nstubs + ngot_entries; |
| 2221 | for (self.stubs.items) |entry| { | 2083 | for (self.stubs_table.entries.items) |entry| { |
| 2222 | const target_sym = entry.getTargetSymbol(self); | 2084 | if (!self.stubs_table.lookup.contains(entry)) continue; |
| | 2085 | const target_sym = self.getSymbol(entry); |
| 2223 | assert(target_sym.undf()); | 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,12 +2206,12 @@ pub const Zld = struct { |
| 2343 | return buf; | 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 | assert(atom_index < self.atoms.items.len); | 2210 | assert(atom_index < self.atoms.items.len); |
| 2348 | return &self.atoms.items[atom_index]; | 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 | assert(atom_index < self.atoms.items.len); | 2215 | assert(atom_index < self.atoms.items.len); |
| 2353 | return self.atoms.items[atom_index]; | 2216 | return self.atoms.items[atom_index]; |
| 2354 | } | 2217 | } |
| ... | @@ -2444,12 +2307,10 @@ pub const Zld = struct { | ... | @@ -2444,12 +2307,10 @@ pub const Zld = struct { |
| 2444 | return header.addr + @sizeOf(u64) * index; | 2307 | return header.addr + @sizeOf(u64) * index; |
| 2445 | } | 2308 | } |
| 2446 | | 2309 | |
| 2447 | /// Returns stubs atom that references `sym_with_loc` if one exists. | 2310 | pub fn getStubsEntryAddress(self: *Zld, sym_with_loc: SymbolWithLoc) ?u64 { |
| 2448 | /// Returns null otherwise. | 2311 | const index = self.stubs_table.lookup.get(sym_with_loc) orelse return null; |
| 2449 | pub fn getStubsAtomIndexForSymbol(self: *Zld, sym_with_loc: SymbolWithLoc) ?AtomIndex { | 2312 | const header = self.sections.items(.header)[self.stubs_section_index.?]; |
| 2450 | const index = self.stubs_table.get(sym_with_loc) orelse return null; | 2313 | return header.addr + stubs.stubSize(self.options.target.cpu.arch) * index; |
| 2451 | const entry = self.stubs.items[index]; | | |
| 2452 | return entry.atom_index; | | |
| 2453 | } | 2314 | } |
| 2454 | | 2315 | |
| 2455 | /// Returns symbol location corresponding to the set entrypoint. | 2316 | /// Returns symbol location corresponding to the set entrypoint. |
| ... | @@ -2581,7 +2442,7 @@ pub const Zld = struct { | ... | @@ -2581,7 +2442,7 @@ pub const Zld = struct { |
| 2581 | | 2442 | |
| 2582 | fn generateSymbolStabsForSymbol( | 2443 | fn generateSymbolStabsForSymbol( |
| 2583 | self: *Zld, | 2444 | self: *Zld, |
| 2584 | atom_index: AtomIndex, | 2445 | atom_index: Atom.Index, |
| 2585 | sym_loc: SymbolWithLoc, | 2446 | sym_loc: SymbolWithLoc, |
| 2586 | lookup: ?DwarfInfo.SubprogramLookupByName, | 2447 | lookup: ?DwarfInfo.SubprogramLookupByName, |
| 2587 | buf: *[4]macho.nlist_64, | 2448 | buf: *[4]macho.nlist_64, |
| ... | @@ -2787,30 +2648,26 @@ pub const Zld = struct { | ... | @@ -2787,30 +2648,26 @@ pub const Zld = struct { |
| 2787 | scoped_log.debug("{}", .{self.tlv_ptr_table}); | 2648 | scoped_log.debug("{}", .{self.tlv_ptr_table}); |
| 2788 | | 2649 | |
| 2789 | scoped_log.debug("stubs entries:", .{}); | 2650 | scoped_log.debug("stubs entries:", .{}); |
| 2790 | for (self.stubs.items, 0..) |entry, i| { | 2651 | scoped_log.debug("{}", .{self.stubs_table}); |
| 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 | } | | |
| 2801 | | 2652 | |
| 2802 | scoped_log.debug("thunks:", .{}); | 2653 | scoped_log.debug("thunks:", .{}); |
| 2803 | for (self.thunks.items, 0..) |thunk, i| { | 2654 | for (self.thunks.items, 0..) |thunk, i| { |
| 2804 | scoped_log.debug(" thunk({d})", .{i}); | 2655 | scoped_log.debug(" thunk({d})", .{i}); |
| 2805 | for (thunk.lookup.keys(), 0..) |target, j| { | 2656 | const slice = thunk.targets.slice(); |
| 2806 | const target_sym = self.getSymbol(target); | 2657 | for (slice.items(.tag), slice.items(.target), 0..) |tag, target, j| { |
| 2807 | const atom = self.getAtom(thunk.lookup.get(target).?); | 2658 | const atom_index = @as(u32, @intCast(thunk.getStartAtomIndex() + j)); |
| | 2659 | const atom = self.getAtom(atom_index); |
| 2808 | const atom_sym = self.getSymbol(atom.getSymbolWithLoc()); | 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 | j, | 2666 | j, |
| 2811 | atom_sym.n_value, | 2667 | atom_sym.n_value, |
| | 2668 | @tagName(tag), |
| 2812 | self.getSymbolName(target), | 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,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 | if (!build_options.enable_logging) return; | 2697 | if (!build_options.enable_logging) return; |
| 2841 | | 2698 | |
| 2842 | const atom = self.getAtom(atom_index); | 2699 | const atom = self.getAtom(atom_index); |
| ... | @@ -2885,11 +2742,9 @@ pub const Zld = struct { | ... | @@ -2885,11 +2742,9 @@ pub const Zld = struct { |
| 2885 | | 2742 | |
| 2886 | pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1))); | 2743 | pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1))); |
| 2887 | | 2744 | |
| 2888 | pub const AtomIndex = u32; | | |
| 2889 | | | |
| 2890 | const IndirectPointer = struct { | 2745 | const IndirectPointer = struct { |
| 2891 | target: SymbolWithLoc, | 2746 | target: SymbolWithLoc, |
| 2892 | atom_index: AtomIndex, | 2747 | atom_index: Atom.Index, |
| 2893 | | 2748 | |
| 2894 | pub fn getTargetSymbol(self: @This(), zld: *Zld) macho.nlist_64 { | 2749 | pub fn getTargetSymbol(self: @This(), zld: *Zld) macho.nlist_64 { |
| 2895 | return zld.getSymbol(self.target); | 2750 | return zld.getSymbol(self.target); |
| ... | @@ -3321,7 +3176,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr | ... | @@ -3321,7 +3176,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3321 | | 3176 | |
| 3322 | try zld.createDyldPrivateAtom(); | 3177 | try zld.createDyldPrivateAtom(); |
| 3323 | try zld.createTentativeDefAtoms(); | 3178 | try zld.createTentativeDefAtoms(); |
| 3324 | try zld.createStubHelperPreambleAtom(); | | |
| 3325 | | 3179 | |
| 3326 | if (zld.options.output_mode == .Exe) { | 3180 | if (zld.options.output_mode == .Exe) { |
| 3327 | const global = zld.getEntryPoint(); | 3181 | const global = zld.getEntryPoint(); |
| ... | @@ -3329,7 +3183,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr | ... | @@ -3329,7 +3183,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3329 | // We do one additional check here in case the entry point was found in one of the dylibs. | 3183 | // We do one additional check here in case the entry point was found in one of the dylibs. |
| 3330 | // (I actually have no idea what this would imply but it is a possible outcome and so we | 3184 | // (I actually have no idea what this would imply but it is a possible outcome and so we |
| 3331 | // support it.) | 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,7 +3227,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3373 | } | 3227 | } |
| 3374 | | 3228 | |
| 3375 | try zld.writeAtoms(); | 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 | if (zld.got_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.got_table); | 3238 | if (zld.got_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.got_table); |
| 3378 | if (zld.tlv_ptr_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.tlv_ptr_table); | 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,14 +3305,12 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 3444 | const global = zld.getEntryPoint(); | 3305 | const global = zld.getEntryPoint(); |
| 3445 | const sym = zld.getSymbol(global); | 3306 | const sym = zld.getSymbol(global); |
| 3446 | | 3307 | |
| 3447 | const addr: u64 = if (sym.undf()) blk: { | 3308 | const addr: u64 = if (sym.undf()) |
| 3448 | // In this case, the symbol has been resolved in one of dylibs and so we point | 3309 | // In this case, the symbol has been resolved in one of dylibs and so we point |
| 3449 | // to the stub as its vmaddr value. | 3310 | // to the stub as its vmaddr value. |
| 3450 | const stub_atom_index = zld.getStubsAtomIndexForSymbol(global).?; | 3311 | zld.getStubsEntryAddress(global).? |
| 3451 | const stub_atom = zld.getAtom(stub_atom_index); | 3312 | else |
| 3452 | const stub_sym = zld.getSymbol(stub_atom.getSymbolWithLoc()); | 3313 | sym.n_value; |
| 3453 | break :blk stub_sym.n_value; | | |
| 3454 | } else sym.n_value; | | |
| 3455 | | 3314 | |
| 3456 | try lc_writer.writeStruct(macho.entry_point_command{ | 3315 | try lc_writer.writeStruct(macho.entry_point_command{ |
| 3457 | .entryoff = @as(u32, @intCast(addr - seg.vmaddr)), | 3316 | .entryoff = @as(u32, @intCast(addr - seg.vmaddr)), |