| author | |
| committer | |
| log | 16604a93b9159fafec3528457366ca146bf29ce5 |
| tree | c502d73aae538298e45f5703d43a7a96a73afe11 |
| parent | e4f5dada615c103bfe656c9fcd8f28df5f5ef9d1 |
| parent | f5a941b3d6238222f43da568c96cfa5b3e56ce5d |
| signature |
The tale of parallel MachO: part 128 files changed, 4696 insertions(+), 3356 deletions(-)
build.zig+1-1| ... | ... | @@ -620,7 +620,7 @@ fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.St |
| 620 | 620 | .root_source_file = b.path("src/main.zig"), |
| 621 | 621 | .target = options.target, |
| 622 | 622 | .optimize = options.optimize, |
| 623 | .max_rss = 7_000_000_000, | |
| 623 | .max_rss = 7_100_000_000, | |
| 624 | 624 | .strip = options.strip, |
| 625 | 625 | .sanitize_thread = options.sanitize_thread, |
| 626 | 626 | .single_threaded = options.single_threaded, |
src/Sema.zig+1-2| ... | ... | @@ -17787,8 +17787,7 @@ fn zirBuiltinSrc( |
| 17787 | 17787 | }; |
| 17788 | 17788 | |
| 17789 | 17789 | const file_name_val = v: { |
| 17790 | // The compiler must not call realpath anywhere. | |
| 17791 | const file_name = try fn_owner_decl.getFileScope(mod).fullPath(sema.arena); | |
| 17790 | const file_name = fn_owner_decl.getFileScope(mod).sub_file_path; | |
| 17792 | 17791 | const array_ty = try pt.intern(.{ .array_type = .{ |
| 17793 | 17792 | .len = file_name.len, |
| 17794 | 17793 | .sentinel = .zero_u8, |
src/arch/x86_64/CodeGen.zig+6-4| ... | ... | @@ -12362,8 +12362,9 @@ fn genCall(self: *Self, info: union(enum) { |
| 12362 | 12362 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }, .{}); |
| 12363 | 12363 | try self.asmRegister(.{ ._, .call }, .rax); |
| 12364 | 12364 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 12365 | const sym_index = try macho_file.getZigObject().?.getOrCreateMetadataForDecl(macho_file, func.owner_decl); | |
| 12366 | const sym = macho_file.getSymbol(sym_index); | |
| 12365 | const zo = macho_file.getZigObject().?; | |
| 12366 | const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, func.owner_decl); | |
| 12367 | const sym = zo.symbols.items[sym_index]; | |
| 12367 | 12368 | try self.genSetReg( |
| 12368 | 12369 | .rax, |
| 12369 | 12370 | Type.usize, |
| ... | ... | @@ -15396,9 +15397,10 @@ fn genLazySymbolRef( |
| 15396 | 15397 | else => unreachable, |
| 15397 | 15398 | } |
| 15398 | 15399 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 15399 | const sym_index = macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err| | |
| 15400 | const zo = macho_file.getZigObject().?; | |
| 15401 | const sym_index = zo.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err| | |
| 15400 | 15402 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 15401 | const sym = macho_file.getSymbol(sym_index); | |
| 15403 | const sym = zo.symbols.items[sym_index]; | |
| 15402 | 15404 | switch (tag) { |
| 15403 | 15405 | .lea, .call => try self.genSetReg( |
| 15404 | 15406 | reg, |
src/arch/x86_64/Emit.zig+8-8| ... | ... | @@ -51,12 +51,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 51 | 51 | }); |
| 52 | 52 | } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| { |
| 53 | 53 | // Add relocation to the decl. |
| 54 | const atom = macho_file.getSymbol(symbol.atom_index).getAtom(macho_file).?; | |
| 55 | const sym_index = macho_file.getZigObject().?.symbols.items[symbol.sym_index]; | |
| 54 | const zo = macho_file.getZigObject().?; | |
| 55 | const atom = zo.symbols.items[symbol.atom_index].getAtom(macho_file).?; | |
| 56 | 56 | try atom.addReloc(macho_file, .{ |
| 57 | 57 | .tag = .@"extern", |
| 58 | 58 | .offset = end_offset - 4, |
| 59 | .target = sym_index, | |
| 59 | .target = symbol.sym_index, | |
| 60 | 60 | .addend = 0, |
| 61 | 61 | .type = .branch, |
| 62 | 62 | .meta = .{ |
| ... | ... | @@ -160,11 +160,11 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 160 | 160 | .Obj => true, |
| 161 | 161 | .Lib => emit.lower.link_mode == .static, |
| 162 | 162 | }; |
| 163 | const atom = macho_file.getSymbol(data.atom_index).getAtom(macho_file).?; | |
| 164 | const sym_index = macho_file.getZigObject().?.symbols.items[data.sym_index]; | |
| 165 | const sym = macho_file.getSymbol(sym_index); | |
| 163 | const zo = macho_file.getZigObject().?; | |
| 164 | const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?; | |
| 165 | const sym = &zo.symbols.items[data.sym_index]; | |
| 166 | 166 | if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { |
| 167 | _ = try sym.getOrCreateZigGotEntry(sym_index, macho_file); | |
| 167 | _ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file); | |
| 168 | 168 | } |
| 169 | 169 | const @"type": link.File.MachO.Relocation.Type = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) |
| 170 | 170 | .zig_got_load |
| ... | ... | @@ -179,7 +179,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 179 | 179 | try atom.addReloc(macho_file, .{ |
| 180 | 180 | .tag = .@"extern", |
| 181 | 181 | .offset = @intCast(end_offset - 4), |
| 182 | .target = sym_index, | |
| 182 | .target = data.sym_index, | |
| 183 | 183 | .addend = 0, |
| 184 | 184 | .type = @"type", |
| 185 | 185 | .meta = .{ |
src/arch/x86_64/Lower.zig+2-2| ... | ... | @@ -425,8 +425,8 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 425 | 425 | else => unreachable, |
| 426 | 426 | }; |
| 427 | 427 | } else if (lower.bin_file.cast(link.File.MachO)) |macho_file| { |
| 428 | const sym_index = macho_file.getZigObject().?.symbols.items[sym.sym_index]; | |
| 429 | const macho_sym = macho_file.getSymbol(sym_index); | |
| 428 | const zo = macho_file.getZigObject().?; | |
| 429 | const macho_sym = zo.symbols.items[sym.sym_index]; | |
| 430 | 430 | |
| 431 | 431 | if (macho_sym.flags.tlv) { |
| 432 | 432 | _ = lower.reloc(.{ .linker_reloc = sym }); |
src/codegen.zig+5-4| ... | ... | @@ -901,15 +901,16 @@ fn genDeclRef( |
| 901 | 901 | } |
| 902 | 902 | return GenResult.mcv(.{ .load_symbol = sym.esym_index }); |
| 903 | 903 | } else if (lf.cast(link.File.MachO)) |macho_file| { |
| 904 | const zo = macho_file.getZigObject().?; | |
| 904 | 905 | if (is_extern) { |
| 905 | 906 | const name = decl.name.toSlice(ip); |
| 906 | 907 | const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null; |
| 907 | 908 | const sym_index = try macho_file.getGlobalSymbol(name, lib_name); |
| 908 | macho_file.getSymbol(macho_file.getZigObject().?.symbols.items[sym_index]).flags.needs_got = true; | |
| 909 | zo.symbols.items[sym_index].flags.needs_got = true; | |
| 909 | 910 | return GenResult.mcv(.{ .load_symbol = sym_index }); |
| 910 | 911 | } |
| 911 | const sym_index = try macho_file.getZigObject().?.getOrCreateMetadataForDecl(macho_file, decl_index); | |
| 912 | const sym = macho_file.getSymbol(sym_index); | |
| 912 | const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, decl_index); | |
| 913 | const sym = zo.symbols.items[sym_index]; | |
| 913 | 914 | if (is_threadlocal) { |
| 914 | 915 | return GenResult.mcv(.{ .load_tlv = sym.nlist_idx }); |
| 915 | 916 | } |
| ... | ... | @@ -956,7 +957,7 @@ fn genUnnamedConst( |
| 956 | 957 | }, |
| 957 | 958 | .macho => { |
| 958 | 959 | const macho_file = lf.cast(link.File.MachO).?; |
| 959 | const local = macho_file.getSymbol(local_sym_index); | |
| 960 | const local = macho_file.getZigObject().?.symbols.items[local_sym_index]; | |
| 960 | 961 | return GenResult.mcv(.{ .load_symbol = local.nlist_idx }); |
| 961 | 962 | }, |
| 962 | 963 | .coff => { |
src/link/MachO.zig+664-1001| ... | ... | @@ -22,16 +22,11 @@ dylibs: std.ArrayListUnmanaged(File.Index) = .{}, |
| 22 | 22 | segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{}, |
| 23 | 23 | sections: std.MultiArrayList(Section) = .{}, |
| 24 | 24 | |
| 25 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | |
| 26 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 27 | symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 28 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, | |
| 25 | resolver: SymbolResolver = .{}, | |
| 29 | 26 | /// This table will be populated after `scanRelocs` has run. |
| 30 | 27 | /// Key is symbol index. |
| 31 | undefs: std.AutoHashMapUnmanaged(Symbol.Index, std.ArrayListUnmanaged(Atom.Index)) = .{}, | |
| 32 | /// Global symbols we need to resolve for the link to succeed. | |
| 33 | undefined_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 34 | boundary_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 28 | undefs: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .{}, | |
| 29 | dupes: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .{}, | |
| 35 | 30 | |
| 36 | 31 | dyld_info_cmd: macho.dyld_info_command = .{}, |
| 37 | 32 | symtab_cmd: macho.symtab_command = .{}, |
| ... | ... | @@ -55,22 +50,7 @@ eh_frame_sect_index: ?u8 = null, |
| 55 | 50 | unwind_info_sect_index: ?u8 = null, |
| 56 | 51 | objc_stubs_sect_index: ?u8 = null, |
| 57 | 52 | |
| 58 | mh_execute_header_index: ?Symbol.Index = null, | |
| 59 | mh_dylib_header_index: ?Symbol.Index = null, | |
| 60 | dyld_private_index: ?Symbol.Index = null, | |
| 61 | dyld_stub_binder_index: ?Symbol.Index = null, | |
| 62 | dso_handle_index: ?Symbol.Index = null, | |
| 63 | objc_msg_send_index: ?Symbol.Index = null, | |
| 64 | entry_index: ?Symbol.Index = null, | |
| 65 | ||
| 66 | /// List of atoms that are either synthetic or map directly to the Zig source program. | |
| 67 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | |
| 68 | atoms_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 69 | 53 | thunks: std.ArrayListUnmanaged(Thunk) = .{}, |
| 70 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{}, | |
| 71 | ||
| 72 | /// String interning table | |
| 73 | strings: StringTable = .{}, | |
| 74 | 54 | |
| 75 | 55 | /// Output synthetic sections |
| 76 | 56 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | ... | @@ -83,12 +63,13 @@ stubs_helper: StubsHelperSection = .{}, |
| 83 | 63 | objc_stubs: ObjcStubsSection = .{}, |
| 84 | 64 | la_symbol_ptr: LaSymbolPtrSection = .{}, |
| 85 | 65 | tlv_ptr: TlvPtrSection = .{}, |
| 86 | rebase: RebaseSection = .{}, | |
| 87 | bind: BindSection = .{}, | |
| 88 | weak_bind: WeakBindSection = .{}, | |
| 89 | lazy_bind: LazyBindSection = .{}, | |
| 90 | export_trie: ExportTrieSection = .{}, | |
| 66 | rebase: Rebase = .{}, | |
| 67 | bind: Bind = .{}, | |
| 68 | weak_bind: WeakBind = .{}, | |
| 69 | lazy_bind: LazyBind = .{}, | |
| 70 | export_trie: ExportTrie = .{}, | |
| 91 | 71 | unwind_info: UnwindInfo = .{}, |
| 72 | data_in_code: DataInCode = .{}, | |
| 92 | 73 | |
| 93 | 74 | /// Tracked loadable segments during incremental linking. |
| 94 | 75 | zig_text_seg_index: ?u8 = null, |
| ... | ... | @@ -245,15 +226,8 @@ pub fn createEmpty( |
| 245 | 226 | |
| 246 | 227 | // Append null file |
| 247 | 228 | try self.files.append(gpa, .null); |
| 248 | // Atom at index 0 is reserved as null atom | |
| 249 | try self.atoms.append(gpa, .{}); | |
| 250 | try self.atoms_extra.append(gpa, 0); | |
| 251 | 229 | // Append empty string to string tables |
| 252 | try self.strings.buffer.append(gpa, 0); | |
| 253 | 230 | try self.strtab.append(gpa, 0); |
| 254 | // Append null symbols | |
| 255 | try self.symbols.append(gpa, .{}); | |
| 256 | try self.symbols_extra.append(gpa, 0); | |
| 257 | 231 | |
| 258 | 232 | if (opt_zcu) |zcu| { |
| 259 | 233 | if (!use_llvm) { |
| ... | ... | @@ -317,15 +291,20 @@ pub fn deinit(self: *MachO) void { |
| 317 | 291 | self.dylibs.deinit(gpa); |
| 318 | 292 | |
| 319 | 293 | self.segments.deinit(gpa); |
| 320 | for (self.sections.items(.atoms)) |*list| { | |
| 321 | list.deinit(gpa); | |
| 294 | for ( | |
| 295 | self.sections.items(.atoms), | |
| 296 | self.sections.items(.out), | |
| 297 | self.sections.items(.thunks), | |
| 298 | self.sections.items(.relocs), | |
| 299 | ) |*atoms, *out, *thnks, *relocs| { | |
| 300 | atoms.deinit(gpa); | |
| 301 | out.deinit(gpa); | |
| 302 | thnks.deinit(gpa); | |
| 303 | relocs.deinit(gpa); | |
| 322 | 304 | } |
| 323 | 305 | self.sections.deinit(gpa); |
| 324 | 306 | |
| 325 | self.symbols.deinit(gpa); | |
| 326 | self.symbols_extra.deinit(gpa); | |
| 327 | self.symbols_free_list.deinit(gpa); | |
| 328 | self.globals.deinit(gpa); | |
| 307 | self.resolver.deinit(gpa); | |
| 329 | 308 | { |
| 330 | 309 | var it = self.undefs.iterator(); |
| 331 | 310 | while (it.next()) |entry| { |
| ... | ... | @@ -333,10 +312,14 @@ pub fn deinit(self: *MachO) void { |
| 333 | 312 | } |
| 334 | 313 | self.undefs.deinit(gpa); |
| 335 | 314 | } |
| 336 | self.undefined_symbols.deinit(gpa); | |
| 337 | self.boundary_symbols.deinit(gpa); | |
| 315 | { | |
| 316 | var it = self.dupes.iterator(); | |
| 317 | while (it.next()) |entry| { | |
| 318 | entry.value_ptr.deinit(gpa); | |
| 319 | } | |
| 320 | self.dupes.deinit(gpa); | |
| 321 | } | |
| 338 | 322 | |
| 339 | self.strings.deinit(gpa); | |
| 340 | 323 | self.symtab.deinit(gpa); |
| 341 | 324 | self.strtab.deinit(gpa); |
| 342 | 325 | self.got.deinit(gpa); |
| ... | ... | @@ -350,14 +333,9 @@ pub fn deinit(self: *MachO) void { |
| 350 | 333 | self.lazy_bind.deinit(gpa); |
| 351 | 334 | self.export_trie.deinit(gpa); |
| 352 | 335 | self.unwind_info.deinit(gpa); |
| 336 | self.data_in_code.deinit(gpa); | |
| 353 | 337 | |
| 354 | self.atoms.deinit(gpa); | |
| 355 | self.atoms_extra.deinit(gpa); | |
| 356 | for (self.thunks.items) |*thunk| { | |
| 357 | thunk.deinit(gpa); | |
| 358 | } | |
| 359 | 338 | self.thunks.deinit(gpa); |
| 360 | self.unwind_records.deinit(gpa); | |
| 361 | 339 | } |
| 362 | 340 | |
| 363 | 341 | pub fn flush(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { |
| ... | ... | @@ -535,17 +513,14 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 535 | 513 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 536 | 514 | self.files.set(index, .{ .internal = .{ .index = index } }); |
| 537 | 515 | self.internal_object = index; |
| 516 | const object = self.getInternalObject().?; | |
| 517 | try object.init(gpa); | |
| 518 | try object.initSymbols(self); | |
| 538 | 519 | } |
| 539 | 520 | |
| 540 | try self.addUndefinedGlobals(); | |
| 541 | 521 | try self.resolveSymbols(); |
| 542 | try self.parseDebugInfo(); | |
| 543 | try self.resolveSyntheticSymbols(); | |
| 544 | ||
| 545 | try self.convertTentativeDefinitions(); | |
| 546 | try self.createObjcSections(); | |
| 522 | try self.convertTentativeDefsAndResolveSpecialSymbols(); | |
| 547 | 523 | try self.dedupLiterals(); |
| 548 | try self.claimUnresolved(); | |
| 549 | 524 | |
| 550 | 525 | if (self.base.gc_sections) { |
| 551 | 526 | try dead_strip.gcAtoms(self); |
| ... | ... | @@ -567,6 +542,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 567 | 542 | dylib.ordinal = @intCast(ord); |
| 568 | 543 | } |
| 569 | 544 | |
| 545 | self.claimUnresolved(); | |
| 546 | ||
| 570 | 547 | self.scanRelocs() catch |err| switch (err) { |
| 571 | 548 | error.HasUndefinedSymbols => return error.FlushFailure, |
| 572 | 549 | else => |e| { |
| ... | ... | @@ -580,92 +557,38 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 580 | 557 | try self.sortSections(); |
| 581 | 558 | try self.addAtomsToSections(); |
| 582 | 559 | try self.calcSectionSizes(); |
| 560 | ||
| 583 | 561 | try self.generateUnwindInfo(); |
| 584 | try self.initSegments(); | |
| 585 | 562 | |
| 563 | try self.initSegments(); | |
| 586 | 564 | try self.allocateSections(); |
| 587 | 565 | self.allocateSegments(); |
| 588 | 566 | self.allocateSyntheticSymbols(); |
| 589 | try self.allocateLinkeditSegment(); | |
| 590 | 567 | |
| 591 | 568 | if (build_options.enable_logging) { |
| 592 | 569 | state_log.debug("{}", .{self.dumpState()}); |
| 593 | 570 | } |
| 594 | 571 | |
| 595 | try self.initDyldInfoSections(); | |
| 596 | ||
| 597 | 572 | // Beyond this point, everything has been allocated a virtual address and we can resolve |
| 598 | 573 | // the relocations, and commit objects to file. |
| 599 | if (self.getZigObject()) |zo| { | |
| 600 | var has_resolve_error = false; | |
| 601 | ||
| 602 | for (zo.atoms.items) |atom_index| { | |
| 603 | const atom = self.getAtom(atom_index) orelse continue; | |
| 604 | if (!atom.flags.alive) continue; | |
| 605 | const sect = &self.sections.items(.header)[atom.out_n_sect]; | |
| 606 | if (sect.isZerofill()) continue; | |
| 607 | if (!self.isZigSection(atom.out_n_sect)) continue; // Non-Zig sections are handled separately | |
| 608 | if (atom.getRelocs(self).len == 0) continue; | |
| 609 | // TODO: we will resolve and write ZigObject's TLS data twice: | |
| 610 | // once here, and once in writeAtoms | |
| 611 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 612 | const code = try gpa.alloc(u8, atom_size); | |
| 613 | defer gpa.free(code); | |
| 614 | atom.getData(self, code) catch |err| switch (err) { | |
| 615 | error.InputOutput => { | |
| 616 | try self.reportUnexpectedError("fetching code for '{s}' failed", .{ | |
| 617 | atom.getName(self), | |
| 618 | }); | |
| 619 | return error.FlushFailure; | |
| 620 | }, | |
| 621 | else => |e| { | |
| 622 | try self.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{ | |
| 623 | atom.getName(self), | |
| 624 | @errorName(e), | |
| 625 | }); | |
| 626 | return error.FlushFailure; | |
| 627 | }, | |
| 628 | }; | |
| 629 | const file_offset = sect.offset + atom.value; | |
| 630 | atom.resolveRelocs(self, code) catch |err| switch (err) { | |
| 631 | error.ResolveFailed => has_resolve_error = true, | |
| 632 | else => |e| { | |
| 633 | try self.reportUnexpectedError("unexpected error while resolving relocations", .{}); | |
| 634 | return e; | |
| 635 | }, | |
| 636 | }; | |
| 637 | try self.base.file.?.pwriteAll(code, file_offset); | |
| 638 | } | |
| 574 | try self.resizeSections(); | |
| 639 | 575 | |
| 640 | if (has_resolve_error) return error.FlushFailure; | |
| 576 | if (self.getZigObject()) |zo| { | |
| 577 | zo.resolveRelocs(self) catch |err| switch (err) { | |
| 578 | error.ResolveFailed => return error.FlushFailure, | |
| 579 | else => |e| return e, | |
| 580 | }; | |
| 641 | 581 | } |
| 642 | ||
| 643 | self.writeAtoms() catch |err| switch (err) { | |
| 644 | error.ResolveFailed => return error.FlushFailure, | |
| 645 | else => |e| { | |
| 646 | try self.reportUnexpectedError("unexpected error while resolving relocations", .{}); | |
| 647 | return e; | |
| 648 | }, | |
| 582 | self.writeSectionsAndUpdateLinkeditSizes() catch |err| { | |
| 583 | switch (err) { | |
| 584 | error.ResolveFailed => return error.FlushFailure, | |
| 585 | else => |e| return e, | |
| 586 | } | |
| 649 | 587 | }; |
| 650 | try self.writeUnwindInfo(); | |
| 651 | try self.finalizeDyldInfoSections(); | |
| 652 | try self.writeSyntheticSections(); | |
| 653 | ||
| 654 | var off = math.cast(u32, self.getLinkeditSegment().fileoff) orelse return error.Overflow; | |
| 655 | off = try self.writeDyldInfoSections(off); | |
| 656 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 657 | off = try self.writeFunctionStarts(off); | |
| 658 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 659 | off = try self.writeDataInCode(self.getTextSegment().vmaddr, off); | |
| 660 | try self.calcSymtabSize(); | |
| 661 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 662 | off = try self.writeSymtab(off); | |
| 663 | off = mem.alignForward(u32, off, @alignOf(u32)); | |
| 664 | off = try self.writeIndsymtab(off); | |
| 665 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 666 | off = try self.writeStrtab(off); | |
| 667 | 588 | |
| 668 | self.getLinkeditSegment().filesize = off - self.getLinkeditSegment().fileoff; | |
| 589 | try self.writeSectionsToFile(); | |
| 590 | try self.allocateLinkeditSegment(); | |
| 591 | try self.writeLinkeditSectionsToFile(); | |
| 669 | 592 | |
| 670 | 593 | var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: { |
| 671 | 594 | // Preallocate space for the code signature. |
| ... | ... | @@ -982,12 +905,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void { |
| 982 | 905 | break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); |
| 983 | 906 | }; |
| 984 | 907 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 985 | self.files.set(index, .{ .object = .{ | |
| 986 | .path = try gpa.dupe(u8, path), | |
| 987 | .file_handle = handle, | |
| 988 | .mtime = mtime, | |
| 989 | .index = index, | |
| 990 | } }); | |
| 908 | self.files.set(index, .{ | |
| 909 | .object = .{ | |
| 910 | .offset = 0, // TODO FAT objects | |
| 911 | .path = try gpa.dupe(u8, path), | |
| 912 | .file_handle = handle, | |
| 913 | .mtime = mtime, | |
| 914 | .index = index, | |
| 915 | }, | |
| 916 | }); | |
| 991 | 917 | try self.objects.append(gpa, index); |
| 992 | 918 | |
| 993 | 919 | const object = self.getFile(index).?.object; |
| ... | ... | @@ -1327,35 +1253,6 @@ fn parseDependentDylibs(self: *MachO) !void { |
| 1327 | 1253 | if (has_errors) return error.MissingLibraryDependencies; |
| 1328 | 1254 | } |
| 1329 | 1255 | |
| 1330 | pub fn addUndefinedGlobals(self: *MachO) !void { | |
| 1331 | const gpa = self.base.comp.gpa; | |
| 1332 | ||
| 1333 | try self.undefined_symbols.ensureUnusedCapacity(gpa, self.base.comp.force_undefined_symbols.keys().len); | |
| 1334 | for (self.base.comp.force_undefined_symbols.keys()) |name| { | |
| 1335 | const off = try self.strings.insert(gpa, name); | |
| 1336 | const gop = try self.getOrCreateGlobal(off); | |
| 1337 | self.undefined_symbols.appendAssumeCapacity(gop.index); | |
| 1338 | } | |
| 1339 | ||
| 1340 | if (!self.base.isDynLib() and self.entry_name != null) { | |
| 1341 | const off = try self.strings.insert(gpa, self.entry_name.?); | |
| 1342 | const gop = try self.getOrCreateGlobal(off); | |
| 1343 | self.entry_index = gop.index; | |
| 1344 | } | |
| 1345 | ||
| 1346 | { | |
| 1347 | const off = try self.strings.insert(gpa, "dyld_stub_binder"); | |
| 1348 | const gop = try self.getOrCreateGlobal(off); | |
| 1349 | self.dyld_stub_binder_index = gop.index; | |
| 1350 | } | |
| 1351 | ||
| 1352 | { | |
| 1353 | const off = try self.strings.insert(gpa, "_objc_msgSend"); | |
| 1354 | const gop = try self.getOrCreateGlobal(off); | |
| 1355 | self.objc_msg_send_index = gop.index; | |
| 1356 | } | |
| 1357 | } | |
| 1358 | ||
| 1359 | 1256 | /// When resolving symbols, we approach the problem similarly to `mold`. |
| 1360 | 1257 | /// 1. Resolve symbols across all objects (including those preemptively extracted archives). |
| 1361 | 1258 | /// 2. Resolve symbols across all shared objects. |
| ... | ... | @@ -1368,18 +1265,17 @@ pub fn resolveSymbols(self: *MachO) !void { |
| 1368 | 1265 | defer tracy.end(); |
| 1369 | 1266 | |
| 1370 | 1267 | // Resolve symbols in the ZigObject. For now, we assume that it's always live. |
| 1371 | if (self.getZigObject()) |zo| zo.asFile().resolveSymbols(self); | |
| 1268 | if (self.getZigObject()) |zo| try zo.asFile().resolveSymbols(self); | |
| 1372 | 1269 | // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). |
| 1373 | for (self.objects.items) |index| self.getFile(index).?.resolveSymbols(self); | |
| 1374 | for (self.dylibs.items) |index| self.getFile(index).?.resolveSymbols(self); | |
| 1270 | for (self.objects.items) |index| try self.getFile(index).?.resolveSymbols(self); | |
| 1271 | for (self.dylibs.items) |index| try self.getFile(index).?.resolveSymbols(self); | |
| 1272 | if (self.getInternalObject()) |obj| try obj.resolveSymbols(self); | |
| 1375 | 1273 | |
| 1376 | 1274 | // Mark live objects. |
| 1377 | 1275 | self.markLive(); |
| 1378 | 1276 | |
| 1379 | 1277 | // Reset state of all globals after marking live objects. |
| 1380 | if (self.getZigObject()) |zo| zo.asFile().resetGlobals(self); | |
| 1381 | for (self.objects.items) |index| self.getFile(index).?.resetGlobals(self); | |
| 1382 | for (self.dylibs.items) |index| self.getFile(index).?.resetGlobals(self); | |
| 1278 | self.resolver.reset(); | |
| 1383 | 1279 | |
| 1384 | 1280 | // Prune dead objects. |
| 1385 | 1281 | var i: usize = 0; |
| ... | ... | @@ -1393,37 +1289,26 @@ pub fn resolveSymbols(self: *MachO) !void { |
| 1393 | 1289 | } |
| 1394 | 1290 | |
| 1395 | 1291 | // Re-resolve the symbols. |
| 1396 | if (self.getZigObject()) |zo| zo.resolveSymbols(self); | |
| 1397 | for (self.objects.items) |index| self.getFile(index).?.resolveSymbols(self); | |
| 1398 | for (self.dylibs.items) |index| self.getFile(index).?.resolveSymbols(self); | |
| 1292 | if (self.getZigObject()) |zo| try zo.resolveSymbols(self); | |
| 1293 | for (self.objects.items) |index| try self.getFile(index).?.resolveSymbols(self); | |
| 1294 | for (self.dylibs.items) |index| try self.getFile(index).?.resolveSymbols(self); | |
| 1295 | if (self.getInternalObject()) |obj| try obj.resolveSymbols(self); | |
| 1296 | ||
| 1297 | // Merge symbol visibility | |
| 1298 | if (self.getZigObject()) |zo| zo.mergeSymbolVisibility(self); | |
| 1299 | for (self.objects.items) |index| self.getFile(index).?.object.mergeSymbolVisibility(self); | |
| 1399 | 1300 | } |
| 1400 | 1301 | |
| 1401 | 1302 | fn markLive(self: *MachO) void { |
| 1402 | 1303 | const tracy = trace(@src()); |
| 1403 | 1304 | defer tracy.end(); |
| 1404 | 1305 | |
| 1405 | for (self.undefined_symbols.items) |index| { | |
| 1406 | if (self.getSymbol(index).getFile(self)) |file| { | |
| 1407 | if (file == .object) file.object.alive = true; | |
| 1408 | } | |
| 1409 | } | |
| 1410 | if (self.entry_index) |index| { | |
| 1411 | const sym = self.getSymbol(index); | |
| 1412 | if (sym.getFile(self)) |file| { | |
| 1413 | if (file == .object) file.object.alive = true; | |
| 1414 | } | |
| 1415 | } | |
| 1416 | 1306 | if (self.getZigObject()) |zo| zo.markLive(self); |
| 1417 | 1307 | for (self.objects.items) |index| { |
| 1418 | 1308 | const object = self.getFile(index).?.object; |
| 1419 | 1309 | if (object.alive) object.markLive(self); |
| 1420 | 1310 | } |
| 1421 | } | |
| 1422 | ||
| 1423 | pub fn parseDebugInfo(self: *MachO) !void { | |
| 1424 | for (self.objects.items) |index| { | |
| 1425 | try self.getFile(index).?.object.parseDebugInfo(self); | |
| 1426 | } | |
| 1311 | if (self.getInternalObject()) |obj| obj.markLive(self); | |
| 1427 | 1312 | } |
| 1428 | 1313 | |
| 1429 | 1314 | fn resolveSyntheticSymbols(self: *MachO) !void { |
| ... | ... | @@ -1473,10 +1358,14 @@ fn resolveSyntheticSymbols(self: *MachO) !void { |
| 1473 | 1358 | } |
| 1474 | 1359 | } |
| 1475 | 1360 | |
| 1476 | fn convertTentativeDefinitions(self: *MachO) !void { | |
| 1361 | fn convertTentativeDefsAndResolveSpecialSymbols(self: *MachO) !void { | |
| 1477 | 1362 | for (self.objects.items) |index| { |
| 1478 | 1363 | try self.getFile(index).?.object.convertTentativeDefinitions(self); |
| 1479 | 1364 | } |
| 1365 | if (self.getInternalObject()) |obj| { | |
| 1366 | try obj.resolveBoundarySymbols(self); | |
| 1367 | try obj.resolveObjcMsgSendSymbols(self); | |
| 1368 | } | |
| 1480 | 1369 | } |
| 1481 | 1370 | |
| 1482 | 1371 | fn createObjcSections(self: *MachO) !void { |
| ... | ... | @@ -1514,6 +1403,9 @@ fn createObjcSections(self: *MachO) !void { |
| 1514 | 1403 | } |
| 1515 | 1404 | |
| 1516 | 1405 | pub fn dedupLiterals(self: *MachO) !void { |
| 1406 | const tracy = trace(@src()); | |
| 1407 | defer tracy.end(); | |
| 1408 | ||
| 1517 | 1409 | const gpa = self.base.comp.gpa; |
| 1518 | 1410 | var lp: LiteralPool = .{}; |
| 1519 | 1411 | defer lp.deinit(gpa); |
| ... | ... | @@ -1539,80 +1431,46 @@ pub fn dedupLiterals(self: *MachO) !void { |
| 1539 | 1431 | } |
| 1540 | 1432 | } |
| 1541 | 1433 | |
| 1542 | fn claimUnresolved(self: *MachO) error{OutOfMemory}!void { | |
| 1434 | fn claimUnresolved(self: *MachO) void { | |
| 1543 | 1435 | if (self.getZigObject()) |zo| { |
| 1544 | try zo.asFile().claimUnresolved(self); | |
| 1436 | zo.asFile().claimUnresolved(self); | |
| 1545 | 1437 | } |
| 1546 | 1438 | for (self.objects.items) |index| { |
| 1547 | try self.getFile(index).?.claimUnresolved(self); | |
| 1439 | self.getFile(index).?.claimUnresolved(self); | |
| 1548 | 1440 | } |
| 1549 | 1441 | } |
| 1550 | 1442 | |
| 1551 | 1443 | fn checkDuplicates(self: *MachO) !void { |
| 1552 | const gpa = self.base.comp.gpa; | |
| 1553 | ||
| 1554 | var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa); | |
| 1555 | defer { | |
| 1556 | for (dupes.values()) |*list| { | |
| 1557 | list.deinit(gpa); | |
| 1558 | } | |
| 1559 | dupes.deinit(); | |
| 1560 | } | |
| 1561 | ||
| 1562 | 1444 | if (self.getZigObject()) |zo| { |
| 1563 | try zo.checkDuplicates(&dupes, self); | |
| 1445 | try zo.asFile().checkDuplicates(self); | |
| 1564 | 1446 | } |
| 1565 | ||
| 1566 | 1447 | for (self.objects.items) |index| { |
| 1567 | try self.getFile(index).?.object.checkDuplicates(&dupes, self); | |
| 1448 | try self.getFile(index).?.checkDuplicates(self); | |
| 1568 | 1449 | } |
| 1569 | ||
| 1570 | try self.reportDuplicates(dupes); | |
| 1450 | if (self.getInternalObject()) |obj| { | |
| 1451 | try obj.asFile().checkDuplicates(self); | |
| 1452 | } | |
| 1453 | try self.reportDuplicates(); | |
| 1571 | 1454 | } |
| 1572 | 1455 | |
| 1573 | 1456 | fn markImportsAndExports(self: *MachO) void { |
| 1457 | const tracy = trace(@src()); | |
| 1458 | defer tracy.end(); | |
| 1459 | ||
| 1574 | 1460 | if (self.getZigObject()) |zo| { |
| 1575 | 1461 | zo.asFile().markImportsExports(self); |
| 1576 | 1462 | } |
| 1577 | 1463 | for (self.objects.items) |index| { |
| 1578 | 1464 | self.getFile(index).?.markImportsExports(self); |
| 1579 | 1465 | } |
| 1580 | ||
| 1581 | for (self.undefined_symbols.items) |index| { | |
| 1582 | const sym = self.getSymbol(index); | |
| 1583 | if (sym.getFile(self)) |file| { | |
| 1584 | if (sym.visibility != .global) continue; | |
| 1585 | if (file == .dylib and !sym.flags.abs) sym.flags.import = true; | |
| 1586 | } | |
| 1587 | } | |
| 1588 | ||
| 1589 | for (&[_]?Symbol.Index{ | |
| 1590 | self.entry_index, | |
| 1591 | self.dyld_stub_binder_index, | |
| 1592 | self.objc_msg_send_index, | |
| 1593 | }) |index| { | |
| 1594 | if (index) |idx| { | |
| 1595 | const sym = self.getSymbol(idx); | |
| 1596 | if (sym.getFile(self)) |file| { | |
| 1597 | if (file == .dylib) sym.flags.import = true; | |
| 1598 | } | |
| 1599 | } | |
| 1466 | if (self.getInternalObject()) |obj| { | |
| 1467 | obj.asFile().markImportsExports(self); | |
| 1600 | 1468 | } |
| 1601 | 1469 | } |
| 1602 | 1470 | |
| 1603 | 1471 | fn deadStripDylibs(self: *MachO) void { |
| 1604 | for (&[_]?Symbol.Index{ | |
| 1605 | self.entry_index, | |
| 1606 | self.dyld_stub_binder_index, | |
| 1607 | self.objc_msg_send_index, | |
| 1608 | }) |index| { | |
| 1609 | if (index) |idx| { | |
| 1610 | const sym = self.getSymbol(idx); | |
| 1611 | if (sym.getFile(self)) |file| { | |
| 1612 | if (file == .dylib) file.dylib.referenced = true; | |
| 1613 | } | |
| 1614 | } | |
| 1615 | } | |
| 1472 | const tracy = trace(@src()); | |
| 1473 | defer tracy.end(); | |
| 1616 | 1474 | |
| 1617 | 1475 | for (self.dylibs.items) |index| { |
| 1618 | 1476 | self.getFile(index).?.dylib.markReferenced(self); |
| ... | ... | @@ -1633,50 +1491,29 @@ fn scanRelocs(self: *MachO) !void { |
| 1633 | 1491 | const tracy = trace(@src()); |
| 1634 | 1492 | defer tracy.end(); |
| 1635 | 1493 | |
| 1636 | if (self.getZigObject()) |zo| try zo.scanRelocs(self); | |
| 1637 | ||
| 1494 | if (self.getZigObject()) |zo| { | |
| 1495 | try zo.scanRelocs(self); | |
| 1496 | } | |
| 1638 | 1497 | for (self.objects.items) |index| { |
| 1639 | 1498 | try self.getFile(index).?.object.scanRelocs(self); |
| 1640 | 1499 | } |
| 1500 | if (self.getInternalObject()) |obj| { | |
| 1501 | obj.scanRelocs(self); | |
| 1502 | } | |
| 1641 | 1503 | |
| 1642 | 1504 | try self.reportUndefs(); |
| 1643 | 1505 | |
| 1644 | if (self.entry_index) |index| { | |
| 1645 | const sym = self.getSymbol(index); | |
| 1646 | if (sym.getFile(self) != null) { | |
| 1647 | if (sym.flags.import) sym.flags.stubs = true; | |
| 1648 | } | |
| 1506 | if (self.getZigObject()) |zo| { | |
| 1507 | try zo.asFile().createSymbolIndirection(self); | |
| 1649 | 1508 | } |
| 1650 | ||
| 1651 | if (self.dyld_stub_binder_index) |index| { | |
| 1652 | const sym = self.getSymbol(index); | |
| 1653 | if (sym.getFile(self) != null) sym.flags.needs_got = true; | |
| 1509 | for (self.objects.items) |index| { | |
| 1510 | try self.getFile(index).?.createSymbolIndirection(self); | |
| 1654 | 1511 | } |
| 1655 | ||
| 1656 | if (self.objc_msg_send_index) |index| { | |
| 1657 | const sym = self.getSymbol(index); | |
| 1658 | if (sym.getFile(self) != null) | |
| 1659 | sym.flags.needs_got = true; // TODO is it always needed, or only if we are synthesising fast stubs? | |
| 1512 | for (self.dylibs.items) |index| { | |
| 1513 | try self.getFile(index).?.createSymbolIndirection(self); | |
| 1660 | 1514 | } |
| 1661 | ||
| 1662 | for (self.symbols.items, 0..) |*symbol, i| { | |
| 1663 | const index = @as(Symbol.Index, @intCast(i)); | |
| 1664 | if (symbol.flags.needs_got) { | |
| 1665 | log.debug("'{s}' needs GOT", .{symbol.getName(self)}); | |
| 1666 | try self.got.addSymbol(index, self); | |
| 1667 | } | |
| 1668 | if (symbol.flags.stubs) { | |
| 1669 | log.debug("'{s}' needs STUBS", .{symbol.getName(self)}); | |
| 1670 | try self.stubs.addSymbol(index, self); | |
| 1671 | } | |
| 1672 | if (symbol.flags.tlv_ptr) { | |
| 1673 | log.debug("'{s}' needs TLV pointer", .{symbol.getName(self)}); | |
| 1674 | try self.tlv_ptr.addSymbol(index, self); | |
| 1675 | } | |
| 1676 | if (symbol.flags.objc_stubs) { | |
| 1677 | log.debug("'{s}' needs OBJC STUBS", .{symbol.getName(self)}); | |
| 1678 | try self.objc_stubs.addSymbol(index, self); | |
| 1679 | } | |
| 1515 | if (self.getInternalObject()) |obj| { | |
| 1516 | try obj.asFile().createSymbolIndirection(self); | |
| 1680 | 1517 | } |
| 1681 | 1518 | } |
| 1682 | 1519 | |
| ... | ... | @@ -1684,17 +1521,15 @@ fn reportUndefs(self: *MachO) !void { |
| 1684 | 1521 | const tracy = trace(@src()); |
| 1685 | 1522 | defer tracy.end(); |
| 1686 | 1523 | |
| 1687 | switch (self.undefined_treatment) { | |
| 1688 | .dynamic_lookup, .suppress => return, | |
| 1689 | .@"error", .warn => {}, | |
| 1690 | } | |
| 1524 | if (self.undefined_treatment == .suppress or | |
| 1525 | self.undefined_treatment == .dynamic_lookup) return; | |
| 1691 | 1526 | |
| 1692 | 1527 | const max_notes = 4; |
| 1693 | 1528 | |
| 1694 | 1529 | var has_undefs = false; |
| 1695 | 1530 | var it = self.undefs.iterator(); |
| 1696 | 1531 | while (it.next()) |entry| { |
| 1697 | const undef_sym = self.getSymbol(entry.key_ptr.*); | |
| 1532 | const undef_sym = self.resolver.keys.items[entry.key_ptr.* - 1]; | |
| 1698 | 1533 | const notes = entry.value_ptr.*; |
| 1699 | 1534 | const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); |
| 1700 | 1535 | |
| ... | ... | @@ -1704,8 +1539,9 @@ fn reportUndefs(self: *MachO) !void { |
| 1704 | 1539 | |
| 1705 | 1540 | var inote: usize = 0; |
| 1706 | 1541 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { |
| 1707 | const atom = self.getAtom(notes.items[inote]).?; | |
| 1708 | const file = atom.getFile(self); | |
| 1542 | const note = notes.items[inote]; | |
| 1543 | const file = self.getFile(note.file).?; | |
| 1544 | const atom = note.getAtom(self).?; | |
| 1709 | 1545 | try err.addNote(self, "referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) }); |
| 1710 | 1546 | } |
| 1711 | 1547 | |
| ... | ... | @@ -1714,64 +1550,18 @@ fn reportUndefs(self: *MachO) !void { |
| 1714 | 1550 | try err.addNote(self, "referenced {d} more times", .{remaining}); |
| 1715 | 1551 | } |
| 1716 | 1552 | } |
| 1717 | ||
| 1718 | for (self.undefined_symbols.items) |index| { | |
| 1719 | const sym = self.getSymbol(index); | |
| 1720 | if (sym.getFile(self) != null) continue; // If undefined in an object file, will be reported above | |
| 1721 | has_undefs = true; | |
| 1722 | var err = try self.addErrorWithNotes(1); | |
| 1723 | try err.addMsg(self, "undefined symbol: {s}", .{sym.getName(self)}); | |
| 1724 | try err.addNote(self, "-u command line option", .{}); | |
| 1725 | } | |
| 1726 | ||
| 1727 | if (self.entry_index) |index| { | |
| 1728 | const sym = self.getSymbol(index); | |
| 1729 | if (sym.getFile(self) == null) { | |
| 1730 | has_undefs = true; | |
| 1731 | var err = try self.addErrorWithNotes(1); | |
| 1732 | try err.addMsg(self, "undefined symbol: {s}", .{sym.getName(self)}); | |
| 1733 | try err.addNote(self, "implicit entry/start for main executable", .{}); | |
| 1734 | } | |
| 1735 | } | |
| 1736 | ||
| 1737 | if (self.dyld_stub_binder_index) |index| { | |
| 1738 | const sym = self.getSymbol(index); | |
| 1739 | if (sym.getFile(self) == null and self.stubs_sect_index != null) { | |
| 1740 | has_undefs = true; | |
| 1741 | var err = try self.addErrorWithNotes(1); | |
| 1742 | try err.addMsg(self, "undefined symbol: {s}", .{sym.getName(self)}); | |
| 1743 | try err.addNote(self, "implicit -u command line option", .{}); | |
| 1744 | } | |
| 1745 | } | |
| 1746 | ||
| 1747 | if (self.objc_msg_send_index) |index| { | |
| 1748 | const sym = self.getSymbol(index); | |
| 1749 | if (sym.getFile(self) == null and self.objc_stubs_sect_index != null) { | |
| 1750 | has_undefs = true; | |
| 1751 | var err = try self.addErrorWithNotes(1); | |
| 1752 | try err.addMsg(self, "undefined symbol: {s}", .{sym.getName(self)}); | |
| 1753 | try err.addNote(self, "implicit -u command line option", .{}); | |
| 1754 | } | |
| 1755 | } | |
| 1756 | ||
| 1757 | 1553 | if (has_undefs) return error.HasUndefinedSymbols; |
| 1758 | 1554 | } |
| 1759 | 1555 | |
| 1760 | 1556 | fn initOutputSections(self: *MachO) !void { |
| 1557 | const tracy = trace(@src()); | |
| 1558 | defer tracy.end(); | |
| 1559 | ||
| 1761 | 1560 | for (self.objects.items) |index| { |
| 1762 | const object = self.getFile(index).?.object; | |
| 1763 | for (object.atoms.items) |atom_index| { | |
| 1764 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1765 | if (!atom.flags.alive) continue; | |
| 1766 | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(self), self); | |
| 1767 | } | |
| 1561 | try self.getFile(index).?.initOutputSections(self); | |
| 1768 | 1562 | } |
| 1769 | if (self.getInternalObject()) |object| { | |
| 1770 | for (object.atoms.items) |atom_index| { | |
| 1771 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1772 | if (!atom.flags.alive) continue; | |
| 1773 | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(self), self); | |
| 1774 | } | |
| 1563 | if (self.getInternalObject()) |obj| { | |
| 1564 | try obj.asFile().initOutputSections(self); | |
| 1775 | 1565 | } |
| 1776 | 1566 | self.text_sect_index = self.getSectionByName("__TEXT", "__text") orelse |
| 1777 | 1567 | try self.addSection("__TEXT", "__text", .{ |
| ... | ... | @@ -1844,46 +1634,50 @@ fn initSyntheticSections(self: *MachO) !void { |
| 1844 | 1634 | self.eh_frame_sect_index = try self.addSection("__TEXT", "__eh_frame", .{}); |
| 1845 | 1635 | } |
| 1846 | 1636 | |
| 1847 | for (self.boundary_symbols.items) |sym_index| { | |
| 1637 | if (self.getInternalObject()) |obj| { | |
| 1848 | 1638 | const gpa = self.base.comp.gpa; |
| 1849 | const sym = self.getSymbol(sym_index); | |
| 1850 | const name = sym.getName(self); | |
| 1851 | ||
| 1852 | if (eatPrefix(name, "segment$start$")) |segname| { | |
| 1853 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid | |
| 1854 | const prot = getSegmentProt(segname); | |
| 1855 | _ = try self.segments.append(gpa, .{ | |
| 1856 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 1857 | .segname = makeStaticString(segname), | |
| 1858 | .initprot = prot, | |
| 1859 | .maxprot = prot, | |
| 1860 | }); | |
| 1861 | } | |
| 1862 | } else if (eatPrefix(name, "segment$stop$")) |segname| { | |
| 1863 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid | |
| 1864 | const prot = getSegmentProt(segname); | |
| 1865 | _ = try self.segments.append(gpa, .{ | |
| 1866 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 1867 | .segname = makeStaticString(segname), | |
| 1868 | .initprot = prot, | |
| 1869 | .maxprot = prot, | |
| 1870 | }); | |
| 1871 | } | |
| 1872 | } else if (eatPrefix(name, "section$start$")) |actual_name| { | |
| 1873 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | |
| 1874 | const segname = actual_name[0..sep]; // TODO check segname is valid | |
| 1875 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid | |
| 1876 | if (self.getSectionByName(segname, sectname) == null) { | |
| 1877 | _ = try self.addSection(segname, sectname, .{}); | |
| 1878 | } | |
| 1879 | } else if (eatPrefix(name, "section$stop$")) |actual_name| { | |
| 1880 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | |
| 1881 | const segname = actual_name[0..sep]; // TODO check segname is valid | |
| 1882 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid | |
| 1883 | if (self.getSectionByName(segname, sectname) == null) { | |
| 1884 | _ = try self.addSection(segname, sectname, .{}); | |
| 1885 | } | |
| 1886 | } else unreachable; | |
| 1639 | ||
| 1640 | for (obj.boundary_symbols.items) |sym_index| { | |
| 1641 | const ref = obj.getSymbolRef(sym_index, self); | |
| 1642 | const sym = ref.getSymbol(self).?; | |
| 1643 | const name = sym.getName(self); | |
| 1644 | ||
| 1645 | if (eatPrefix(name, "segment$start$")) |segname| { | |
| 1646 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid | |
| 1647 | const prot = getSegmentProt(segname); | |
| 1648 | _ = try self.segments.append(gpa, .{ | |
| 1649 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 1650 | .segname = makeStaticString(segname), | |
| 1651 | .initprot = prot, | |
| 1652 | .maxprot = prot, | |
| 1653 | }); | |
| 1654 | } | |
| 1655 | } else if (eatPrefix(name, "segment$stop$")) |segname| { | |
| 1656 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid | |
| 1657 | const prot = getSegmentProt(segname); | |
| 1658 | _ = try self.segments.append(gpa, .{ | |
| 1659 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 1660 | .segname = makeStaticString(segname), | |
| 1661 | .initprot = prot, | |
| 1662 | .maxprot = prot, | |
| 1663 | }); | |
| 1664 | } | |
| 1665 | } else if (eatPrefix(name, "section$start$")) |actual_name| { | |
| 1666 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | |
| 1667 | const segname = actual_name[0..sep]; // TODO check segname is valid | |
| 1668 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid | |
| 1669 | if (self.getSectionByName(segname, sectname) == null) { | |
| 1670 | _ = try self.addSection(segname, sectname, .{}); | |
| 1671 | } | |
| 1672 | } else if (eatPrefix(name, "section$stop$")) |actual_name| { | |
| 1673 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | |
| 1674 | const segname = actual_name[0..sep]; // TODO check segname is valid | |
| 1675 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid | |
| 1676 | if (self.getSectionByName(segname, sectname) == null) { | |
| 1677 | _ = try self.addSection(segname, sectname, .{}); | |
| 1678 | } | |
| 1679 | } else unreachable; | |
| 1680 | } | |
| 1887 | 1681 | } |
| 1888 | 1682 | } |
| 1889 | 1683 | |
| ... | ... | @@ -1990,38 +1784,25 @@ pub fn sortSections(self: *MachO) !void { |
| 1990 | 1784 | } |
| 1991 | 1785 | |
| 1992 | 1786 | if (self.getZigObject()) |zo| { |
| 1993 | for (zo.atoms.items) |atom_index| { | |
| 1994 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1787 | for (zo.getAtoms()) |atom_index| { | |
| 1788 | const atom = zo.getAtom(atom_index) orelse continue; | |
| 1995 | 1789 | if (!atom.flags.alive) continue; |
| 1996 | 1790 | atom.out_n_sect = backlinks[atom.out_n_sect]; |
| 1997 | 1791 | } |
| 1998 | ||
| 1999 | for (zo.symtab.items(.nlist)) |*sym| { | |
| 2000 | if (sym.sect()) { | |
| 2001 | sym.n_sect = backlinks[sym.n_sect - 1] + 1; | |
| 2002 | } | |
| 2003 | } | |
| 2004 | ||
| 2005 | for (zo.symbols.items) |sym_index| { | |
| 2006 | const sym = self.getSymbol(sym_index); | |
| 2007 | const atom = sym.getAtom(self) orelse continue; | |
| 2008 | if (!atom.flags.alive) continue; | |
| 2009 | if (sym.getFile(self).?.getIndex() != zo.index) continue; | |
| 2010 | sym.out_n_sect = backlinks[sym.out_n_sect]; | |
| 2011 | } | |
| 2012 | 1792 | } |
| 2013 | 1793 | |
| 2014 | 1794 | for (self.objects.items) |index| { |
| 2015 | for (self.getFile(index).?.object.atoms.items) |atom_index| { | |
| 2016 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1795 | const file = self.getFile(index).?; | |
| 1796 | for (file.getAtoms()) |atom_index| { | |
| 1797 | const atom = file.getAtom(atom_index) orelse continue; | |
| 2017 | 1798 | if (!atom.flags.alive) continue; |
| 2018 | 1799 | atom.out_n_sect = backlinks[atom.out_n_sect]; |
| 2019 | 1800 | } |
| 2020 | 1801 | } |
| 2021 | 1802 | |
| 2022 | 1803 | if (self.getInternalObject()) |object| { |
| 2023 | for (object.atoms.items) |atom_index| { | |
| 2024 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1804 | for (object.getAtoms()) |atom_index| { | |
| 1805 | const atom = object.getAtom(atom_index) orelse continue; | |
| 2025 | 1806 | if (!atom.flags.alive) continue; |
| 2026 | 1807 | atom.out_n_sect = backlinks[atom.out_n_sect]; |
| 2027 | 1808 | } |
| ... | ... | @@ -2058,35 +1839,32 @@ pub fn addAtomsToSections(self: *MachO) !void { |
| 2058 | 1839 | const tracy = trace(@src()); |
| 2059 | 1840 | defer tracy.end(); |
| 2060 | 1841 | |
| 2061 | for (self.objects.items) |index| { | |
| 2062 | const object = self.getFile(index).?.object; | |
| 2063 | for (object.atoms.items) |atom_index| { | |
| 2064 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1842 | const gpa = self.base.comp.gpa; | |
| 1843 | ||
| 1844 | if (self.getZigObject()) |zo| { | |
| 1845 | for (zo.getAtoms()) |atom_index| { | |
| 1846 | const atom = zo.getAtom(atom_index) orelse continue; | |
| 2065 | 1847 | if (!atom.flags.alive) continue; |
| 1848 | if (self.isZigSection(atom.out_n_sect)) continue; | |
| 2066 | 1849 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; |
| 2067 | try atoms.append(self.base.comp.gpa, atom_index); | |
| 1850 | try atoms.append(gpa, .{ .index = atom_index, .file = zo.index }); | |
| 2068 | 1851 | } |
| 2069 | for (object.symbols.items) |sym_index| { | |
| 2070 | const sym = self.getSymbol(sym_index); | |
| 2071 | const atom = sym.getAtom(self) orelse continue; | |
| 1852 | } | |
| 1853 | for (self.objects.items) |index| { | |
| 1854 | const file = self.getFile(index).?; | |
| 1855 | for (file.getAtoms()) |atom_index| { | |
| 1856 | const atom = file.getAtom(atom_index) orelse continue; | |
| 2072 | 1857 | if (!atom.flags.alive) continue; |
| 2073 | if (sym.getFile(self).?.getIndex() != index) continue; | |
| 2074 | sym.out_n_sect = atom.out_n_sect; | |
| 1858 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; | |
| 1859 | try atoms.append(gpa, .{ .index = atom_index, .file = index }); | |
| 2075 | 1860 | } |
| 2076 | 1861 | } |
| 2077 | 1862 | if (self.getInternalObject()) |object| { |
| 2078 | for (object.atoms.items) |atom_index| { | |
| 2079 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1863 | for (object.getAtoms()) |atom_index| { | |
| 1864 | const atom = object.getAtom(atom_index) orelse continue; | |
| 2080 | 1865 | if (!atom.flags.alive) continue; |
| 2081 | 1866 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; |
| 2082 | try atoms.append(self.base.comp.gpa, atom_index); | |
| 2083 | } | |
| 2084 | for (object.symbols.items) |sym_index| { | |
| 2085 | const sym = self.getSymbol(sym_index); | |
| 2086 | const atom = sym.getAtom(self) orelse continue; | |
| 2087 | if (!atom.flags.alive) continue; | |
| 2088 | if (sym.getFile(self).?.getIndex() != object.index) continue; | |
| 2089 | sym.out_n_sect = atom.out_n_sect; | |
| 1867 | try atoms.append(gpa, .{ .index = atom_index, .file = object.index }); | |
| 2090 | 1868 | } |
| 2091 | 1869 | } |
| 2092 | 1870 | } |
| ... | ... | @@ -2108,8 +1886,8 @@ fn calcSectionSizes(self: *MachO) !void { |
| 2108 | 1886 | if (atoms.items.len == 0) continue; |
| 2109 | 1887 | if (self.requiresThunks() and header.isCode()) continue; |
| 2110 | 1888 | |
| 2111 | for (atoms.items) |atom_index| { | |
| 2112 | const atom = self.getAtom(atom_index).?; | |
| 1889 | for (atoms.items) |ref| { | |
| 1890 | const atom = ref.getAtom(self).?; | |
| 2113 | 1891 | const atom_alignment = atom.alignment.toByteUnits() orelse 1; |
| 2114 | 1892 | const offset = mem.alignForward(u64, header.size, atom_alignment); |
| 2115 | 1893 | const padding = offset - header.size; |
| ... | ... | @@ -2129,6 +1907,22 @@ fn calcSectionSizes(self: *MachO) !void { |
| 2129 | 1907 | } |
| 2130 | 1908 | } |
| 2131 | 1909 | |
| 1910 | // At this point, we can also calculate symtab and data-in-code linkedit section sizes | |
| 1911 | if (self.getZigObject()) |zo| { | |
| 1912 | zo.asFile().calcSymtabSize(self); | |
| 1913 | } | |
| 1914 | for (self.objects.items) |index| { | |
| 1915 | self.getFile(index).?.calcSymtabSize(self); | |
| 1916 | } | |
| 1917 | for (self.dylibs.items) |index| { | |
| 1918 | self.getFile(index).?.calcSymtabSize(self); | |
| 1919 | } | |
| 1920 | if (self.getInternalObject()) |obj| { | |
| 1921 | obj.asFile().calcSymtabSize(self); | |
| 1922 | } | |
| 1923 | ||
| 1924 | try self.calcSymtabSize(); | |
| 1925 | ||
| 2132 | 1926 | if (self.got_sect_index) |idx| { |
| 2133 | 1927 | const header = &self.sections.items(.header)[idx]; |
| 2134 | 1928 | header.size = self.got.size(); |
| ... | ... | @@ -2409,77 +2203,61 @@ fn allocateSegments(self: *MachO) void { |
| 2409 | 2203 | } |
| 2410 | 2204 | |
| 2411 | 2205 | fn allocateSyntheticSymbols(self: *MachO) void { |
| 2412 | const text_seg = self.getTextSegment(); | |
| 2413 | ||
| 2414 | if (self.mh_execute_header_index) |index| { | |
| 2415 | const global = self.getSymbol(index); | |
| 2416 | global.value = text_seg.vmaddr; | |
| 2417 | } | |
| 2206 | if (self.getInternalObject()) |obj| { | |
| 2207 | obj.allocateSyntheticSymbols(self); | |
| 2418 | 2208 | |
| 2419 | if (self.data_sect_index) |idx| { | |
| 2420 | const sect = self.sections.items(.header)[idx]; | |
| 2421 | for (&[_]?Symbol.Index{ | |
| 2422 | self.dso_handle_index, | |
| 2423 | self.mh_dylib_header_index, | |
| 2424 | self.dyld_private_index, | |
| 2425 | }) |maybe_index| { | |
| 2426 | if (maybe_index) |index| { | |
| 2427 | const global = self.getSymbol(index); | |
| 2428 | global.value = sect.addr; | |
| 2429 | global.out_n_sect = idx; | |
| 2430 | } | |
| 2431 | } | |
| 2432 | } | |
| 2209 | const text_seg = self.getTextSegment(); | |
| 2433 | 2210 | |
| 2434 | for (self.boundary_symbols.items) |sym_index| { | |
| 2435 | const sym = self.getSymbol(sym_index); | |
| 2436 | const name = sym.getName(self); | |
| 2211 | for (obj.boundary_symbols.items) |sym_index| { | |
| 2212 | const ref = obj.getSymbolRef(sym_index, self); | |
| 2213 | const sym = ref.getSymbol(self).?; | |
| 2214 | const name = sym.getName(self); | |
| 2437 | 2215 | |
| 2438 | sym.flags.@"export" = false; | |
| 2439 | sym.value = text_seg.vmaddr; | |
| 2216 | sym.value = text_seg.vmaddr; | |
| 2440 | 2217 | |
| 2441 | if (mem.startsWith(u8, name, "segment$start$")) { | |
| 2442 | const segname = name["segment$start$".len..]; | |
| 2443 | if (self.getSegmentByName(segname)) |seg_id| { | |
| 2444 | const seg = self.segments.items[seg_id]; | |
| 2445 | sym.value = seg.vmaddr; | |
| 2446 | } | |
| 2447 | } else if (mem.startsWith(u8, name, "segment$stop$")) { | |
| 2448 | const segname = name["segment$stop$".len..]; | |
| 2449 | if (self.getSegmentByName(segname)) |seg_id| { | |
| 2450 | const seg = self.segments.items[seg_id]; | |
| 2451 | sym.value = seg.vmaddr + seg.vmsize; | |
| 2452 | } | |
| 2453 | } else if (mem.startsWith(u8, name, "section$start$")) { | |
| 2454 | const actual_name = name["section$start$".len..]; | |
| 2455 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | |
| 2456 | const segname = actual_name[0..sep]; | |
| 2457 | const sectname = actual_name[sep + 1 ..]; | |
| 2458 | if (self.getSectionByName(segname, sectname)) |sect_id| { | |
| 2459 | const sect = self.sections.items(.header)[sect_id]; | |
| 2460 | sym.value = sect.addr; | |
| 2461 | sym.out_n_sect = sect_id; | |
| 2462 | } | |
| 2463 | } else if (mem.startsWith(u8, name, "section$stop$")) { | |
| 2464 | const actual_name = name["section$stop$".len..]; | |
| 2465 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | |
| 2466 | const segname = actual_name[0..sep]; | |
| 2467 | const sectname = actual_name[sep + 1 ..]; | |
| 2468 | if (self.getSectionByName(segname, sectname)) |sect_id| { | |
| 2469 | const sect = self.sections.items(.header)[sect_id]; | |
| 2470 | sym.value = sect.addr + sect.size; | |
| 2471 | sym.out_n_sect = sect_id; | |
| 2472 | } | |
| 2473 | } else unreachable; | |
| 2474 | } | |
| 2218 | if (mem.startsWith(u8, name, "segment$start$")) { | |
| 2219 | const segname = name["segment$start$".len..]; | |
| 2220 | if (self.getSegmentByName(segname)) |seg_id| { | |
| 2221 | const seg = self.segments.items[seg_id]; | |
| 2222 | sym.value = seg.vmaddr; | |
| 2223 | } | |
| 2224 | } else if (mem.startsWith(u8, name, "segment$stop$")) { | |
| 2225 | const segname = name["segment$stop$".len..]; | |
| 2226 | if (self.getSegmentByName(segname)) |seg_id| { | |
| 2227 | const seg = self.segments.items[seg_id]; | |
| 2228 | sym.value = seg.vmaddr + seg.vmsize; | |
| 2229 | } | |
| 2230 | } else if (mem.startsWith(u8, name, "section$start$")) { | |
| 2231 | const actual_name = name["section$start$".len..]; | |
| 2232 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | |
| 2233 | const segname = actual_name[0..sep]; | |
| 2234 | const sectname = actual_name[sep + 1 ..]; | |
| 2235 | if (self.getSectionByName(segname, sectname)) |sect_id| { | |
| 2236 | const sect = self.sections.items(.header)[sect_id]; | |
| 2237 | sym.value = sect.addr; | |
| 2238 | sym.out_n_sect = sect_id; | |
| 2239 | } | |
| 2240 | } else if (mem.startsWith(u8, name, "section$stop$")) { | |
| 2241 | const actual_name = name["section$stop$".len..]; | |
| 2242 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | |
| 2243 | const segname = actual_name[0..sep]; | |
| 2244 | const sectname = actual_name[sep + 1 ..]; | |
| 2245 | if (self.getSectionByName(segname, sectname)) |sect_id| { | |
| 2246 | const sect = self.sections.items(.header)[sect_id]; | |
| 2247 | sym.value = sect.addr + sect.size; | |
| 2248 | sym.out_n_sect = sect_id; | |
| 2249 | } | |
| 2250 | } else unreachable; | |
| 2251 | } | |
| 2475 | 2252 | |
| 2476 | if (self.objc_stubs.symbols.items.len > 0) { | |
| 2477 | const addr = self.sections.items(.header)[self.objc_stubs_sect_index.?].addr; | |
| 2253 | if (self.objc_stubs.symbols.items.len > 0) { | |
| 2254 | const addr = self.sections.items(.header)[self.objc_stubs_sect_index.?].addr; | |
| 2478 | 2255 | |
| 2479 | for (self.objc_stubs.symbols.items, 0..) |sym_index, idx| { | |
| 2480 | const sym = self.getSymbol(sym_index); | |
| 2481 | sym.value = addr + idx * ObjcStubsSection.entrySize(self.getTarget().cpu.arch); | |
| 2482 | sym.out_n_sect = self.objc_stubs_sect_index.?; | |
| 2256 | for (self.objc_stubs.symbols.items, 0..) |ref, idx| { | |
| 2257 | const sym = ref.getSymbol(self).?; | |
| 2258 | sym.value = addr + idx * ObjcStubsSection.entrySize(self.getTarget().cpu.arch); | |
| 2259 | sym.out_n_sect = self.objc_stubs_sect_index.?; | |
| 2260 | } | |
| 2483 | 2261 | } |
| 2484 | 2262 | } |
| 2485 | 2263 | } |
| ... | ... | @@ -2497,269 +2275,228 @@ fn allocateLinkeditSegment(self: *MachO) !void { |
| 2497 | 2275 | const seg = self.getLinkeditSegment(); |
| 2498 | 2276 | seg.vmaddr = mem.alignForward(u64, vmaddr, page_size); |
| 2499 | 2277 | seg.fileoff = mem.alignForward(u64, fileoff, page_size); |
| 2500 | } | |
| 2501 | ||
| 2502 | fn initDyldInfoSections(self: *MachO) !void { | |
| 2503 | const tracy = trace(@src()); | |
| 2504 | defer tracy.end(); | |
| 2505 | ||
| 2506 | const gpa = self.base.comp.gpa; | |
| 2507 | 2278 | |
| 2508 | if (self.zig_got_sect_index != null) try self.zig_got.addDyldRelocs(self); | |
| 2509 | if (self.got_sect_index != null) try self.got.addDyldRelocs(self); | |
| 2510 | if (self.tlv_ptr_sect_index != null) try self.tlv_ptr.addDyldRelocs(self); | |
| 2511 | if (self.la_symbol_ptr_sect_index != null) try self.la_symbol_ptr.addDyldRelocs(self); | |
| 2512 | try self.initExportTrie(); | |
| 2513 | ||
| 2514 | var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1); | |
| 2515 | defer objects.deinit(); | |
| 2516 | if (self.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index); | |
| 2517 | objects.appendSliceAssumeCapacity(self.objects.items); | |
| 2518 | ||
| 2519 | var nrebases: usize = 0; | |
| 2520 | var nbinds: usize = 0; | |
| 2521 | var nweak_binds: usize = 0; | |
| 2522 | for (objects.items) |index| { | |
| 2523 | const ctx = switch (self.getFile(index).?) { | |
| 2524 | .zig_object => |x| x.dynamic_relocs, | |
| 2525 | .object => |x| x.dynamic_relocs, | |
| 2526 | else => unreachable, | |
| 2527 | }; | |
| 2528 | nrebases += ctx.rebase_relocs; | |
| 2529 | nbinds += ctx.bind_relocs; | |
| 2530 | nweak_binds += ctx.weak_bind_relocs; | |
| 2531 | } | |
| 2532 | if (self.getInternalObject()) |int| { | |
| 2533 | nrebases += int.num_rebase_relocs; | |
| 2279 | var off = math.cast(u32, seg.fileoff) orelse return error.Overflow; | |
| 2280 | // DYLD_INFO_ONLY | |
| 2281 | { | |
| 2282 | const cmd = &self.dyld_info_cmd; | |
| 2283 | cmd.rebase_off = off; | |
| 2284 | off += cmd.rebase_size; | |
| 2285 | cmd.bind_off = off; | |
| 2286 | off += cmd.bind_size; | |
| 2287 | cmd.weak_bind_off = off; | |
| 2288 | off += cmd.weak_bind_size; | |
| 2289 | cmd.lazy_bind_off = off; | |
| 2290 | off += cmd.lazy_bind_size; | |
| 2291 | cmd.export_off = off; | |
| 2292 | off += cmd.export_size; | |
| 2293 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 2294 | } | |
| 2295 | ||
| 2296 | // FUNCTION_STARTS | |
| 2297 | { | |
| 2298 | const cmd = &self.function_starts_cmd; | |
| 2299 | cmd.dataoff = off; | |
| 2300 | off += cmd.datasize; | |
| 2301 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 2534 | 2302 | } |
| 2535 | try self.rebase.entries.ensureUnusedCapacity(gpa, nrebases); | |
| 2536 | try self.bind.entries.ensureUnusedCapacity(gpa, nbinds); | |
| 2537 | try self.weak_bind.entries.ensureUnusedCapacity(gpa, nweak_binds); | |
| 2538 | } | |
| 2539 | ||
| 2540 | fn initExportTrie(self: *MachO) !void { | |
| 2541 | const tracy = trace(@src()); | |
| 2542 | defer tracy.end(); | |
| 2543 | 2303 | |
| 2544 | const gpa = self.base.comp.gpa; | |
| 2545 | try self.export_trie.init(gpa); | |
| 2304 | // DATA_IN_CODE | |
| 2305 | { | |
| 2306 | const cmd = &self.data_in_code_cmd; | |
| 2307 | cmd.dataoff = off; | |
| 2308 | off += cmd.datasize; | |
| 2309 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 2310 | } | |
| 2546 | 2311 | |
| 2547 | const seg = self.getTextSegment(); | |
| 2548 | for (self.objects.items) |index| { | |
| 2549 | for (self.getFile(index).?.getSymbols()) |sym_index| { | |
| 2550 | const sym = self.getSymbol(sym_index); | |
| 2551 | if (!sym.flags.@"export") continue; | |
| 2552 | if (sym.getAtom(self)) |atom| if (!atom.flags.alive) continue; | |
| 2553 | if (sym.getFile(self).?.getIndex() != index) continue; | |
| 2554 | var flags: u64 = if (sym.flags.abs) | |
| 2555 | macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE | |
| 2556 | else if (sym.flags.tlv) | |
| 2557 | macho.EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL | |
| 2558 | else | |
| 2559 | macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR; | |
| 2560 | if (sym.flags.weak) { | |
| 2561 | flags |= macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; | |
| 2562 | self.weak_defines = true; | |
| 2563 | self.binds_to_weak = true; | |
| 2564 | } | |
| 2565 | try self.export_trie.put(gpa, .{ | |
| 2566 | .name = sym.getName(self), | |
| 2567 | .vmaddr_offset = sym.getAddress(.{ .stubs = false }, self) - seg.vmaddr, | |
| 2568 | .export_flags = flags, | |
| 2569 | }); | |
| 2570 | } | |
| 2312 | // SYMTAB (symtab) | |
| 2313 | { | |
| 2314 | const cmd = &self.symtab_cmd; | |
| 2315 | cmd.symoff = off; | |
| 2316 | off += cmd.nsyms * @sizeOf(macho.nlist_64); | |
| 2317 | off = mem.alignForward(u32, off, @alignOf(u32)); | |
| 2571 | 2318 | } |
| 2572 | 2319 | |
| 2573 | if (self.mh_execute_header_index) |index| { | |
| 2574 | const sym = self.getSymbol(index); | |
| 2575 | try self.export_trie.put(gpa, .{ | |
| 2576 | .name = sym.getName(self), | |
| 2577 | .vmaddr_offset = sym.getAddress(.{}, self) - seg.vmaddr, | |
| 2578 | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, | |
| 2579 | }); | |
| 2320 | // DYSYMTAB | |
| 2321 | { | |
| 2322 | const cmd = &self.dysymtab_cmd; | |
| 2323 | cmd.indirectsymoff = off; | |
| 2324 | off += cmd.nindirectsyms * @sizeOf(u32); | |
| 2325 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 2580 | 2326 | } |
| 2581 | } | |
| 2582 | 2327 | |
| 2583 | fn writeAtoms(self: *MachO) !void { | |
| 2584 | const tracy = trace(@src()); | |
| 2585 | defer tracy.end(); | |
| 2328 | // SYMTAB (strtab) | |
| 2329 | { | |
| 2330 | const cmd = &self.symtab_cmd; | |
| 2331 | cmd.stroff = off; | |
| 2332 | off += cmd.strsize; | |
| 2333 | } | |
| 2586 | 2334 | |
| 2587 | const gpa = self.base.comp.gpa; | |
| 2588 | var arena = std.heap.ArenaAllocator.init(gpa); | |
| 2589 | defer arena.deinit(); | |
| 2335 | seg.filesize = off - seg.fileoff; | |
| 2336 | } | |
| 2590 | 2337 | |
| 2591 | const cpu_arch = self.getTarget().cpu.arch; | |
| 2338 | fn resizeSections(self: *MachO) !void { | |
| 2592 | 2339 | const slice = self.sections.slice(); |
| 2593 | ||
| 2594 | var has_resolve_error = false; | |
| 2595 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { | |
| 2596 | if (atoms.items.len == 0) continue; | |
| 2340 | for (slice.items(.header), slice.items(.out), 0..) |header, *out, n_sect| { | |
| 2597 | 2341 | if (header.isZerofill()) continue; |
| 2598 | ||
| 2342 | if (self.isZigSection(@intCast(n_sect))) continue; // TODO this is horrible | |
| 2343 | const cpu_arch = self.getTarget().cpu.arch; | |
| 2599 | 2344 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2600 | const buffer = try gpa.alloc(u8, size); | |
| 2601 | defer gpa.free(buffer); | |
| 2345 | try out.resize(self.base.comp.gpa, size); | |
| 2602 | 2346 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; |
| 2603 | @memset(buffer, padding_byte); | |
| 2604 | ||
| 2605 | for (atoms.items) |atom_index| { | |
| 2606 | const atom = self.getAtom(atom_index).?; | |
| 2607 | assert(atom.flags.alive); | |
| 2608 | const off = math.cast(usize, atom.value) orelse return error.Overflow; | |
| 2609 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 2610 | try atom.getData(self, buffer[off..][0..atom_size]); | |
| 2611 | atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) { | |
| 2612 | error.ResolveFailed => has_resolve_error = true, | |
| 2613 | else => |e| return e, | |
| 2614 | }; | |
| 2615 | } | |
| 2616 | ||
| 2617 | try self.base.file.?.pwriteAll(buffer, header.offset); | |
| 2347 | @memset(out.items, padding_byte); | |
| 2618 | 2348 | } |
| 2349 | } | |
| 2350 | ||
| 2351 | fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void { | |
| 2352 | const gpa = self.base.comp.gpa; | |
| 2619 | 2353 | |
| 2354 | const cmd = self.symtab_cmd; | |
| 2355 | try self.symtab.resize(gpa, cmd.nsyms); | |
| 2356 | try self.strtab.resize(gpa, cmd.strsize); | |
| 2357 | self.strtab.items[0] = 0; | |
| 2358 | ||
| 2359 | for (self.objects.items) |index| { | |
| 2360 | try self.getFile(index).?.writeAtoms(self); | |
| 2361 | } | |
| 2362 | if (self.getZigObject()) |zo| { | |
| 2363 | try zo.writeAtoms(self); | |
| 2364 | } | |
| 2365 | if (self.getInternalObject()) |obj| { | |
| 2366 | try obj.asFile().writeAtoms(self); | |
| 2367 | } | |
| 2620 | 2368 | for (self.thunks.items) |thunk| { |
| 2621 | const header = slice.items(.header)[thunk.out_n_sect]; | |
| 2622 | const offset = thunk.value + header.offset; | |
| 2623 | const buffer = try gpa.alloc(u8, thunk.size()); | |
| 2624 | defer gpa.free(buffer); | |
| 2625 | var stream = std.io.fixedBufferStream(buffer); | |
| 2369 | const out = self.sections.items(.out)[thunk.out_n_sect].items; | |
| 2370 | const off = math.cast(usize, thunk.value) orelse return error.Overflow; | |
| 2371 | const size = thunk.size(); | |
| 2372 | var stream = std.io.fixedBufferStream(out[off..][0..size]); | |
| 2626 | 2373 | try thunk.write(self, stream.writer()); |
| 2627 | try self.base.file.?.pwriteAll(buffer, offset); | |
| 2628 | 2374 | } |
| 2629 | 2375 | |
| 2630 | if (has_resolve_error) return error.ResolveFailed; | |
| 2631 | } | |
| 2376 | const slice = self.sections.slice(); | |
| 2377 | for (&[_]?u8{ | |
| 2378 | self.eh_frame_sect_index, | |
| 2379 | self.unwind_info_sect_index, | |
| 2380 | self.got_sect_index, | |
| 2381 | self.stubs_sect_index, | |
| 2382 | self.la_symbol_ptr_sect_index, | |
| 2383 | self.tlv_ptr_sect_index, | |
| 2384 | self.objc_stubs_sect_index, | |
| 2385 | }) |maybe_sect_id| { | |
| 2386 | if (maybe_sect_id) |sect_id| { | |
| 2387 | const out = slice.items(.out)[sect_id].items; | |
| 2388 | try self.writeSyntheticSection(sect_id, out); | |
| 2389 | } | |
| 2390 | } | |
| 2632 | 2391 | |
| 2633 | fn writeUnwindInfo(self: *MachO) !void { | |
| 2634 | const tracy = trace(@src()); | |
| 2635 | defer tracy.end(); | |
| 2392 | if (self.la_symbol_ptr_sect_index) |_| { | |
| 2393 | try self.updateLazyBindSize(); | |
| 2394 | } | |
| 2636 | 2395 | |
| 2637 | const gpa = self.base.comp.gpa; | |
| 2396 | try self.rebase.updateSize(self); | |
| 2397 | try self.bind.updateSize(self); | |
| 2398 | try self.weak_bind.updateSize(self); | |
| 2399 | try self.export_trie.updateSize(self); | |
| 2400 | try self.data_in_code.updateSize(self); | |
| 2638 | 2401 | |
| 2639 | if (self.eh_frame_sect_index) |index| { | |
| 2640 | const header = self.sections.items(.header)[index]; | |
| 2641 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2642 | const buffer = try gpa.alloc(u8, size); | |
| 2643 | defer gpa.free(buffer); | |
| 2644 | eh_frame.write(self, buffer); | |
| 2645 | try self.base.file.?.pwriteAll(buffer, header.offset); | |
| 2402 | if (self.getZigObject()) |zo| { | |
| 2403 | zo.asFile().writeSymtab(self, self); | |
| 2646 | 2404 | } |
| 2647 | ||
| 2648 | if (self.unwind_info_sect_index) |index| { | |
| 2649 | const header = self.sections.items(.header)[index]; | |
| 2650 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2651 | const buffer = try gpa.alloc(u8, size); | |
| 2652 | defer gpa.free(buffer); | |
| 2653 | try self.unwind_info.write(self, buffer); | |
| 2654 | try self.base.file.?.pwriteAll(buffer, header.offset); | |
| 2405 | for (self.objects.items) |index| { | |
| 2406 | self.getFile(index).?.writeSymtab(self, self); | |
| 2407 | } | |
| 2408 | for (self.dylibs.items) |index| { | |
| 2409 | self.getFile(index).?.writeSymtab(self, self); | |
| 2410 | } | |
| 2411 | if (self.getInternalObject()) |obj| { | |
| 2412 | obj.asFile().writeSymtab(self, self); | |
| 2655 | 2413 | } |
| 2656 | 2414 | } |
| 2657 | 2415 | |
| 2658 | fn finalizeDyldInfoSections(self: *MachO) !void { | |
| 2416 | fn writeSyntheticSection(self: *MachO, sect_id: u8, out: []u8) !void { | |
| 2659 | 2417 | const tracy = trace(@src()); |
| 2660 | 2418 | defer tracy.end(); |
| 2661 | const gpa = self.base.comp.gpa; | |
| 2662 | 2419 | |
| 2663 | try self.rebase.finalize(gpa); | |
| 2664 | try self.bind.finalize(gpa, self); | |
| 2665 | try self.weak_bind.finalize(gpa, self); | |
| 2666 | try self.lazy_bind.finalize(gpa, self); | |
| 2667 | try self.export_trie.finalize(gpa); | |
| 2420 | const Tag = enum { | |
| 2421 | eh_frame, | |
| 2422 | unwind_info, | |
| 2423 | got, | |
| 2424 | stubs, | |
| 2425 | la_symbol_ptr, | |
| 2426 | tlv_ptr, | |
| 2427 | objc_stubs, | |
| 2428 | }; | |
| 2429 | ||
| 2430 | const tag: Tag = tag: { | |
| 2431 | if (self.eh_frame_sect_index != null and | |
| 2432 | self.eh_frame_sect_index.? == sect_id) break :tag .eh_frame; | |
| 2433 | if (self.unwind_info_sect_index != null and | |
| 2434 | self.unwind_info_sect_index.? == sect_id) break :tag .unwind_info; | |
| 2435 | if (self.got_sect_index != null and | |
| 2436 | self.got_sect_index.? == sect_id) break :tag .got; | |
| 2437 | if (self.stubs_sect_index != null and | |
| 2438 | self.stubs_sect_index.? == sect_id) break :tag .stubs; | |
| 2439 | if (self.la_symbol_ptr_sect_index != null and | |
| 2440 | self.la_symbol_ptr_sect_index.? == sect_id) break :tag .la_symbol_ptr; | |
| 2441 | if (self.tlv_ptr_sect_index != null and | |
| 2442 | self.tlv_ptr_sect_index.? == sect_id) break :tag .tlv_ptr; | |
| 2443 | if (self.objc_stubs_sect_index != null and | |
| 2444 | self.objc_stubs_sect_index.? == sect_id) break :tag .objc_stubs; | |
| 2445 | unreachable; | |
| 2446 | }; | |
| 2447 | var stream = std.io.fixedBufferStream(out); | |
| 2448 | switch (tag) { | |
| 2449 | .eh_frame => eh_frame.write(self, out), | |
| 2450 | .unwind_info => try self.unwind_info.write(self, out), | |
| 2451 | .got => try self.got.write(self, stream.writer()), | |
| 2452 | .stubs => try self.stubs.write(self, stream.writer()), | |
| 2453 | .la_symbol_ptr => try self.la_symbol_ptr.write(self, stream.writer()), | |
| 2454 | .tlv_ptr => try self.tlv_ptr.write(self, stream.writer()), | |
| 2455 | .objc_stubs => try self.objc_stubs.write(self, stream.writer()), | |
| 2456 | } | |
| 2668 | 2457 | } |
| 2669 | 2458 | |
| 2670 | fn writeSyntheticSections(self: *MachO) !void { | |
| 2459 | fn updateLazyBindSize(self: *MachO) !void { | |
| 2671 | 2460 | const tracy = trace(@src()); |
| 2672 | 2461 | defer tracy.end(); |
| 2462 | try self.lazy_bind.updateSize(self); | |
| 2463 | const sect_id = self.stubs_helper_sect_index.?; | |
| 2464 | const out = &self.sections.items(.out)[sect_id]; | |
| 2465 | var stream = std.io.fixedBufferStream(out.items); | |
| 2466 | try self.stubs_helper.write(self, stream.writer()); | |
| 2467 | } | |
| 2673 | 2468 | |
| 2674 | const gpa = self.base.comp.gpa; | |
| 2675 | ||
| 2676 | if (self.got_sect_index) |sect_id| { | |
| 2677 | const header = self.sections.items(.header)[sect_id]; | |
| 2678 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2679 | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); | |
| 2680 | defer buffer.deinit(); | |
| 2681 | try self.got.write(self, buffer.writer()); | |
| 2682 | assert(buffer.items.len == header.size); | |
| 2683 | try self.base.file.?.pwriteAll(buffer.items, header.offset); | |
| 2684 | } | |
| 2685 | ||
| 2686 | if (self.stubs_sect_index) |sect_id| { | |
| 2687 | const header = self.sections.items(.header)[sect_id]; | |
| 2688 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2689 | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); | |
| 2690 | defer buffer.deinit(); | |
| 2691 | try self.stubs.write(self, buffer.writer()); | |
| 2692 | assert(buffer.items.len == header.size); | |
| 2693 | try self.base.file.?.pwriteAll(buffer.items, header.offset); | |
| 2694 | } | |
| 2695 | ||
| 2696 | if (self.stubs_helper_sect_index) |sect_id| { | |
| 2697 | const header = self.sections.items(.header)[sect_id]; | |
| 2698 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2699 | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); | |
| 2700 | defer buffer.deinit(); | |
| 2701 | try self.stubs_helper.write(self, buffer.writer()); | |
| 2702 | assert(buffer.items.len == header.size); | |
| 2703 | try self.base.file.?.pwriteAll(buffer.items, header.offset); | |
| 2704 | } | |
| 2705 | ||
| 2706 | if (self.la_symbol_ptr_sect_index) |sect_id| { | |
| 2707 | const header = self.sections.items(.header)[sect_id]; | |
| 2708 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2709 | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); | |
| 2710 | defer buffer.deinit(); | |
| 2711 | try self.la_symbol_ptr.write(self, buffer.writer()); | |
| 2712 | assert(buffer.items.len == header.size); | |
| 2713 | try self.base.file.?.pwriteAll(buffer.items, header.offset); | |
| 2714 | } | |
| 2469 | fn writeSectionsToFile(self: *MachO) !void { | |
| 2470 | const tracy = trace(@src()); | |
| 2471 | defer tracy.end(); | |
| 2715 | 2472 | |
| 2716 | if (self.tlv_ptr_sect_index) |sect_id| { | |
| 2717 | const header = self.sections.items(.header)[sect_id]; | |
| 2718 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2719 | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); | |
| 2720 | defer buffer.deinit(); | |
| 2721 | try self.tlv_ptr.write(self, buffer.writer()); | |
| 2722 | assert(buffer.items.len == header.size); | |
| 2723 | try self.base.file.?.pwriteAll(buffer.items, header.offset); | |
| 2473 | const slice = self.sections.slice(); | |
| 2474 | for (slice.items(.header), slice.items(.out)) |header, out| { | |
| 2475 | try self.base.file.?.pwriteAll(out.items, header.offset); | |
| 2724 | 2476 | } |
| 2477 | } | |
| 2725 | 2478 | |
| 2726 | if (self.objc_stubs_sect_index) |sect_id| { | |
| 2727 | const header = self.sections.items(.header)[sect_id]; | |
| 2728 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2729 | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); | |
| 2730 | defer buffer.deinit(); | |
| 2731 | try self.objc_stubs.write(self, buffer.writer()); | |
| 2732 | assert(buffer.items.len == header.size); | |
| 2733 | try self.base.file.?.pwriteAll(buffer.items, header.offset); | |
| 2734 | } | |
| 2479 | fn writeLinkeditSectionsToFile(self: *MachO) !void { | |
| 2480 | const tracy = trace(@src()); | |
| 2481 | defer tracy.end(); | |
| 2482 | try self.writeDyldInfo(); | |
| 2483 | try self.writeDataInCode(); | |
| 2484 | try self.writeSymtabToFile(); | |
| 2485 | try self.writeIndsymtab(); | |
| 2735 | 2486 | } |
| 2736 | 2487 | |
| 2737 | fn writeDyldInfoSections(self: *MachO, off: u32) !u32 { | |
| 2488 | fn writeDyldInfo(self: *MachO) !void { | |
| 2738 | 2489 | const tracy = trace(@src()); |
| 2739 | 2490 | defer tracy.end(); |
| 2740 | 2491 | |
| 2741 | 2492 | const gpa = self.base.comp.gpa; |
| 2742 | const cmd = &self.dyld_info_cmd; | |
| 2493 | const base_off = self.getLinkeditSegment().fileoff; | |
| 2494 | const cmd = self.dyld_info_cmd; | |
| 2743 | 2495 | var needed_size: u32 = 0; |
| 2744 | ||
| 2745 | cmd.rebase_off = needed_size; | |
| 2746 | cmd.rebase_size = mem.alignForward(u32, @intCast(self.rebase.size()), @alignOf(u64)); | |
| 2747 | 2496 | needed_size += cmd.rebase_size; |
| 2748 | ||
| 2749 | cmd.bind_off = needed_size; | |
| 2750 | cmd.bind_size = mem.alignForward(u32, @intCast(self.bind.size()), @alignOf(u64)); | |
| 2751 | 2497 | needed_size += cmd.bind_size; |
| 2752 | ||
| 2753 | cmd.weak_bind_off = needed_size; | |
| 2754 | cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.weak_bind.size()), @alignOf(u64)); | |
| 2755 | 2498 | needed_size += cmd.weak_bind_size; |
| 2756 | ||
| 2757 | cmd.lazy_bind_off = needed_size; | |
| 2758 | cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.lazy_bind.size()), @alignOf(u64)); | |
| 2759 | 2499 | needed_size += cmd.lazy_bind_size; |
| 2760 | ||
| 2761 | cmd.export_off = needed_size; | |
| 2762 | cmd.export_size = mem.alignForward(u32, @intCast(self.export_trie.size), @alignOf(u64)); | |
| 2763 | 2500 | needed_size += cmd.export_size; |
| 2764 | 2501 | |
| 2765 | 2502 | const buffer = try gpa.alloc(u8, needed_size); |
| ... | ... | @@ -2770,89 +2507,78 @@ fn writeDyldInfoSections(self: *MachO, off: u32) !u32 { |
| 2770 | 2507 | const writer = stream.writer(); |
| 2771 | 2508 | |
| 2772 | 2509 | try self.rebase.write(writer); |
| 2773 | try stream.seekTo(cmd.bind_off); | |
| 2510 | try stream.seekTo(cmd.bind_off - base_off); | |
| 2774 | 2511 | try self.bind.write(writer); |
| 2775 | try stream.seekTo(cmd.weak_bind_off); | |
| 2512 | try stream.seekTo(cmd.weak_bind_off - base_off); | |
| 2776 | 2513 | try self.weak_bind.write(writer); |
| 2777 | try stream.seekTo(cmd.lazy_bind_off); | |
| 2514 | try stream.seekTo(cmd.lazy_bind_off - base_off); | |
| 2778 | 2515 | try self.lazy_bind.write(writer); |
| 2779 | try stream.seekTo(cmd.export_off); | |
| 2516 | try stream.seekTo(cmd.export_off - base_off); | |
| 2780 | 2517 | try self.export_trie.write(writer); |
| 2518 | try self.base.file.?.pwriteAll(buffer, cmd.rebase_off); | |
| 2519 | } | |
| 2781 | 2520 | |
| 2782 | cmd.rebase_off += off; | |
| 2783 | cmd.bind_off += off; | |
| 2784 | cmd.weak_bind_off += off; | |
| 2785 | cmd.lazy_bind_off += off; | |
| 2786 | cmd.export_off += off; | |
| 2787 | ||
| 2788 | try self.base.file.?.pwriteAll(buffer, off); | |
| 2521 | pub fn writeDataInCode(self: *MachO) !void { | |
| 2522 | const tracy = trace(@src()); | |
| 2523 | defer tracy.end(); | |
| 2524 | const gpa = self.base.comp.gpa; | |
| 2525 | const cmd = self.data_in_code_cmd; | |
| 2526 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size()); | |
| 2527 | defer buffer.deinit(); | |
| 2528 | try self.data_in_code.write(self, buffer.writer()); | |
| 2529 | try self.base.file.?.pwriteAll(buffer.items, cmd.dataoff); | |
| 2530 | } | |
| 2789 | 2531 | |
| 2790 | return off + needed_size; | |
| 2532 | fn writeIndsymtab(self: *MachO) !void { | |
| 2533 | const tracy = trace(@src()); | |
| 2534 | defer tracy.end(); | |
| 2535 | const gpa = self.base.comp.gpa; | |
| 2536 | const cmd = self.dysymtab_cmd; | |
| 2537 | const needed_size = cmd.nindirectsyms * @sizeOf(u32); | |
| 2538 | var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size); | |
| 2539 | defer buffer.deinit(); | |
| 2540 | try self.indsymtab.write(self, buffer.writer()); | |
| 2541 | try self.base.file.?.pwriteAll(buffer.items, cmd.indirectsymoff); | |
| 2791 | 2542 | } |
| 2792 | 2543 | |
| 2793 | fn writeFunctionStarts(self: *MachO, off: u32) !u32 { | |
| 2794 | // TODO actually write it out | |
| 2795 | const cmd = &self.function_starts_cmd; | |
| 2796 | cmd.dataoff = off; | |
| 2797 | return off; | |
| 2544 | pub fn writeSymtabToFile(self: *MachO) !void { | |
| 2545 | const tracy = trace(@src()); | |
| 2546 | defer tracy.end(); | |
| 2547 | const cmd = self.symtab_cmd; | |
| 2548 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); | |
| 2549 | try self.base.file.?.pwriteAll(self.strtab.items, cmd.stroff); | |
| 2798 | 2550 | } |
| 2799 | 2551 | |
| 2800 | pub fn writeDataInCode(self: *MachO, base_address: u64, off: u32) !u32 { | |
| 2801 | const cmd = &self.data_in_code_cmd; | |
| 2802 | cmd.dataoff = off; | |
| 2552 | fn writeUnwindInfo(self: *MachO) !void { | |
| 2553 | const tracy = trace(@src()); | |
| 2554 | defer tracy.end(); | |
| 2803 | 2555 | |
| 2804 | 2556 | const gpa = self.base.comp.gpa; |
| 2805 | var dices = std.ArrayList(macho.data_in_code_entry).init(gpa); | |
| 2806 | defer dices.deinit(); | |
| 2807 | 2557 | |
| 2808 | for (self.objects.items) |index| { | |
| 2809 | const object = self.getFile(index).?.object; | |
| 2810 | const in_dices = object.getDataInCode(); | |
| 2811 | ||
| 2812 | try dices.ensureUnusedCapacity(in_dices.len); | |
| 2813 | ||
| 2814 | var next_dice: usize = 0; | |
| 2815 | for (object.atoms.items) |atom_index| { | |
| 2816 | if (next_dice >= in_dices.len) break; | |
| 2817 | const atom = self.getAtom(atom_index) orelse continue; | |
| 2818 | const start_off = atom.getInputAddress(self); | |
| 2819 | const end_off = start_off + atom.size; | |
| 2820 | const start_dice = next_dice; | |
| 2821 | ||
| 2822 | if (end_off < in_dices[next_dice].offset) continue; | |
| 2823 | ||
| 2824 | while (next_dice < in_dices.len and | |
| 2825 | in_dices[next_dice].offset < end_off) : (next_dice += 1) | |
| 2826 | {} | |
| 2827 | ||
| 2828 | if (atom.flags.alive) for (in_dices[start_dice..next_dice]) |dice| { | |
| 2829 | dices.appendAssumeCapacity(.{ | |
| 2830 | .offset = @intCast(atom.getAddress(self) + dice.offset - start_off - base_address), | |
| 2831 | .length = dice.length, | |
| 2832 | .kind = dice.kind, | |
| 2833 | }); | |
| 2834 | }; | |
| 2835 | } | |
| 2558 | if (self.eh_frame_sect_index) |index| { | |
| 2559 | const header = self.sections.items(.header)[index]; | |
| 2560 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2561 | const buffer = try gpa.alloc(u8, size); | |
| 2562 | defer gpa.free(buffer); | |
| 2563 | eh_frame.write(self, buffer); | |
| 2564 | try self.base.file.?.pwriteAll(buffer, header.offset); | |
| 2836 | 2565 | } |
| 2837 | 2566 | |
| 2838 | const needed_size = math.cast(u32, dices.items.len * @sizeOf(macho.data_in_code_entry)) orelse return error.Overflow; | |
| 2839 | cmd.datasize = needed_size; | |
| 2840 | ||
| 2841 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(dices.items), cmd.dataoff); | |
| 2842 | ||
| 2843 | return off + needed_size; | |
| 2567 | if (self.unwind_info_sect_index) |index| { | |
| 2568 | const header = self.sections.items(.header)[index]; | |
| 2569 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2570 | const buffer = try gpa.alloc(u8, size); | |
| 2571 | defer gpa.free(buffer); | |
| 2572 | try self.unwind_info.write(self, buffer); | |
| 2573 | try self.base.file.?.pwriteAll(buffer, header.offset); | |
| 2574 | } | |
| 2844 | 2575 | } |
| 2845 | 2576 | |
| 2846 | pub fn calcSymtabSize(self: *MachO) !void { | |
| 2577 | fn calcSymtabSize(self: *MachO) !void { | |
| 2847 | 2578 | const tracy = trace(@src()); |
| 2848 | 2579 | defer tracy.end(); |
| 2849 | const gpa = self.base.comp.gpa; | |
| 2850 | 2580 | |
| 2851 | var nlocals: u32 = 0; | |
| 2852 | var nstabs: u32 = 0; | |
| 2853 | var nexports: u32 = 0; | |
| 2854 | var nimports: u32 = 0; | |
| 2855 | var strsize: u32 = 0; | |
| 2581 | const gpa = self.base.comp.gpa; | |
| 2856 | 2582 | |
| 2857 | 2583 | var files = std.ArrayList(File.Index).init(gpa); |
| 2858 | 2584 | defer files.deinit(); |
| ... | ... | @@ -2862,6 +2588,12 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2862 | 2588 | for (self.dylibs.items) |index| files.appendAssumeCapacity(index); |
| 2863 | 2589 | if (self.internal_object) |index| files.appendAssumeCapacity(index); |
| 2864 | 2590 | |
| 2591 | var nlocals: u32 = 0; | |
| 2592 | var nstabs: u32 = 0; | |
| 2593 | var nexports: u32 = 0; | |
| 2594 | var nimports: u32 = 0; | |
| 2595 | var strsize: u32 = 1; | |
| 2596 | ||
| 2865 | 2597 | for (files.items) |index| { |
| 2866 | 2598 | const file = self.getFile(index).?; |
| 2867 | 2599 | const ctx = switch (file) { |
| ... | ... | @@ -2871,7 +2603,7 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2871 | 2603 | ctx.istab = nstabs; |
| 2872 | 2604 | ctx.iexport = nexports; |
| 2873 | 2605 | ctx.iimport = nimports; |
| 2874 | try file.calcSymtabSize(self); | |
| 2606 | ctx.stroff = strsize; | |
| 2875 | 2607 | nlocals += ctx.nlocals; |
| 2876 | 2608 | nstabs += ctx.nstabs; |
| 2877 | 2609 | nexports += ctx.nexports; |
| ... | ... | @@ -2889,10 +2621,12 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2889 | 2621 | ctx.iimport += nlocals + nstabs + nexports; |
| 2890 | 2622 | } |
| 2891 | 2623 | |
| 2624 | try self.indsymtab.updateSize(self); | |
| 2625 | ||
| 2892 | 2626 | { |
| 2893 | 2627 | const cmd = &self.symtab_cmd; |
| 2894 | 2628 | cmd.nsyms = nlocals + nstabs + nexports + nimports; |
| 2895 | cmd.strsize = strsize + 1; | |
| 2629 | cmd.strsize = strsize; | |
| 2896 | 2630 | } |
| 2897 | 2631 | |
| 2898 | 2632 | { |
| ... | ... | @@ -2906,60 +2640,6 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2906 | 2640 | } |
| 2907 | 2641 | } |
| 2908 | 2642 | |
| 2909 | pub fn writeSymtab(self: *MachO, off: u32) !u32 { | |
| 2910 | const tracy = trace(@src()); | |
| 2911 | defer tracy.end(); | |
| 2912 | const gpa = self.base.comp.gpa; | |
| 2913 | const cmd = &self.symtab_cmd; | |
| 2914 | cmd.symoff = off; | |
| 2915 | ||
| 2916 | try self.symtab.resize(gpa, cmd.nsyms); | |
| 2917 | try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1); | |
| 2918 | ||
| 2919 | if (self.getZigObject()) |zo| { | |
| 2920 | zo.writeSymtab(self, self); | |
| 2921 | } | |
| 2922 | for (self.objects.items) |index| { | |
| 2923 | try self.getFile(index).?.writeSymtab(self, self); | |
| 2924 | } | |
| 2925 | for (self.dylibs.items) |index| { | |
| 2926 | try self.getFile(index).?.writeSymtab(self, self); | |
| 2927 | } | |
| 2928 | if (self.getInternalObject()) |internal| { | |
| 2929 | internal.writeSymtab(self, self); | |
| 2930 | } | |
| 2931 | ||
| 2932 | assert(self.strtab.items.len == cmd.strsize); | |
| 2933 | ||
| 2934 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); | |
| 2935 | ||
| 2936 | return off + cmd.nsyms * @sizeOf(macho.nlist_64); | |
| 2937 | } | |
| 2938 | ||
| 2939 | fn writeIndsymtab(self: *MachO, off: u32) !u32 { | |
| 2940 | const gpa = self.base.comp.gpa; | |
| 2941 | const cmd = &self.dysymtab_cmd; | |
| 2942 | cmd.indirectsymoff = off; | |
| 2943 | cmd.nindirectsyms = self.indsymtab.nsyms(self); | |
| 2944 | ||
| 2945 | const needed_size = cmd.nindirectsyms * @sizeOf(u32); | |
| 2946 | var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size); | |
| 2947 | defer buffer.deinit(); | |
| 2948 | try self.indsymtab.write(self, buffer.writer()); | |
| 2949 | ||
| 2950 | try self.base.file.?.pwriteAll(buffer.items, cmd.indirectsymoff); | |
| 2951 | assert(buffer.items.len == needed_size); | |
| 2952 | ||
| 2953 | return off + needed_size; | |
| 2954 | } | |
| 2955 | ||
| 2956 | pub fn writeStrtab(self: *MachO, off: u32) !u32 { | |
| 2957 | const cmd = &self.symtab_cmd; | |
| 2958 | cmd.stroff = off; | |
| 2959 | try self.base.file.?.pwriteAll(self.strtab.items, cmd.stroff); | |
| 2960 | return off + cmd.strsize; | |
| 2961 | } | |
| 2962 | ||
| 2963 | 2643 | fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 2964 | 2644 | const comp = self.base.comp; |
| 2965 | 2645 | const gpa = comp.gpa; |
| ... | ... | @@ -2999,18 +2679,20 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 2999 | 2679 | try load_commands.writeDylinkerLC(writer); |
| 3000 | 2680 | ncmds += 1; |
| 3001 | 2681 | |
| 3002 | if (self.entry_index) |global_index| { | |
| 3003 | const sym = self.getSymbol(global_index); | |
| 3004 | const seg = self.getTextSegment(); | |
| 3005 | const entryoff: u32 = if (sym.getFile(self) == null) | |
| 3006 | 0 | |
| 3007 | else | |
| 3008 | @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr)); | |
| 3009 | try writer.writeStruct(macho.entry_point_command{ | |
| 3010 | .entryoff = entryoff, | |
| 3011 | .stacksize = self.base.stack_size, | |
| 3012 | }); | |
| 3013 | ncmds += 1; | |
| 2682 | if (self.getInternalObject()) |obj| { | |
| 2683 | if (obj.getEntryRef(self)) |ref| { | |
| 2684 | const sym = ref.getSymbol(self).?; | |
| 2685 | const seg = self.getTextSegment(); | |
| 2686 | const entryoff: u32 = if (sym.getFile(self) == null) | |
| 2687 | 0 | |
| 2688 | else | |
| 2689 | @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr)); | |
| 2690 | try writer.writeStruct(macho.entry_point_command{ | |
| 2691 | .entryoff = entryoff, | |
| 2692 | .stacksize = self.base.stack_size, | |
| 2693 | }); | |
| 2694 | ncmds += 1; | |
| 2695 | } | |
| 3014 | 2696 | } |
| 3015 | 2697 | |
| 3016 | 2698 | if (self.base.isDynLib()) { |
| ... | ... | @@ -3919,157 +3601,6 @@ pub fn getFileHandle(self: MachO, index: File.HandleIndex) File.Handle { |
| 3919 | 3601 | return self.file_handles.items[index]; |
| 3920 | 3602 | } |
| 3921 | 3603 | |
| 3922 | pub fn addAtom(self: *MachO) error{OutOfMemory}!Atom.Index { | |
| 3923 | const index = @as(Atom.Index, @intCast(self.atoms.items.len)); | |
| 3924 | const atom = try self.atoms.addOne(self.base.comp.gpa); | |
| 3925 | atom.* = .{}; | |
| 3926 | return index; | |
| 3927 | } | |
| 3928 | ||
| 3929 | pub fn getAtom(self: *MachO, index: Atom.Index) ?*Atom { | |
| 3930 | if (index == 0) return null; | |
| 3931 | assert(index < self.atoms.items.len); | |
| 3932 | return &self.atoms.items[index]; | |
| 3933 | } | |
| 3934 | ||
| 3935 | pub fn addAtomExtra(self: *MachO, extra: Atom.Extra) !u32 { | |
| 3936 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 3937 | try self.atoms_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len); | |
| 3938 | return self.addAtomExtraAssumeCapacity(extra); | |
| 3939 | } | |
| 3940 | ||
| 3941 | pub fn addAtomExtraAssumeCapacity(self: *MachO, extra: Atom.Extra) u32 { | |
| 3942 | const index = @as(u32, @intCast(self.atoms_extra.items.len)); | |
| 3943 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 3944 | inline for (fields) |field| { | |
| 3945 | self.atoms_extra.appendAssumeCapacity(switch (field.type) { | |
| 3946 | u32 => @field(extra, field.name), | |
| 3947 | else => @compileError("bad field type"), | |
| 3948 | }); | |
| 3949 | } | |
| 3950 | return index; | |
| 3951 | } | |
| 3952 | ||
| 3953 | pub fn getAtomExtra(self: *MachO, index: u32) ?Atom.Extra { | |
| 3954 | if (index == 0) return null; | |
| 3955 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 3956 | var i: usize = index; | |
| 3957 | var result: Atom.Extra = undefined; | |
| 3958 | inline for (fields) |field| { | |
| 3959 | @field(result, field.name) = switch (field.type) { | |
| 3960 | u32 => self.atoms_extra.items[i], | |
| 3961 | else => @compileError("bad field type"), | |
| 3962 | }; | |
| 3963 | i += 1; | |
| 3964 | } | |
| 3965 | return result; | |
| 3966 | } | |
| 3967 | ||
| 3968 | pub fn setAtomExtra(self: *MachO, index: u32, extra: Atom.Extra) void { | |
| 3969 | assert(index > 0); | |
| 3970 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 3971 | inline for (fields, 0..) |field, i| { | |
| 3972 | self.atoms_extra.items[index + i] = switch (field.type) { | |
| 3973 | u32 => @field(extra, field.name), | |
| 3974 | else => @compileError("bad field type"), | |
| 3975 | }; | |
| 3976 | } | |
| 3977 | } | |
| 3978 | ||
| 3979 | pub fn addSymbol(self: *MachO) !Symbol.Index { | |
| 3980 | const index = @as(Symbol.Index, @intCast(self.symbols.items.len)); | |
| 3981 | const symbol = try self.symbols.addOne(self.base.comp.gpa); | |
| 3982 | symbol.* = .{}; | |
| 3983 | return index; | |
| 3984 | } | |
| 3985 | ||
| 3986 | pub fn getSymbol(self: *MachO, index: Symbol.Index) *Symbol { | |
| 3987 | assert(index < self.symbols.items.len); | |
| 3988 | return &self.symbols.items[index]; | |
| 3989 | } | |
| 3990 | ||
| 3991 | pub fn addSymbolExtra(self: *MachO, extra: Symbol.Extra) !u32 { | |
| 3992 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 3993 | try self.symbols_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len); | |
| 3994 | return self.addSymbolExtraAssumeCapacity(extra); | |
| 3995 | } | |
| 3996 | ||
| 3997 | pub fn addSymbolExtraAssumeCapacity(self: *MachO, extra: Symbol.Extra) u32 { | |
| 3998 | const index = @as(u32, @intCast(self.symbols_extra.items.len)); | |
| 3999 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 4000 | inline for (fields) |field| { | |
| 4001 | self.symbols_extra.appendAssumeCapacity(switch (field.type) { | |
| 4002 | u32 => @field(extra, field.name), | |
| 4003 | else => @compileError("bad field type"), | |
| 4004 | }); | |
| 4005 | } | |
| 4006 | return index; | |
| 4007 | } | |
| 4008 | ||
| 4009 | pub fn getSymbolExtra(self: MachO, index: u32) ?Symbol.Extra { | |
| 4010 | if (index == 0) return null; | |
| 4011 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 4012 | var i: usize = index; | |
| 4013 | var result: Symbol.Extra = undefined; | |
| 4014 | inline for (fields) |field| { | |
| 4015 | @field(result, field.name) = switch (field.type) { | |
| 4016 | u32 => self.symbols_extra.items[i], | |
| 4017 | else => @compileError("bad field type"), | |
| 4018 | }; | |
| 4019 | i += 1; | |
| 4020 | } | |
| 4021 | return result; | |
| 4022 | } | |
| 4023 | ||
| 4024 | pub fn setSymbolExtra(self: *MachO, index: u32, extra: Symbol.Extra) void { | |
| 4025 | assert(index > 0); | |
| 4026 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 4027 | inline for (fields, 0..) |field, i| { | |
| 4028 | self.symbols_extra.items[index + i] = switch (field.type) { | |
| 4029 | u32 => @field(extra, field.name), | |
| 4030 | else => @compileError("bad field type"), | |
| 4031 | }; | |
| 4032 | } | |
| 4033 | } | |
| 4034 | ||
| 4035 | const GetOrCreateGlobalResult = struct { | |
| 4036 | found_existing: bool, | |
| 4037 | index: Symbol.Index, | |
| 4038 | }; | |
| 4039 | ||
| 4040 | pub fn getOrCreateGlobal(self: *MachO, off: u32) !GetOrCreateGlobalResult { | |
| 4041 | const gpa = self.base.comp.gpa; | |
| 4042 | const gop = try self.globals.getOrPut(gpa, off); | |
| 4043 | if (!gop.found_existing) { | |
| 4044 | const index = try self.addSymbol(); | |
| 4045 | const global = self.getSymbol(index); | |
| 4046 | global.name = off; | |
| 4047 | global.flags.global = true; | |
| 4048 | gop.value_ptr.* = index; | |
| 4049 | } | |
| 4050 | return .{ | |
| 4051 | .found_existing = gop.found_existing, | |
| 4052 | .index = gop.value_ptr.*, | |
| 4053 | }; | |
| 4054 | } | |
| 4055 | ||
| 4056 | pub fn getGlobalByName(self: *MachO, name: []const u8) ?Symbol.Index { | |
| 4057 | const off = self.strings.getOffset(name) orelse return null; | |
| 4058 | return self.globals.get(off); | |
| 4059 | } | |
| 4060 | ||
| 4061 | pub fn addUnwindRecord(self: *MachO) !UnwindInfo.Record.Index { | |
| 4062 | const index = @as(UnwindInfo.Record.Index, @intCast(self.unwind_records.items.len)); | |
| 4063 | const rec = try self.unwind_records.addOne(self.base.comp.gpa); | |
| 4064 | rec.* = .{}; | |
| 4065 | return index; | |
| 4066 | } | |
| 4067 | ||
| 4068 | pub fn getUnwindRecord(self: *MachO, index: UnwindInfo.Record.Index) *UnwindInfo.Record { | |
| 4069 | assert(index < self.unwind_records.items.len); | |
| 4070 | return &self.unwind_records.items[index]; | |
| 4071 | } | |
| 4072 | ||
| 4073 | 3604 | pub fn addThunk(self: *MachO) !Thunk.Index { |
| 4074 | 3605 | const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); |
| 4075 | 3606 | const thunk = try self.thunks.addOne(self.base.comp.gpa); |
| ... | ... | @@ -4208,22 +3739,23 @@ pub fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: an |
| 4208 | 3739 | try err.addNote(self, "please report this as a linker bug on https://github.com/ziglang/zig/issues/new/choose", .{}); |
| 4209 | 3740 | } |
| 4210 | 3741 | |
| 4211 | fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void { | |
| 3742 | fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void { | |
| 4212 | 3743 | const tracy = trace(@src()); |
| 4213 | 3744 | defer tracy.end(); |
| 4214 | 3745 | |
| 4215 | 3746 | const max_notes = 3; |
| 4216 | 3747 | |
| 4217 | 3748 | var has_dupes = false; |
| 4218 | var it = dupes.iterator(); | |
| 3749 | var it = self.dupes.iterator(); | |
| 4219 | 3750 | while (it.next()) |entry| { |
| 4220 | const sym = self.getSymbol(entry.key_ptr.*); | |
| 3751 | const sym = self.resolver.keys.items[entry.key_ptr.* - 1]; | |
| 4221 | 3752 | const notes = entry.value_ptr.*; |
| 4222 | 3753 | const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); |
| 4223 | 3754 | |
| 4224 | 3755 | var err = try self.addErrorWithNotes(nnotes + 1); |
| 4225 | 3756 | try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.getName(self)}); |
| 4226 | 3757 | try err.addNote(self, "defined by {}", .{sym.getFile(self).?.fmtPath()}); |
| 3758 | has_dupes = true; | |
| 4227 | 3759 | |
| 4228 | 3760 | var inote: usize = 0; |
| 4229 | 3761 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { |
| ... | ... | @@ -4235,10 +3767,7 @@ fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMem |
| 4235 | 3767 | const remaining = notes.items.len - max_notes; |
| 4236 | 3768 | try err.addNote(self, "defined {d} more times", .{remaining}); |
| 4237 | 3769 | } |
| 4238 | ||
| 4239 | has_dupes = true; | |
| 4240 | 3770 | } |
| 4241 | ||
| 4242 | 3771 | if (has_dupes) return error.HasDuplicates; |
| 4243 | 3772 | } |
| 4244 | 3773 | |
| ... | ... | @@ -4435,15 +3964,18 @@ pub const base_tag: link.File.Tag = link.File.Tag.macho; |
| 4435 | 3964 | const Section = struct { |
| 4436 | 3965 | header: macho.section_64, |
| 4437 | 3966 | segment_id: u8, |
| 4438 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 3967 | atoms: std.ArrayListUnmanaged(Ref) = .{}, | |
| 4439 | 3968 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 4440 | 3969 | last_atom_index: Atom.Index = 0, |
| 3970 | thunks: std.ArrayListUnmanaged(Thunk.Index) = .{}, | |
| 3971 | out: std.ArrayListUnmanaged(u8) = .{}, | |
| 3972 | relocs: std.ArrayListUnmanaged(macho.relocation_info) = .{}, | |
| 4441 | 3973 | }; |
| 4442 | 3974 | |
| 4443 | 3975 | pub const LiteralPool = struct { |
| 4444 | 3976 | table: std.AutoArrayHashMapUnmanaged(void, void) = .{}, |
| 4445 | 3977 | keys: std.ArrayListUnmanaged(Key) = .{}, |
| 4446 | values: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 3978 | values: std.ArrayListUnmanaged(MachO.Ref) = .{}, | |
| 4447 | 3979 | data: std.ArrayListUnmanaged(u8) = .{}, |
| 4448 | 3980 | |
| 4449 | 3981 | pub fn deinit(lp: *LiteralPool, allocator: Allocator) void { |
| ... | ... | @@ -4453,17 +3985,21 @@ pub const LiteralPool = struct { |
| 4453 | 3985 | lp.data.deinit(allocator); |
| 4454 | 3986 | } |
| 4455 | 3987 | |
| 4456 | pub fn getAtom(lp: LiteralPool, index: Index, macho_file: *MachO) *Atom { | |
| 4457 | assert(index < lp.values.items.len); | |
| 4458 | return macho_file.getAtom(lp.values.items[index]).?; | |
| 4459 | } | |
| 4460 | ||
| 4461 | 3988 | const InsertResult = struct { |
| 4462 | 3989 | found_existing: bool, |
| 4463 | 3990 | index: Index, |
| 4464 | atom: *Atom.Index, | |
| 3991 | ref: *MachO.Ref, | |
| 4465 | 3992 | }; |
| 4466 | 3993 | |
| 3994 | pub fn getSymbolRef(lp: LiteralPool, index: Index) MachO.Ref { | |
| 3995 | assert(index < lp.values.items.len); | |
| 3996 | return lp.values.items[index]; | |
| 3997 | } | |
| 3998 | ||
| 3999 | pub fn getSymbol(lp: LiteralPool, index: Index, macho_file: *MachO) *Symbol { | |
| 4000 | return lp.getSymbolRef(index).getSymbol(macho_file).?; | |
| 4001 | } | |
| 4002 | ||
| 4467 | 4003 | pub fn insert(lp: *LiteralPool, allocator: Allocator, @"type": u8, string: []const u8) !InsertResult { |
| 4468 | 4004 | const size: u32 = @intCast(string.len); |
| 4469 | 4005 | try lp.data.ensureUnusedCapacity(allocator, size); |
| ... | ... | @@ -4479,7 +4015,7 @@ pub const LiteralPool = struct { |
| 4479 | 4015 | return .{ |
| 4480 | 4016 | .found_existing = gop.found_existing, |
| 4481 | 4017 | .index = @intCast(gop.index), |
| 4482 | .atom = &lp.values.items[gop.index], | |
| 4018 | .ref = &lp.values.items[gop.index], | |
| 4483 | 4019 | }; |
| 4484 | 4020 | } |
| 4485 | 4021 | |
| ... | ... | @@ -4525,12 +4061,6 @@ const HotUpdateState = struct { |
| 4525 | 4061 | mach_task: ?std.c.MachTask = null, |
| 4526 | 4062 | }; |
| 4527 | 4063 | |
| 4528 | pub const DynamicRelocs = struct { | |
| 4529 | rebase_relocs: u32 = 0, | |
| 4530 | bind_relocs: u32 = 0, | |
| 4531 | weak_bind_relocs: u32 = 0, | |
| 4532 | }; | |
| 4533 | ||
| 4534 | 4064 | pub const SymtabCtx = struct { |
| 4535 | 4065 | ilocal: u32 = 0, |
| 4536 | 4066 | istab: u32 = 0, |
| ... | ... | @@ -4540,6 +4070,7 @@ pub const SymtabCtx = struct { |
| 4540 | 4070 | nstabs: u32 = 0, |
| 4541 | 4071 | nexports: u32 = 0, |
| 4542 | 4072 | nimports: u32 = 0, |
| 4073 | stroff: u32 = 0, | |
| 4543 | 4074 | strsize: u32 = 0, |
| 4544 | 4075 | }; |
| 4545 | 4076 | |
| ... | ... | @@ -4826,6 +4357,136 @@ const UndefinedTreatment = enum { |
| 4826 | 4357 | dynamic_lookup, |
| 4827 | 4358 | }; |
| 4828 | 4359 | |
| 4360 | /// A reference to atom or symbol in an input file. | |
| 4361 | /// If file == 0, symbol is an undefined global. | |
| 4362 | pub const Ref = struct { | |
| 4363 | index: u32, | |
| 4364 | file: File.Index, | |
| 4365 | ||
| 4366 | pub fn eql(ref: Ref, other: Ref) bool { | |
| 4367 | return ref.index == other.index and ref.file == other.file; | |
| 4368 | } | |
| 4369 | ||
| 4370 | pub fn getFile(ref: Ref, macho_file: *MachO) ?File { | |
| 4371 | return macho_file.getFile(ref.file); | |
| 4372 | } | |
| 4373 | ||
| 4374 | pub fn getAtom(ref: Ref, macho_file: *MachO) ?*Atom { | |
| 4375 | const file = ref.getFile(macho_file) orelse return null; | |
| 4376 | return file.getAtom(ref.index); | |
| 4377 | } | |
| 4378 | ||
| 4379 | pub fn getSymbol(ref: Ref, macho_file: *MachO) ?*Symbol { | |
| 4380 | const file = ref.getFile(macho_file) orelse return null; | |
| 4381 | return switch (file) { | |
| 4382 | inline else => |x| &x.symbols.items[ref.index], | |
| 4383 | }; | |
| 4384 | } | |
| 4385 | ||
| 4386 | pub fn format( | |
| 4387 | ref: Ref, | |
| 4388 | comptime unused_fmt_string: []const u8, | |
| 4389 | options: std.fmt.FormatOptions, | |
| 4390 | writer: anytype, | |
| 4391 | ) !void { | |
| 4392 | _ = unused_fmt_string; | |
| 4393 | _ = options; | |
| 4394 | try writer.print("%{d} in file({d})", .{ ref.index, ref.file }); | |
| 4395 | } | |
| 4396 | }; | |
| 4397 | ||
| 4398 | pub const SymbolResolver = struct { | |
| 4399 | keys: std.ArrayListUnmanaged(Key) = .{}, | |
| 4400 | values: std.ArrayListUnmanaged(Ref) = .{}, | |
| 4401 | table: std.AutoArrayHashMapUnmanaged(void, void) = .{}, | |
| 4402 | ||
| 4403 | const Result = struct { | |
| 4404 | found_existing: bool, | |
| 4405 | index: Index, | |
| 4406 | ref: *Ref, | |
| 4407 | }; | |
| 4408 | ||
| 4409 | pub fn deinit(resolver: *SymbolResolver, allocator: Allocator) void { | |
| 4410 | resolver.keys.deinit(allocator); | |
| 4411 | resolver.values.deinit(allocator); | |
| 4412 | resolver.table.deinit(allocator); | |
| 4413 | } | |
| 4414 | ||
| 4415 | pub fn getOrPut( | |
| 4416 | resolver: *SymbolResolver, | |
| 4417 | allocator: Allocator, | |
| 4418 | ref: Ref, | |
| 4419 | macho_file: *MachO, | |
| 4420 | ) !Result { | |
| 4421 | const adapter = Adapter{ .keys = resolver.keys.items, .macho_file = macho_file }; | |
| 4422 | const key = Key{ .index = ref.index, .file = ref.file }; | |
| 4423 | const gop = try resolver.table.getOrPutAdapted(allocator, key, adapter); | |
| 4424 | if (!gop.found_existing) { | |
| 4425 | try resolver.keys.append(allocator, key); | |
| 4426 | _ = try resolver.values.addOne(allocator); | |
| 4427 | } | |
| 4428 | return .{ | |
| 4429 | .found_existing = gop.found_existing, | |
| 4430 | .index = @intCast(gop.index + 1), | |
| 4431 | .ref = &resolver.values.items[gop.index], | |
| 4432 | }; | |
| 4433 | } | |
| 4434 | ||
| 4435 | pub fn get(resolver: SymbolResolver, index: Index) ?Ref { | |
| 4436 | if (index == 0) return null; | |
| 4437 | return resolver.values.items[index - 1]; | |
| 4438 | } | |
| 4439 | ||
| 4440 | pub fn reset(resolver: *SymbolResolver) void { | |
| 4441 | resolver.keys.clearRetainingCapacity(); | |
| 4442 | resolver.values.clearRetainingCapacity(); | |
| 4443 | resolver.table.clearRetainingCapacity(); | |
| 4444 | } | |
| 4445 | ||
| 4446 | const Key = struct { | |
| 4447 | index: Symbol.Index, | |
| 4448 | file: File.Index, | |
| 4449 | ||
| 4450 | fn getName(key: Key, macho_file: *MachO) [:0]const u8 { | |
| 4451 | const ref = Ref{ .index = key.index, .file = key.file }; | |
| 4452 | return ref.getSymbol(macho_file).?.getName(macho_file); | |
| 4453 | } | |
| 4454 | ||
| 4455 | pub fn getFile(key: Key, macho_file: *MachO) ?File { | |
| 4456 | const ref = Ref{ .index = key.index, .file = key.file }; | |
| 4457 | return ref.getFile(macho_file); | |
| 4458 | } | |
| 4459 | ||
| 4460 | fn eql(key: Key, other: Key, macho_file: *MachO) bool { | |
| 4461 | const key_name = key.getName(macho_file); | |
| 4462 | const other_name = other.getName(macho_file); | |
| 4463 | return mem.eql(u8, key_name, other_name); | |
| 4464 | } | |
| 4465 | ||
| 4466 | fn hash(key: Key, macho_file: *MachO) u32 { | |
| 4467 | const name = key.getName(macho_file); | |
| 4468 | return @truncate(Hash.hash(0, name)); | |
| 4469 | } | |
| 4470 | }; | |
| 4471 | ||
| 4472 | const Adapter = struct { | |
| 4473 | keys: []const Key, | |
| 4474 | macho_file: *MachO, | |
| 4475 | ||
| 4476 | pub fn eql(ctx: @This(), key: Key, b_void: void, b_map_index: usize) bool { | |
| 4477 | _ = b_void; | |
| 4478 | const other = ctx.keys[b_map_index]; | |
| 4479 | return key.eql(other, ctx.macho_file); | |
| 4480 | } | |
| 4481 | ||
| 4482 | pub fn hash(ctx: @This(), key: Key) u32 { | |
| 4483 | return key.hash(ctx.macho_file); | |
| 4484 | } | |
| 4485 | }; | |
| 4486 | ||
| 4487 | pub const Index = u32; | |
| 4488 | }; | |
| 4489 | ||
| 4829 | 4490 | const MachO = @This(); |
| 4830 | 4491 | |
| 4831 | 4492 | const std = @import("std"); |
| ... | ... | @@ -4842,6 +4503,7 @@ const mem = std.mem; |
| 4842 | 4503 | const meta = std.meta; |
| 4843 | 4504 | |
| 4844 | 4505 | const aarch64 = @import("../arch/aarch64/bits.zig"); |
| 4506 | const bind = @import("MachO/dyld_info/bind.zig"); | |
| 4845 | 4507 | const calcUuid = @import("MachO/uuid.zig").calcUuid; |
| 4846 | 4508 | const codegen = @import("../codegen.zig"); |
| 4847 | 4509 | const dead_strip = @import("MachO/dead_strip.zig"); |
| ... | ... | @@ -4862,13 +4524,14 @@ const Alignment = Atom.Alignment; |
| 4862 | 4524 | const Allocator = mem.Allocator; |
| 4863 | 4525 | const Archive = @import("MachO/Archive.zig"); |
| 4864 | 4526 | pub const Atom = @import("MachO/Atom.zig"); |
| 4865 | const BindSection = synthetic.BindSection; | |
| 4527 | const Bind = bind.Bind; | |
| 4866 | 4528 | const Cache = std.Build.Cache; |
| 4867 | 4529 | const CodeSignature = @import("MachO/CodeSignature.zig"); |
| 4868 | 4530 | const Compilation = @import("../Compilation.zig"); |
| 4531 | const DataInCode = synthetic.DataInCode; | |
| 4869 | 4532 | pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 4870 | 4533 | const Dylib = @import("MachO/Dylib.zig"); |
| 4871 | const ExportTrieSection = synthetic.ExportTrieSection; | |
| 4534 | const ExportTrie = @import("MachO/dyld_info/Trie.zig"); | |
| 4872 | 4535 | const File = @import("MachO/file.zig").File; |
| 4873 | 4536 | const GotSection = synthetic.GotSection; |
| 4874 | 4537 | const Hash = std.hash.Wyhash; |
| ... | ... | @@ -4876,7 +4539,7 @@ const Indsymtab = synthetic.Indsymtab; |
| 4876 | 4539 | const InternalObject = @import("MachO/InternalObject.zig"); |
| 4877 | 4540 | const ObjcStubsSection = synthetic.ObjcStubsSection; |
| 4878 | 4541 | const Object = @import("MachO/Object.zig"); |
| 4879 | const LazyBindSection = synthetic.LazyBindSection; | |
| 4542 | const LazyBind = bind.LazyBind; | |
| 4880 | 4543 | const LaSymbolPtrSection = synthetic.LaSymbolPtrSection; |
| 4881 | 4544 | const LibStub = tapi.LibStub; |
| 4882 | 4545 | const Liveness = @import("../Liveness.zig"); |
| ... | ... | @@ -4886,7 +4549,7 @@ const Zcu = @import("../Zcu.zig"); |
| 4886 | 4549 | /// Deprecated. |
| 4887 | 4550 | const Module = Zcu; |
| 4888 | 4551 | const InternPool = @import("../InternPool.zig"); |
| 4889 | const RebaseSection = synthetic.RebaseSection; | |
| 4552 | const Rebase = @import("MachO/dyld_info/Rebase.zig"); | |
| 4890 | 4553 | pub const Relocation = @import("MachO/Relocation.zig"); |
| 4891 | 4554 | const StringTable = @import("StringTable.zig"); |
| 4892 | 4555 | const StubsSection = synthetic.StubsSection; |
| ... | ... | @@ -4896,6 +4559,6 @@ const Thunk = thunks.Thunk; |
| 4896 | 4559 | const TlvPtrSection = synthetic.TlvPtrSection; |
| 4897 | 4560 | const Value = @import("../Value.zig"); |
| 4898 | 4561 | const UnwindInfo = @import("MachO/UnwindInfo.zig"); |
| 4899 | const WeakBindSection = synthetic.WeakBindSection; | |
| 4562 | const WeakBind = bind.WeakBind; | |
| 4900 | 4563 | const ZigGotSection = synthetic.ZigGotSection; |
| 4901 | 4564 | const ZigObject = @import("MachO/ZigObject.zig"); |
src/link/MachO/Archive.zig+2-2| ... | ... | @@ -67,9 +67,9 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: |
| 67 | 67 | mem.eql(u8, name, SYMDEF64_SORTED)) continue; |
| 68 | 68 | |
| 69 | 69 | const object = Object{ |
| 70 | .archive = .{ | |
| 70 | .offset = pos, | |
| 71 | .in_archive = .{ | |
| 71 | 72 | .path = try gpa.dupe(u8, path), |
| 72 | .offset = pos, | |
| 73 | 73 | .size = hdr_size, |
| 74 | 74 | }, |
| 75 | 75 | .path = try gpa.dupe(u8, name), |
src/link/MachO/Atom.zig+116-156| ... | ... | @@ -47,16 +47,6 @@ pub fn getFile(self: Atom, macho_file: *MachO) File { |
| 47 | 47 | return macho_file.getFile(self.file).?; |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | pub fn getData(self: Atom, macho_file: *MachO, buffer: []u8) !void { | |
| 51 | assert(buffer.len == self.size); | |
| 52 | switch (self.getFile(macho_file)) { | |
| 53 | .internal => |x| try x.getAtomData(self, buffer), | |
| 54 | .object => |x| try x.getAtomData(macho_file, self, buffer), | |
| 55 | .zig_object => |x| try x.getAtomData(macho_file, self, buffer), | |
| 56 | else => unreachable, | |
| 57 | } | |
| 58 | } | |
| 59 | ||
| 60 | 50 | pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation { |
| 61 | 51 | return switch (self.getFile(macho_file)) { |
| 62 | 52 | .dylib => unreachable, |
| ... | ... | @@ -88,17 +78,18 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 { |
| 88 | 78 | } |
| 89 | 79 | |
| 90 | 80 | pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index { |
| 91 | if (!self.flags.unwind) return &[0]UnwindInfo.Record.Index{}; | |
| 92 | const extra = self.getExtra(macho_file).?; | |
| 81 | const extra = self.getExtra(macho_file); | |
| 93 | 82 | return switch (self.getFile(macho_file)) { |
| 94 | .dylib, .zig_object, .internal => unreachable, | |
| 95 | .object => |x| x.unwind_records.items[extra.unwind_index..][0..extra.unwind_count], | |
| 83 | .dylib => unreachable, | |
| 84 | .zig_object, .internal => &[0]UnwindInfo.Record.Index{}, | |
| 85 | .object => |x| x.unwind_records_indexes.items[extra.unwind_index..][0..extra.unwind_count], | |
| 96 | 86 | }; |
| 97 | 87 | } |
| 98 | 88 | |
| 99 | 89 | pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { |
| 90 | const object = self.getFile(macho_file).object; | |
| 100 | 91 | for (self.getUnwindRecords(macho_file)) |cu_index| { |
| 101 | const cu = macho_file.getUnwindRecord(cu_index); | |
| 92 | const cu = object.getUnwindRecord(cu_index); | |
| 102 | 93 | cu.alive = false; |
| 103 | 94 | |
| 104 | 95 | if (cu.getFdePtr(macho_file)) |fde| { |
| ... | ... | @@ -108,44 +99,39 @@ pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { |
| 108 | 99 | } |
| 109 | 100 | |
| 110 | 101 | pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { |
| 111 | assert(self.flags.thunk); | |
| 112 | const extra = self.getExtra(macho_file).?; | |
| 102 | const extra = self.getExtra(macho_file); | |
| 113 | 103 | return macho_file.getThunk(extra.thunk); |
| 114 | 104 | } |
| 115 | 105 | |
| 116 | pub fn getLiteralPoolIndex(self: Atom, macho_file: *MachO) ?MachO.LiteralPool.Index { | |
| 117 | if (!self.flags.literal_pool) return null; | |
| 118 | return self.getExtra(macho_file).?.literal_index; | |
| 119 | } | |
| 120 | ||
| 121 | 106 | const AddExtraOpts = struct { |
| 122 | 107 | thunk: ?u32 = null, |
| 123 | 108 | rel_index: ?u32 = null, |
| 124 | 109 | rel_count: ?u32 = null, |
| 110 | rel_out_index: ?u32 = null, | |
| 111 | rel_out_count: ?u32 = null, | |
| 125 | 112 | unwind_index: ?u32 = null, |
| 126 | 113 | unwind_count: ?u32 = null, |
| 127 | literal_index: ?u32 = null, | |
| 114 | literal_pool_index: ?u32 = null, | |
| 115 | literal_symbol_index: ?u32 = null, | |
| 128 | 116 | }; |
| 129 | 117 | |
| 130 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) !void { | |
| 131 | if (atom.getExtra(macho_file) == null) { | |
| 132 | atom.extra = try macho_file.addAtomExtra(.{}); | |
| 133 | } | |
| 134 | var extra = atom.getExtra(macho_file).?; | |
| 118 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) void { | |
| 119 | const file = atom.getFile(macho_file); | |
| 120 | var extra = file.getAtomExtra(atom.extra); | |
| 135 | 121 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { |
| 136 | 122 | if (@field(opts, field.name)) |x| { |
| 137 | 123 | @field(extra, field.name) = x; |
| 138 | 124 | } |
| 139 | 125 | } |
| 140 | atom.setExtra(extra, macho_file); | |
| 126 | file.setAtomExtra(atom.extra, extra); | |
| 141 | 127 | } |
| 142 | 128 | |
| 143 | pub inline fn getExtra(atom: Atom, macho_file: *MachO) ?Extra { | |
| 144 | return macho_file.getAtomExtra(atom.extra); | |
| 129 | pub inline fn getExtra(atom: Atom, macho_file: *MachO) Extra { | |
| 130 | return atom.getFile(macho_file).getAtomExtra(atom.extra); | |
| 145 | 131 | } |
| 146 | 132 | |
| 147 | 133 | pub inline fn setExtra(atom: Atom, extra: Extra, macho_file: *MachO) void { |
| 148 | macho_file.setAtomExtra(atom.extra, extra); | |
| 134 | atom.getFile(macho_file).setAtomExtra(atom.extra, extra); | |
| 149 | 135 | } |
| 150 | 136 | |
| 151 | 137 | pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| ... | ... | @@ -227,7 +213,8 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| 227 | 213 | /// File offset relocation happens transparently, so it is not included in |
| 228 | 214 | /// this calculation. |
| 229 | 215 | pub fn capacity(self: Atom, macho_file: *MachO) u64 { |
| 230 | const next_addr = if (macho_file.getAtom(self.next_index)) |next| | |
| 216 | const zo = macho_file.getZigObject().?; | |
| 217 | const next_addr = if (zo.getAtom(self.next_index)) |next| | |
| 231 | 218 | next.getAddress(macho_file) |
| 232 | 219 | else |
| 233 | 220 | std.math.maxInt(u32); |
| ... | ... | @@ -236,7 +223,8 @@ pub fn capacity(self: Atom, macho_file: *MachO) u64 { |
| 236 | 223 | |
| 237 | 224 | pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { |
| 238 | 225 | // No need to keep a free list node for the last block. |
| 239 | const next = macho_file.getAtom(self.next_index) orelse return false; | |
| 226 | const zo = macho_file.getZigObject().?; | |
| 227 | const next = zo.getAtom(self.next_index) orelse return false; | |
| 240 | 228 | const cap = next.getAddress(macho_file) - self.getAddress(macho_file); |
| 241 | 229 | const ideal_cap = MachO.padToIdeal(self.size); |
| 242 | 230 | if (cap <= ideal_cap) return false; |
| ... | ... | @@ -245,6 +233,7 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { |
| 245 | 233 | } |
| 246 | 234 | |
| 247 | 235 | pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 236 | const zo = macho_file.getZigObject().?; | |
| 248 | 237 | const sect = &macho_file.sections.items(.header)[self.out_n_sect]; |
| 249 | 238 | const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect]; |
| 250 | 239 | const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect]; |
| ... | ... | @@ -264,7 +253,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 264 | 253 | var i: usize = free_list.items.len; |
| 265 | 254 | while (i < free_list.items.len) { |
| 266 | 255 | const big_atom_index = free_list.items[i]; |
| 267 | const big_atom = macho_file.getAtom(big_atom_index).?; | |
| 256 | const big_atom = zo.getAtom(big_atom_index).?; | |
| 268 | 257 | // We now have a pointer to a live atom that has too much capacity. |
| 269 | 258 | // Is it enough that we could fit this new atom? |
| 270 | 259 | const cap = big_atom.capacity(macho_file); |
| ... | ... | @@ -296,7 +285,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 296 | 285 | free_list_removal = i; |
| 297 | 286 | } |
| 298 | 287 | break :blk new_start_vaddr; |
| 299 | } else if (macho_file.getAtom(last_atom_index.*)) |last| { | |
| 288 | } else if (zo.getAtom(last_atom_index.*)) |last| { | |
| 300 | 289 | const ideal_capacity = MachO.padToIdeal(last.size); |
| 301 | 290 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; |
| 302 | 291 | const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); |
| ... | ... | @@ -316,7 +305,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 316 | 305 | }); |
| 317 | 306 | |
| 318 | 307 | const expand_section = if (atom_placement) |placement_index| |
| 319 | macho_file.getAtom(placement_index).?.next_index == 0 | |
| 308 | zo.getAtom(placement_index).?.next_index == 0 | |
| 320 | 309 | else |
| 321 | 310 | true; |
| 322 | 311 | if (expand_section) { |
| ... | ... | @@ -341,15 +330,15 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 341 | 330 | // This function can also reallocate an atom. |
| 342 | 331 | // In this case we need to "unplug" it from its previous location before |
| 343 | 332 | // plugging it in to its new location. |
| 344 | if (macho_file.getAtom(self.prev_index)) |prev| { | |
| 333 | if (zo.getAtom(self.prev_index)) |prev| { | |
| 345 | 334 | prev.next_index = self.next_index; |
| 346 | 335 | } |
| 347 | if (macho_file.getAtom(self.next_index)) |next| { | |
| 336 | if (zo.getAtom(self.next_index)) |next| { | |
| 348 | 337 | next.prev_index = self.prev_index; |
| 349 | 338 | } |
| 350 | 339 | |
| 351 | 340 | if (atom_placement) |big_atom_index| { |
| 352 | const big_atom = macho_file.getAtom(big_atom_index).?; | |
| 341 | const big_atom = zo.getAtom(big_atom_index).?; | |
| 353 | 342 | self.prev_index = big_atom_index; |
| 354 | 343 | self.next_index = big_atom.next_index; |
| 355 | 344 | big_atom.next_index = self.atom_index; |
| ... | ... | @@ -379,6 +368,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void { |
| 379 | 368 | |
| 380 | 369 | const comp = macho_file.base.comp; |
| 381 | 370 | const gpa = comp.gpa; |
| 371 | const zo = macho_file.getZigObject().?; | |
| 382 | 372 | const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect]; |
| 383 | 373 | const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect]; |
| 384 | 374 | var already_have_free_list_node = false; |
| ... | ... | @@ -397,9 +387,9 @@ pub fn free(self: *Atom, macho_file: *MachO) void { |
| 397 | 387 | } |
| 398 | 388 | } |
| 399 | 389 | |
| 400 | if (macho_file.getAtom(last_atom_index.*)) |last_atom| { | |
| 390 | if (zo.getAtom(last_atom_index.*)) |last_atom| { | |
| 401 | 391 | if (last_atom.atom_index == self.atom_index) { |
| 402 | if (macho_file.getAtom(self.prev_index)) |_| { | |
| 392 | if (zo.getAtom(self.prev_index)) |_| { | |
| 403 | 393 | // TODO shrink the section size here |
| 404 | 394 | last_atom_index.* = self.prev_index; |
| 405 | 395 | } else { |
| ... | ... | @@ -408,7 +398,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void { |
| 408 | 398 | } |
| 409 | 399 | } |
| 410 | 400 | |
| 411 | if (macho_file.getAtom(self.prev_index)) |prev| { | |
| 401 | if (zo.getAtom(self.prev_index)) |prev| { | |
| 412 | 402 | prev.next_index = self.next_index; |
| 413 | 403 | if (!already_have_free_list_node and prev.*.freeListEligible(macho_file)) { |
| 414 | 404 | // The free list is heuristics, it doesn't have to be perfect, so we can |
| ... | ... | @@ -419,7 +409,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void { |
| 419 | 409 | self.prev_index = 0; |
| 420 | 410 | } |
| 421 | 411 | |
| 422 | if (macho_file.getAtom(self.next_index)) |next| { | |
| 412 | if (zo.getAtom(self.next_index)) |next| { | |
| 423 | 413 | next.prev_index = self.prev_index; |
| 424 | 414 | } else { |
| 425 | 415 | self.next_index = 0; |
| ... | ... | @@ -437,8 +427,7 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void { |
| 437 | 427 | const gpa = macho_file.base.comp.gpa; |
| 438 | 428 | const file = self.getFile(macho_file); |
| 439 | 429 | assert(file == .zig_object); |
| 440 | assert(self.flags.relocs); | |
| 441 | var extra = self.getExtra(macho_file).?; | |
| 430 | var extra = self.getExtra(macho_file); | |
| 442 | 431 | const rels = &file.zig_object.relocs.items[extra.rel_index]; |
| 443 | 432 | try rels.append(gpa, reloc); |
| 444 | 433 | extra.rel_count += 1; |
| ... | ... | @@ -446,9 +435,8 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void { |
| 446 | 435 | } |
| 447 | 436 | |
| 448 | 437 | pub fn freeRelocs(self: *Atom, macho_file: *MachO) void { |
| 449 | if (!self.flags.relocs) return; | |
| 450 | 438 | self.getFile(macho_file).zig_object.freeAtomRelocs(self.*, macho_file); |
| 451 | var extra = self.getExtra(macho_file).?; | |
| 439 | var extra = self.getExtra(macho_file); | |
| 452 | 440 | extra.rel_count = 0; |
| 453 | 441 | self.setExtra(extra, macho_file); |
| 454 | 442 | } |
| ... | ... | @@ -458,11 +446,6 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 458 | 446 | defer tracy.end(); |
| 459 | 447 | assert(self.flags.alive); |
| 460 | 448 | |
| 461 | const dynrel_ctx = switch (self.getFile(macho_file)) { | |
| 462 | .zig_object => |x| &x.dynamic_relocs, | |
| 463 | .object => |x| &x.dynamic_relocs, | |
| 464 | else => unreachable, | |
| 465 | }; | |
| 466 | 449 | const relocs = self.getRelocs(macho_file); |
| 467 | 450 | |
| 468 | 451 | for (relocs) |rel| { |
| ... | ... | @@ -470,7 +453,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 470 | 453 | |
| 471 | 454 | switch (rel.type) { |
| 472 | 455 | .branch => { |
| 473 | const symbol = rel.getTargetSymbol(macho_file); | |
| 456 | const symbol = rel.getTargetSymbol(self, macho_file); | |
| 474 | 457 | if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) { |
| 475 | 458 | symbol.flags.stubs = true; |
| 476 | 459 | if (symbol.flags.weak) { |
| ... | ... | @@ -485,7 +468,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 485 | 468 | .got_load_page, |
| 486 | 469 | .got_load_pageoff, |
| 487 | 470 | => { |
| 488 | const symbol = rel.getTargetSymbol(macho_file); | |
| 471 | const symbol = rel.getTargetSymbol(self, macho_file); | |
| 489 | 472 | if (symbol.flags.import or |
| 490 | 473 | (symbol.flags.@"export" and symbol.flags.weak) or |
| 491 | 474 | symbol.flags.interposable or |
| ... | ... | @@ -499,18 +482,18 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 499 | 482 | }, |
| 500 | 483 | |
| 501 | 484 | .zig_got_load => { |
| 502 | assert(rel.getTargetSymbol(macho_file).flags.has_zig_got); | |
| 485 | assert(rel.getTargetSymbol(self, macho_file).flags.has_zig_got); | |
| 503 | 486 | }, |
| 504 | 487 | |
| 505 | 488 | .got => { |
| 506 | rel.getTargetSymbol(macho_file).flags.needs_got = true; | |
| 489 | rel.getTargetSymbol(self, macho_file).flags.needs_got = true; | |
| 507 | 490 | }, |
| 508 | 491 | |
| 509 | 492 | .tlv, |
| 510 | 493 | .tlvp_page, |
| 511 | 494 | .tlvp_pageoff, |
| 512 | 495 | => { |
| 513 | const symbol = rel.getTargetSymbol(macho_file); | |
| 496 | const symbol = rel.getTargetSymbol(self, macho_file); | |
| 514 | 497 | if (!symbol.flags.tlv) { |
| 515 | 498 | try macho_file.reportParseError2( |
| 516 | 499 | self.getFile(macho_file).getIndex(), |
| ... | ... | @@ -529,27 +512,21 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 529 | 512 | .unsigned => { |
| 530 | 513 | if (rel.meta.length == 3) { // TODO this really should check if this is pointer width |
| 531 | 514 | if (rel.tag == .@"extern") { |
| 532 | const symbol = rel.getTargetSymbol(macho_file); | |
| 515 | const symbol = rel.getTargetSymbol(self, macho_file); | |
| 533 | 516 | if (symbol.isTlvInit(macho_file)) { |
| 534 | 517 | macho_file.has_tlv = true; |
| 535 | 518 | continue; |
| 536 | 519 | } |
| 537 | 520 | if (symbol.flags.import) { |
| 538 | dynrel_ctx.bind_relocs += 1; | |
| 539 | 521 | if (symbol.flags.weak) { |
| 540 | dynrel_ctx.weak_bind_relocs += 1; | |
| 541 | 522 | macho_file.binds_to_weak = true; |
| 542 | 523 | } |
| 543 | 524 | continue; |
| 544 | 525 | } |
| 545 | 526 | if (symbol.flags.@"export" and symbol.flags.weak) { |
| 546 | dynrel_ctx.weak_bind_relocs += 1; | |
| 547 | 527 | macho_file.binds_to_weak = true; |
| 548 | } else if (symbol.flags.interposable) { | |
| 549 | dynrel_ctx.bind_relocs += 1; | |
| 550 | 528 | } |
| 551 | 529 | } |
| 552 | dynrel_ctx.rebase_relocs += 1; | |
| 553 | 530 | } |
| 554 | 531 | }, |
| 555 | 532 | |
| ... | ... | @@ -568,14 +545,15 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 568 | 545 | fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool { |
| 569 | 546 | if (rel.tag == .local) return false; |
| 570 | 547 | |
| 571 | const sym = rel.getTargetSymbol(macho_file); | |
| 572 | if (sym.getFile(macho_file) == null) { | |
| 548 | const file = self.getFile(macho_file); | |
| 549 | const ref = file.getSymbolRef(rel.target, macho_file); | |
| 550 | if (ref.getFile(macho_file) == null) { | |
| 573 | 551 | const gpa = macho_file.base.comp.gpa; |
| 574 | const gop = try macho_file.undefs.getOrPut(gpa, rel.target); | |
| 552 | const gop = try macho_file.undefs.getOrPut(gpa, file.getGlobals()[rel.target]); | |
| 575 | 553 | if (!gop.found_existing) { |
| 576 | 554 | gop.value_ptr.* = .{}; |
| 577 | 555 | } |
| 578 | try gop.value_ptr.append(gpa, self.atom_index); | |
| 556 | try gop.value_ptr.append(gpa, .{ .index = self.atom_index, .file = self.file }); | |
| 579 | 557 | return true; |
| 580 | 558 | } |
| 581 | 559 | |
| ... | ... | @@ -591,7 +569,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 591 | 569 | const name = self.getName(macho_file); |
| 592 | 570 | const relocs = self.getRelocs(macho_file); |
| 593 | 571 | |
| 594 | relocs_log.debug("{x}: {s}", .{ self.getAddress(macho_file), name }); | |
| 572 | relocs_log.debug("{x}: {s}", .{ self.value, name }); | |
| 595 | 573 | |
| 596 | 574 | var has_error = false; |
| 597 | 575 | var stream = std.io.fixedBufferStream(buffer); |
| ... | ... | @@ -602,7 +580,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 602 | 580 | const subtractor = if (rel.meta.has_subtractor) relocs[i - 1] else null; |
| 603 | 581 | |
| 604 | 582 | if (rel.tag == .@"extern") { |
| 605 | if (rel.getTargetSymbol(macho_file).getFile(macho_file) == null) continue; | |
| 583 | if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue; | |
| 606 | 584 | } |
| 607 | 585 | |
| 608 | 586 | try stream.seekTo(rel_offset); |
| ... | ... | @@ -610,13 +588,19 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 610 | 588 | switch (err) { |
| 611 | 589 | error.RelaxFail => { |
| 612 | 590 | const target = switch (rel.tag) { |
| 613 | .@"extern" => rel.getTargetSymbol(macho_file).getName(macho_file), | |
| 614 | .local => rel.getTargetAtom(macho_file).getName(macho_file), | |
| 591 | .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file), | |
| 592 | .local => rel.getTargetAtom(self, macho_file).getName(macho_file), | |
| 615 | 593 | }; |
| 616 | 594 | try macho_file.reportParseError2( |
| 617 | 595 | file.getIndex(), |
| 618 | "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {s}, target {s}", | |
| 619 | .{ name, self.getAddress(macho_file), rel.offset, @tagName(rel.type), target }, | |
| 596 | "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}", | |
| 597 | .{ | |
| 598 | name, | |
| 599 | self.getAddress(macho_file), | |
| 600 | rel.offset, | |
| 601 | rel.fmtPretty(macho_file.getTarget().cpu.arch), | |
| 602 | target, | |
| 603 | }, | |
| 620 | 604 | ); |
| 621 | 605 | has_error = true; |
| 622 | 606 | }, |
| ... | ... | @@ -649,14 +633,12 @@ fn resolveRelocInner( |
| 649 | 633 | ) ResolveError!void { |
| 650 | 634 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 651 | 635 | const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; |
| 652 | const seg_id = macho_file.sections.items(.segment_id)[self.out_n_sect]; | |
| 653 | const seg = macho_file.segments.items[seg_id]; | |
| 654 | 636 | const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset)); |
| 655 | 637 | const A = rel.addend + rel.getRelocAddend(cpu_arch); |
| 656 | const S: i64 = @intCast(rel.getTargetAddress(macho_file)); | |
| 657 | const G: i64 = @intCast(rel.getGotTargetAddress(macho_file)); | |
| 638 | const S: i64 = @intCast(rel.getTargetAddress(self, macho_file)); | |
| 639 | const G: i64 = @intCast(rel.getGotTargetAddress(self, macho_file)); | |
| 658 | 640 | const TLS = @as(i64, @intCast(macho_file.getTlsAddress())); |
| 659 | const SUB = if (subtractor) |sub| @as(i64, @intCast(sub.getTargetAddress(macho_file))) else 0; | |
| 641 | const SUB = if (subtractor) |sub| @as(i64, @intCast(sub.getTargetAddress(self, macho_file))) else 0; | |
| 660 | 642 | // Address of the __got_zig table entry if any. |
| 661 | 643 | const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(macho_file))); |
| 662 | 644 | |
| ... | ... | @@ -674,21 +656,21 @@ fn resolveRelocInner( |
| 674 | 656 | }.divExact; |
| 675 | 657 | |
| 676 | 658 | switch (rel.tag) { |
| 677 | .local => relocs_log.debug(" {x}<+{d}>: {s}: [=> {x}] atom({d})", .{ | |
| 659 | .local => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] atom({d})", .{ | |
| 678 | 660 | P, |
| 679 | 661 | rel_offset, |
| 680 | @tagName(rel.type), | |
| 662 | rel.fmtPretty(cpu_arch), | |
| 681 | 663 | S + A - SUB, |
| 682 | rel.getTargetAtom(macho_file).atom_index, | |
| 664 | rel.getTargetAtom(self, macho_file).atom_index, | |
| 683 | 665 | }), |
| 684 | .@"extern" => relocs_log.debug(" {x}<+{d}>: {s}: [=> {x}] G({x}) ZG({x}) ({s})", .{ | |
| 666 | .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ZG({x}) ({s})", .{ | |
| 685 | 667 | P, |
| 686 | 668 | rel_offset, |
| 687 | @tagName(rel.type), | |
| 669 | rel.fmtPretty(cpu_arch), | |
| 688 | 670 | S + A - SUB, |
| 689 | 671 | G + A, |
| 690 | 672 | ZIG_GOT + A, |
| 691 | rel.getTargetSymbol(macho_file).getName(macho_file), | |
| 673 | rel.getTargetSymbol(self, macho_file).getName(macho_file), | |
| 692 | 674 | }), |
| 693 | 675 | } |
| 694 | 676 | |
| ... | ... | @@ -699,34 +681,13 @@ fn resolveRelocInner( |
| 699 | 681 | assert(!rel.meta.pcrel); |
| 700 | 682 | if (rel.meta.length == 3) { |
| 701 | 683 | if (rel.tag == .@"extern") { |
| 702 | const sym = rel.getTargetSymbol(macho_file); | |
| 684 | const sym = rel.getTargetSymbol(self, macho_file); | |
| 703 | 685 | if (sym.isTlvInit(macho_file)) { |
| 704 | 686 | try writer.writeInt(u64, @intCast(S - TLS), .little); |
| 705 | 687 | return; |
| 706 | 688 | } |
| 707 | const entry = bind.Entry{ | |
| 708 | .target = rel.target, | |
| 709 | .offset = @as(u64, @intCast(P)) - seg.vmaddr, | |
| 710 | .segment_id = seg_id, | |
| 711 | .addend = A, | |
| 712 | }; | |
| 713 | if (sym.flags.import) { | |
| 714 | macho_file.bind.entries.appendAssumeCapacity(entry); | |
| 715 | if (sym.flags.weak) { | |
| 716 | macho_file.weak_bind.entries.appendAssumeCapacity(entry); | |
| 717 | } | |
| 718 | return; | |
| 719 | } | |
| 720 | if (sym.flags.@"export" and sym.flags.weak) { | |
| 721 | macho_file.weak_bind.entries.appendAssumeCapacity(entry); | |
| 722 | } else if (sym.flags.interposable) { | |
| 723 | macho_file.bind.entries.appendAssumeCapacity(entry); | |
| 724 | } | |
| 689 | if (sym.flags.import) return; | |
| 725 | 690 | } |
| 726 | macho_file.rebase.entries.appendAssumeCapacity(.{ | |
| 727 | .offset = @as(u64, @intCast(P)) - seg.vmaddr, | |
| 728 | .segment_id = seg_id, | |
| 729 | }); | |
| 730 | 691 | try writer.writeInt(u64, @bitCast(S + A - SUB), .little); |
| 731 | 692 | } else if (rel.meta.length == 2) { |
| 732 | 693 | try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little); |
| ... | ... | @@ -750,7 +711,7 @@ fn resolveRelocInner( |
| 750 | 711 | .aarch64 => { |
| 751 | 712 | const disp: i28 = math.cast(i28, S + A - P) orelse blk: { |
| 752 | 713 | const thunk = self.getThunk(macho_file); |
| 753 | const S_: i64 = @intCast(thunk.getTargetAddress(rel.target, macho_file)); | |
| 714 | const S_: i64 = @intCast(thunk.getTargetAddress(rel.getTargetSymbolRef(self, macho_file), macho_file)); | |
| 754 | 715 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; |
| 755 | 716 | }; |
| 756 | 717 | aarch64.writeBranchImm(disp, code[rel_offset..][0..4]); |
| ... | ... | @@ -763,7 +724,7 @@ fn resolveRelocInner( |
| 763 | 724 | assert(rel.tag == .@"extern"); |
| 764 | 725 | assert(rel.meta.length == 2); |
| 765 | 726 | assert(rel.meta.pcrel); |
| 766 | if (rel.getTargetSymbol(macho_file).flags.has_got) { | |
| 727 | if (rel.getTargetSymbol(self, macho_file).flags.has_got) { | |
| 767 | 728 | try writer.writeInt(i32, @intCast(G + A - P), .little); |
| 768 | 729 | } else { |
| 769 | 730 | try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file); |
| ... | ... | @@ -786,7 +747,7 @@ fn resolveRelocInner( |
| 786 | 747 | assert(rel.tag == .@"extern"); |
| 787 | 748 | assert(rel.meta.length == 2); |
| 788 | 749 | assert(rel.meta.pcrel); |
| 789 | const sym = rel.getTargetSymbol(macho_file); | |
| 750 | const sym = rel.getTargetSymbol(self, macho_file); | |
| 790 | 751 | if (sym.flags.tlv_ptr) { |
| 791 | 752 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); |
| 792 | 753 | try writer.writeInt(i32, @intCast(S_ + A - P), .little); |
| ... | ... | @@ -809,7 +770,7 @@ fn resolveRelocInner( |
| 809 | 770 | assert(rel.tag == .@"extern"); |
| 810 | 771 | assert(rel.meta.length == 2); |
| 811 | 772 | assert(rel.meta.pcrel); |
| 812 | const sym = rel.getTargetSymbol(macho_file); | |
| 773 | const sym = rel.getTargetSymbol(self, macho_file); | |
| 813 | 774 | const source = math.cast(u64, P) orelse return error.Overflow; |
| 814 | 775 | const target = target: { |
| 815 | 776 | const target = switch (rel.type) { |
| ... | ... | @@ -868,7 +829,7 @@ fn resolveRelocInner( |
| 868 | 829 | assert(rel.meta.length == 2); |
| 869 | 830 | assert(!rel.meta.pcrel); |
| 870 | 831 | |
| 871 | const sym = rel.getTargetSymbol(macho_file); | |
| 832 | const sym = rel.getTargetSymbol(self, macho_file); | |
| 872 | 833 | const target = target: { |
| 873 | 834 | const target = if (sym.flags.tlv_ptr) blk: { |
| 874 | 835 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); |
| ... | ... | @@ -945,11 +906,11 @@ const x86_64 = struct { |
| 945 | 906 | }, |
| 946 | 907 | else => |x| { |
| 947 | 908 | var err = try macho_file.addErrorWithNotes(2); |
| 948 | try err.addMsg(macho_file, "{s}: 0x{x}: 0x{x}: failed to relax relocation of type {s}", .{ | |
| 909 | try err.addMsg(macho_file, "{s}: 0x{x}: 0x{x}: failed to relax relocation of type {}", .{ | |
| 949 | 910 | self.getName(macho_file), |
| 950 | 911 | self.getAddress(macho_file), |
| 951 | 912 | rel.offset, |
| 952 | @tagName(rel.type), | |
| 913 | rel.fmtPretty(.x86_64), | |
| 953 | 914 | }); |
| 954 | 915 | try err.addNote(macho_file, "expected .mov instruction but found .{s}", .{@tagName(x)}); |
| 955 | 916 | try err.addNote(macho_file, "while parsing {}", .{self.getFile(macho_file).fmtPath()}); |
| ... | ... | @@ -1012,48 +973,49 @@ pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 { |
| 1012 | 973 | } |
| 1013 | 974 | } |
| 1014 | 975 | |
| 1015 | pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.ArrayList(macho.relocation_info)) !void { | |
| 976 | pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.relocation_info) !void { | |
| 1016 | 977 | const tracy = trace(@src()); |
| 1017 | 978 | defer tracy.end(); |
| 1018 | 979 | |
| 1019 | 980 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 1020 | 981 | const relocs = self.getRelocs(macho_file); |
| 1021 | var stream = std.io.fixedBufferStream(code); | |
| 1022 | 982 | |
| 983 | var i: usize = 0; | |
| 1023 | 984 | for (relocs) |rel| { |
| 1024 | const rel_offset = rel.offset - self.off; | |
| 985 | defer i += 1; | |
| 986 | const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; | |
| 1025 | 987 | const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow; |
| 988 | assert(r_address >= 0); | |
| 1026 | 989 | const r_symbolnum = r_symbolnum: { |
| 1027 | 990 | const r_symbolnum: u32 = switch (rel.tag) { |
| 1028 | .local => rel.getTargetAtom(macho_file).out_n_sect + 1, | |
| 1029 | .@"extern" => rel.getTargetSymbol(macho_file).getOutputSymtabIndex(macho_file).?, | |
| 991 | .local => rel.getTargetAtom(self, macho_file).out_n_sect + 1, | |
| 992 | .@"extern" => rel.getTargetSymbol(self, macho_file).getOutputSymtabIndex(macho_file).?, | |
| 1030 | 993 | }; |
| 1031 | 994 | break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow; |
| 1032 | 995 | }; |
| 1033 | 996 | const r_extern = rel.tag == .@"extern"; |
| 1034 | 997 | var addend = rel.addend + rel.getRelocAddend(cpu_arch); |
| 1035 | 998 | if (rel.tag == .local) { |
| 1036 | const target: i64 = @intCast(rel.getTargetAddress(macho_file)); | |
| 999 | const target: i64 = @intCast(rel.getTargetAddress(self, macho_file)); | |
| 1037 | 1000 | addend += target; |
| 1038 | 1001 | } |
| 1039 | 1002 | |
| 1040 | try stream.seekTo(rel_offset); | |
| 1041 | ||
| 1042 | 1003 | switch (cpu_arch) { |
| 1043 | 1004 | .aarch64 => { |
| 1044 | 1005 | if (rel.type == .unsigned) switch (rel.meta.length) { |
| 1045 | 1006 | 0, 1 => unreachable, |
| 1046 | 2 => try stream.writer().writeInt(i32, @truncate(addend), .little), | |
| 1047 | 3 => try stream.writer().writeInt(i64, addend, .little), | |
| 1007 | 2 => mem.writeInt(i32, code[rel_offset..][0..4], @truncate(addend), .little), | |
| 1008 | 3 => mem.writeInt(i64, code[rel_offset..][0..8], addend, .little), | |
| 1048 | 1009 | } else if (addend > 0) { |
| 1049 | buffer.appendAssumeCapacity(.{ | |
| 1010 | buffer[i] = .{ | |
| 1050 | 1011 | .r_address = r_address, |
| 1051 | 1012 | .r_symbolnum = @bitCast(math.cast(i24, addend) orelse return error.Overflow), |
| 1052 | 1013 | .r_pcrel = 0, |
| 1053 | 1014 | .r_length = 2, |
| 1054 | 1015 | .r_extern = 0, |
| 1055 | 1016 | .r_type = @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_ADDEND), |
| 1056 | }); | |
| 1017 | }; | |
| 1018 | i += 1; | |
| 1057 | 1019 | } |
| 1058 | 1020 | |
| 1059 | 1021 | const r_type: macho.reloc_type_arm64 = switch (rel.type) { |
| ... | ... | @@ -1077,14 +1039,14 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1077 | 1039 | .tlv, |
| 1078 | 1040 | => unreachable, |
| 1079 | 1041 | }; |
| 1080 | buffer.appendAssumeCapacity(.{ | |
| 1042 | buffer[i] = .{ | |
| 1081 | 1043 | .r_address = r_address, |
| 1082 | 1044 | .r_symbolnum = r_symbolnum, |
| 1083 | 1045 | .r_pcrel = @intFromBool(rel.meta.pcrel), |
| 1084 | 1046 | .r_extern = @intFromBool(r_extern), |
| 1085 | 1047 | .r_length = rel.meta.length, |
| 1086 | 1048 | .r_type = @intFromEnum(r_type), |
| 1087 | }); | |
| 1049 | }; | |
| 1088 | 1050 | }, |
| 1089 | 1051 | .x86_64 => { |
| 1090 | 1052 | if (rel.meta.pcrel) { |
| ... | ... | @@ -1096,8 +1058,8 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1096 | 1058 | } |
| 1097 | 1059 | switch (rel.meta.length) { |
| 1098 | 1060 | 0, 1 => unreachable, |
| 1099 | 2 => try stream.writer().writeInt(i32, @truncate(addend), .little), | |
| 1100 | 3 => try stream.writer().writeInt(i64, addend, .little), | |
| 1061 | 2 => mem.writeInt(i32, code[rel_offset..][0..4], @truncate(addend), .little), | |
| 1062 | 3 => mem.writeInt(i64, code[rel_offset..][0..8], addend, .little), | |
| 1101 | 1063 | } |
| 1102 | 1064 | |
| 1103 | 1065 | const r_type: macho.reloc_type_x86_64 = switch (rel.type) { |
| ... | ... | @@ -1121,18 +1083,20 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1121 | 1083 | .tlvp_pageoff, |
| 1122 | 1084 | => unreachable, |
| 1123 | 1085 | }; |
| 1124 | buffer.appendAssumeCapacity(.{ | |
| 1086 | buffer[i] = .{ | |
| 1125 | 1087 | .r_address = r_address, |
| 1126 | 1088 | .r_symbolnum = r_symbolnum, |
| 1127 | 1089 | .r_pcrel = @intFromBool(rel.meta.pcrel), |
| 1128 | 1090 | .r_extern = @intFromBool(r_extern), |
| 1129 | 1091 | .r_length = rel.meta.length, |
| 1130 | 1092 | .r_type = @intFromEnum(r_type), |
| 1131 | }); | |
| 1093 | }; | |
| 1132 | 1094 | }, |
| 1133 | 1095 | else => unreachable, |
| 1134 | 1096 | } |
| 1135 | 1097 | } |
| 1098 | ||
| 1099 | assert(i == buffer.len); | |
| 1136 | 1100 | } |
| 1137 | 1101 | |
| 1138 | 1102 | pub fn format( |
| ... | ... | @@ -1170,18 +1134,18 @@ fn format2( |
| 1170 | 1134 | _ = unused_fmt_string; |
| 1171 | 1135 | const atom = ctx.atom; |
| 1172 | 1136 | const macho_file = ctx.macho_file; |
| 1173 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{ | |
| 1174 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), | |
| 1175 | atom.out_n_sect, atom.alignment, atom.size, | |
| 1176 | atom.getRelocs(macho_file).len, | |
| 1137 | const file = atom.getFile(macho_file); | |
| 1138 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{ | |
| 1139 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), | |
| 1140 | atom.out_n_sect, atom.alignment, atom.size, | |
| 1141 | atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk, | |
| 1177 | 1142 | }); |
| 1178 | if (atom.flags.thunk) try writer.print(" : thunk({d})", .{atom.getExtra(macho_file).?.thunk}); | |
| 1179 | 1143 | if (!atom.flags.alive) try writer.writeAll(" : [*]"); |
| 1180 | if (atom.flags.unwind) { | |
| 1144 | if (atom.getUnwindRecords(macho_file).len > 0) { | |
| 1181 | 1145 | try writer.writeAll(" : unwind{ "); |
| 1182 | const extra = atom.getExtra(macho_file).?; | |
| 1146 | const extra = atom.getExtra(macho_file); | |
| 1183 | 1147 | for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| { |
| 1184 | const rec = macho_file.getUnwindRecord(index); | |
| 1148 | const rec = file.object.getUnwindRecord(index); | |
| 1185 | 1149 | try writer.print("{d}", .{index}); |
| 1186 | 1150 | if (!rec.alive) try writer.writeAll("([*])"); |
| 1187 | 1151 | if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", "); |
| ... | ... | @@ -1198,18 +1162,6 @@ pub const Flags = packed struct { |
| 1198 | 1162 | |
| 1199 | 1163 | /// Specifies if this atom has been visited during garbage collection. |
| 1200 | 1164 | visited: bool = false, |
| 1201 | ||
| 1202 | /// Whether this atom has a range extension thunk. | |
| 1203 | thunk: bool = false, | |
| 1204 | ||
| 1205 | /// Whether this atom has any relocations. | |
| 1206 | relocs: bool = false, | |
| 1207 | ||
| 1208 | /// Whether this atom has any unwind records. | |
| 1209 | unwind: bool = false, | |
| 1210 | ||
| 1211 | /// Whether this atom has LiteralPool entry. | |
| 1212 | literal_pool: bool = false, | |
| 1213 | 1165 | }; |
| 1214 | 1166 | |
| 1215 | 1167 | pub const Extra = struct { |
| ... | ... | @@ -1222,6 +1174,12 @@ pub const Extra = struct { |
| 1222 | 1174 | /// Count of relocations belonging to this atom. |
| 1223 | 1175 | rel_count: u32 = 0, |
| 1224 | 1176 | |
| 1177 | /// Start index of relocations being written out to file for this atom. | |
| 1178 | rel_out_index: u32 = 0, | |
| 1179 | ||
| 1180 | /// Count of relocations written out to file for this atom. | |
| 1181 | rel_out_count: u32 = 0, | |
| 1182 | ||
| 1225 | 1183 | /// Start index of relocations belonging to this atom. |
| 1226 | 1184 | unwind_index: u32 = 0, |
| 1227 | 1185 | |
| ... | ... | @@ -1229,14 +1187,16 @@ pub const Extra = struct { |
| 1229 | 1187 | unwind_count: u32 = 0, |
| 1230 | 1188 | |
| 1231 | 1189 | /// Index into LiteralPool entry for this atom. |
| 1232 | literal_index: u32 = 0, | |
| 1190 | literal_pool_index: u32 = 0, | |
| 1191 | ||
| 1192 | /// Index into the File's symbol table for local symbol representing this literal atom. | |
| 1193 | literal_symbol_index: u32 = 0, | |
| 1233 | 1194 | }; |
| 1234 | 1195 | |
| 1235 | 1196 | pub const Alignment = @import("../../InternPool.zig").Alignment; |
| 1236 | 1197 | |
| 1237 | 1198 | const aarch64 = @import("../aarch64.zig"); |
| 1238 | 1199 | const assert = std.debug.assert; |
| 1239 | const bind = @import("dyld_info/bind.zig"); | |
| 1240 | 1200 | const macho = std.macho; |
| 1241 | 1201 | const math = std.math; |
| 1242 | 1202 | const mem = std.mem; |
src/link/MachO/DebugSymbols.zig+6-6| ... | ... | @@ -175,8 +175,9 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 |
| 175 | 175 | } |
| 176 | 176 | |
| 177 | 177 | pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { |
| 178 | const zo = macho_file.getZigObject().?; | |
| 178 | 179 | for (self.relocs.items) |*reloc| { |
| 179 | const sym = macho_file.getSymbol(reloc.target); | |
| 180 | const sym = zo.symbols.items[reloc.target]; | |
| 180 | 181 | const sym_name = sym.getName(macho_file); |
| 181 | 182 | const addr = switch (reloc.type) { |
| 182 | 183 | .direct_load => sym.getAddress(.{}, macho_file), |
| ... | ... | @@ -382,23 +383,22 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 { |
| 382 | 383 | cmd.symoff = off; |
| 383 | 384 | |
| 384 | 385 | try self.symtab.resize(gpa, cmd.nsyms); |
| 385 | try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1); | |
| 386 | try self.strtab.resize(gpa, cmd.strsize); | |
| 387 | self.strtab.items[0] = 0; | |
| 386 | 388 | |
| 387 | 389 | if (macho_file.getZigObject()) |zo| { |
| 388 | 390 | zo.writeSymtab(macho_file, self); |
| 389 | 391 | } |
| 390 | 392 | for (macho_file.objects.items) |index| { |
| 391 | try macho_file.getFile(index).?.writeSymtab(macho_file, self); | |
| 393 | macho_file.getFile(index).?.writeSymtab(macho_file, self); | |
| 392 | 394 | } |
| 393 | 395 | for (macho_file.dylibs.items) |index| { |
| 394 | try macho_file.getFile(index).?.writeSymtab(macho_file, self); | |
| 396 | macho_file.getFile(index).?.writeSymtab(macho_file, self); | |
| 395 | 397 | } |
| 396 | 398 | if (macho_file.getInternalObject()) |internal| { |
| 397 | 399 | internal.writeSymtab(macho_file, self); |
| 398 | 400 | } |
| 399 | 401 | |
| 400 | assert(self.strtab.items.len == cmd.strsize); | |
| 401 | ||
| 402 | 402 | try self.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); |
| 403 | 403 | |
| 404 | 404 | return off + cmd.nsyms * @sizeOf(macho.nlist_64); |
src/link/MachO/Dylib.zig+136-60| ... | ... | @@ -6,7 +6,9 @@ strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 6 | 6 | id: ?Id = null, |
| 7 | 7 | ordinal: u16 = 0, |
| 8 | 8 | |
| 9 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 9 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | |
| 10 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 11 | globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{}, | |
| 10 | 12 | dependents: std.ArrayListUnmanaged(Id) = .{}, |
| 11 | 13 | rpaths: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 12 | 14 | umbrella: File.Index = 0, |
| ... | ... | @@ -37,6 +39,8 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void { |
| 37 | 39 | self.strtab.deinit(allocator); |
| 38 | 40 | if (self.id) |*id| id.deinit(allocator); |
| 39 | 41 | self.symbols.deinit(allocator); |
| 42 | self.symbols_extra.deinit(allocator); | |
| 43 | self.globals.deinit(allocator); | |
| 40 | 44 | for (self.dependents.items) |*id| { |
| 41 | 45 | id.deinit(allocator); |
| 42 | 46 | } |
| ... | ... | @@ -494,53 +498,55 @@ fn addObjCExport( |
| 494 | 498 | pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void { |
| 495 | 499 | const gpa = macho_file.base.comp.gpa; |
| 496 | 500 | |
| 497 | try self.symbols.ensureTotalCapacityPrecise(gpa, self.exports.items(.name).len); | |
| 498 | ||
| 499 | for (self.exports.items(.name)) |noff| { | |
| 500 | const name = self.getString(noff); | |
| 501 | const off = try macho_file.strings.insert(gpa, name); | |
| 502 | const gop = try macho_file.getOrCreateGlobal(off); | |
| 503 | self.symbols.addOneAssumeCapacity().* = gop.index; | |
| 501 | const nsyms = self.exports.items(.name).len; | |
| 502 | try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms); | |
| 503 | try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra)); | |
| 504 | try self.globals.ensureTotalCapacityPrecise(gpa, nsyms); | |
| 505 | self.globals.resize(gpa, nsyms) catch unreachable; | |
| 506 | @memset(self.globals.items, 0); | |
| 507 | ||
| 508 | for (self.exports.items(.name), self.exports.items(.flags)) |noff, flags| { | |
| 509 | const index = self.addSymbolAssumeCapacity(); | |
| 510 | const symbol = &self.symbols.items[index]; | |
| 511 | symbol.name = noff; | |
| 512 | symbol.extra = self.addSymbolExtraAssumeCapacity(.{}); | |
| 513 | symbol.flags.weak = flags.weak; | |
| 514 | symbol.flags.tlv = flags.tlv; | |
| 515 | symbol.visibility = .global; | |
| 504 | 516 | } |
| 505 | 517 | } |
| 506 | 518 | |
| 507 | pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) void { | |
| 519 | pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) !void { | |
| 508 | 520 | const tracy = trace(@src()); |
| 509 | 521 | defer tracy.end(); |
| 510 | 522 | |
| 511 | 523 | if (!self.explicit and !self.hoisted) return; |
| 512 | 524 | |
| 513 | for (self.symbols.items, self.exports.items(.flags)) |index, flags| { | |
| 514 | const global = macho_file.getSymbol(index); | |
| 525 | const gpa = macho_file.base.comp.gpa; | |
| 526 | ||
| 527 | for (self.exports.items(.flags), self.globals.items, 0..) |flags, *global, i| { | |
| 528 | const gop = try macho_file.resolver.getOrPut(gpa, .{ | |
| 529 | .index = @intCast(i), | |
| 530 | .file = self.index, | |
| 531 | }, macho_file); | |
| 532 | if (!gop.found_existing) { | |
| 533 | gop.ref.* = .{ .index = 0, .file = 0 }; | |
| 534 | } | |
| 535 | global.* = gop.index; | |
| 536 | ||
| 537 | if (gop.ref.getFile(macho_file) == null) { | |
| 538 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; | |
| 539 | continue; | |
| 540 | } | |
| 541 | ||
| 515 | 542 | if (self.asFile().getSymbolRank(.{ |
| 516 | 543 | .weak = flags.weak, |
| 517 | }) < global.getSymbolRank(macho_file)) { | |
| 518 | global.value = 0; | |
| 519 | global.atom = 0; | |
| 520 | global.nlist_idx = 0; | |
| 521 | global.file = self.index; | |
| 522 | global.flags.weak = flags.weak; | |
| 523 | global.flags.tlv = flags.tlv; | |
| 524 | global.flags.dyn_ref = false; | |
| 525 | global.flags.tentative = false; | |
| 526 | global.visibility = .global; | |
| 544 | }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) { | |
| 545 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; | |
| 527 | 546 | } |
| 528 | 547 | } |
| 529 | 548 | } |
| 530 | 549 | |
| 531 | pub fn resetGlobals(self: *Dylib, macho_file: *MachO) void { | |
| 532 | for (self.symbols.items) |sym_index| { | |
| 533 | const sym = macho_file.getSymbol(sym_index); | |
| 534 | const name = sym.name; | |
| 535 | const global = sym.flags.global; | |
| 536 | const weak_ref = sym.flags.weak_ref; | |
| 537 | sym.* = .{}; | |
| 538 | sym.name = name; | |
| 539 | sym.flags.global = global; | |
| 540 | sym.flags.weak_ref = weak_ref; | |
| 541 | } | |
| 542 | } | |
| 543 | ||
| 544 | 550 | pub fn isAlive(self: Dylib, macho_file: *MachO) bool { |
| 545 | 551 | if (!macho_file.dead_strip_dylibs) return self.explicit or self.referenced or self.needed; |
| 546 | 552 | return self.referenced or self.needed; |
| ... | ... | @@ -550,30 +556,31 @@ pub fn markReferenced(self: *Dylib, macho_file: *MachO) void { |
| 550 | 556 | const tracy = trace(@src()); |
| 551 | 557 | defer tracy.end(); |
| 552 | 558 | |
| 553 | for (self.symbols.items) |global_index| { | |
| 554 | const global = macho_file.getSymbol(global_index); | |
| 555 | const file_ptr = global.getFile(macho_file) orelse continue; | |
| 556 | if (file_ptr.getIndex() != self.index) continue; | |
| 559 | for (0..self.symbols.items.len) |i| { | |
| 560 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 561 | const file = ref.getFile(macho_file) orelse continue; | |
| 562 | if (file.getIndex() != self.index) continue; | |
| 563 | const global = ref.getSymbol(macho_file).?; | |
| 557 | 564 | if (global.isLocal()) continue; |
| 558 | 565 | self.referenced = true; |
| 559 | 566 | break; |
| 560 | 567 | } |
| 561 | 568 | } |
| 562 | 569 | |
| 563 | pub fn calcSymtabSize(self: *Dylib, macho_file: *MachO) !void { | |
| 570 | pub fn calcSymtabSize(self: *Dylib, macho_file: *MachO) void { | |
| 564 | 571 | const tracy = trace(@src()); |
| 565 | 572 | defer tracy.end(); |
| 566 | 573 | |
| 567 | for (self.symbols.items) |global_index| { | |
| 568 | const global = macho_file.getSymbol(global_index); | |
| 569 | const file_ptr = global.getFile(macho_file) orelse continue; | |
| 570 | if (file_ptr.getIndex() != self.index) continue; | |
| 571 | if (global.isLocal()) continue; | |
| 572 | assert(global.flags.import); | |
| 573 | global.flags.output_symtab = true; | |
| 574 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | |
| 574 | for (self.symbols.items, 0..) |*sym, i| { | |
| 575 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 576 | const file = ref.getFile(macho_file) orelse continue; | |
| 577 | if (file.getIndex() != self.index) continue; | |
| 578 | if (sym.isLocal()) continue; | |
| 579 | assert(sym.flags.import); | |
| 580 | sym.flags.output_symtab = true; | |
| 581 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | |
| 575 | 582 | self.output_symtab_ctx.nimports += 1; |
| 576 | self.output_symtab_ctx.strsize += @as(u32, @intCast(global.getName(macho_file).len + 1)); | |
| 583 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1)); | |
| 577 | 584 | } |
| 578 | 585 | } |
| 579 | 586 | |
| ... | ... | @@ -581,17 +588,20 @@ pub fn writeSymtab(self: Dylib, macho_file: *MachO, ctx: anytype) void { |
| 581 | 588 | const tracy = trace(@src()); |
| 582 | 589 | defer tracy.end(); |
| 583 | 590 | |
| 584 | for (self.symbols.items) |global_index| { | |
| 585 | const global = macho_file.getSymbol(global_index); | |
| 586 | const file = global.getFile(macho_file) orelse continue; | |
| 591 | var n_strx = self.output_symtab_ctx.stroff; | |
| 592 | for (self.symbols.items, 0..) |sym, i| { | |
| 593 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 594 | const file = ref.getFile(macho_file) orelse continue; | |
| 587 | 595 | if (file.getIndex() != self.index) continue; |
| 588 | const idx = global.getOutputSymtabIndex(macho_file) orelse continue; | |
| 589 | const n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 590 | ctx.strtab.appendSliceAssumeCapacity(global.getName(macho_file)); | |
| 591 | ctx.strtab.appendAssumeCapacity(0); | |
| 596 | const idx = sym.getOutputSymtabIndex(macho_file) orelse continue; | |
| 592 | 597 | const out_sym = &ctx.symtab.items[idx]; |
| 593 | 598 | out_sym.n_strx = n_strx; |
| 594 | global.setOutputSym(macho_file, out_sym); | |
| 599 | sym.setOutputSym(macho_file, out_sym); | |
| 600 | const name = sym.getName(macho_file); | |
| 601 | @memcpy(ctx.strtab.items[n_strx..][0..name.len], name); | |
| 602 | n_strx += @intCast(name.len); | |
| 603 | ctx.strtab.items[n_strx] = 0; | |
| 604 | n_strx += 1; | |
| 595 | 605 | } |
| 596 | 606 | } |
| 597 | 607 | |
| ... | ... | @@ -605,7 +615,7 @@ fn addString(self: *Dylib, allocator: Allocator, name: []const u8) !u32 { |
| 605 | 615 | return off; |
| 606 | 616 | } |
| 607 | 617 | |
| 608 | pub inline fn getString(self: Dylib, off: u32) [:0]const u8 { | |
| 618 | pub fn getString(self: Dylib, off: u32) [:0]const u8 { | |
| 609 | 619 | assert(off < self.strtab.items.len); |
| 610 | 620 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); |
| 611 | 621 | } |
| ... | ... | @@ -614,6 +624,66 @@ pub fn asFile(self: *Dylib) File { |
| 614 | 624 | return .{ .dylib = self }; |
| 615 | 625 | } |
| 616 | 626 | |
| 627 | fn addSymbol(self: *Dylib, allocator: Allocator) !Symbol.Index { | |
| 628 | try self.symbols.ensureUnusedCapacity(allocator, 1); | |
| 629 | return self.addSymbolAssumeCapacity(); | |
| 630 | } | |
| 631 | ||
| 632 | fn addSymbolAssumeCapacity(self: *Dylib) Symbol.Index { | |
| 633 | const index: Symbol.Index = @intCast(self.symbols.items.len); | |
| 634 | const symbol = self.symbols.addOneAssumeCapacity(); | |
| 635 | symbol.* = .{ .file = self.index }; | |
| 636 | return index; | |
| 637 | } | |
| 638 | ||
| 639 | pub fn getSymbolRef(self: Dylib, index: Symbol.Index, macho_file: *MachO) MachO.Ref { | |
| 640 | const global_index = self.globals.items[index]; | |
| 641 | if (macho_file.resolver.get(global_index)) |ref| return ref; | |
| 642 | return .{ .index = index, .file = self.index }; | |
| 643 | } | |
| 644 | ||
| 645 | pub fn addSymbolExtra(self: *Dylib, allocator: Allocator, extra: Symbol.Extra) !u32 { | |
| 646 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 647 | try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); | |
| 648 | return self.addSymbolExtraAssumeCapacity(extra); | |
| 649 | } | |
| 650 | ||
| 651 | fn addSymbolExtraAssumeCapacity(self: *Dylib, extra: Symbol.Extra) u32 { | |
| 652 | const index = @as(u32, @intCast(self.symbols_extra.items.len)); | |
| 653 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 654 | inline for (fields) |field| { | |
| 655 | self.symbols_extra.appendAssumeCapacity(switch (field.type) { | |
| 656 | u32 => @field(extra, field.name), | |
| 657 | else => @compileError("bad field type"), | |
| 658 | }); | |
| 659 | } | |
| 660 | return index; | |
| 661 | } | |
| 662 | ||
| 663 | pub fn getSymbolExtra(self: Dylib, index: u32) Symbol.Extra { | |
| 664 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 665 | var i: usize = index; | |
| 666 | var result: Symbol.Extra = undefined; | |
| 667 | inline for (fields) |field| { | |
| 668 | @field(result, field.name) = switch (field.type) { | |
| 669 | u32 => self.symbols_extra.items[i], | |
| 670 | else => @compileError("bad field type"), | |
| 671 | }; | |
| 672 | i += 1; | |
| 673 | } | |
| 674 | return result; | |
| 675 | } | |
| 676 | ||
| 677 | pub fn setSymbolExtra(self: *Dylib, index: u32, extra: Symbol.Extra) void { | |
| 678 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 679 | inline for (fields, 0..) |field, i| { | |
| 680 | self.symbols_extra.items[index + i] = switch (field.type) { | |
| 681 | u32 => @field(extra, field.name), | |
| 682 | else => @compileError("bad field type"), | |
| 683 | }; | |
| 684 | } | |
| 685 | } | |
| 686 | ||
| 617 | 687 | pub fn format( |
| 618 | 688 | self: *Dylib, |
| 619 | 689 | comptime unused_fmt_string: []const u8, |
| ... | ... | @@ -648,10 +718,16 @@ fn formatSymtab( |
| 648 | 718 | _ = unused_fmt_string; |
| 649 | 719 | _ = options; |
| 650 | 720 | const dylib = ctx.dylib; |
| 721 | const macho_file = ctx.macho_file; | |
| 651 | 722 | try writer.writeAll(" globals\n"); |
| 652 | for (dylib.symbols.items) |index| { | |
| 653 | const global = ctx.macho_file.getSymbol(index); | |
| 654 | try writer.print(" {}\n", .{global.fmt(ctx.macho_file)}); | |
| 723 | for (dylib.symbols.items, 0..) |sym, i| { | |
| 724 | const ref = dylib.getSymbolRef(@intCast(i), macho_file); | |
| 725 | if (ref.getFile(macho_file) == null) { | |
| 726 | // TODO any better way of handling this? | |
| 727 | try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); | |
| 728 | } else { | |
| 729 | try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); | |
| 730 | } | |
| 655 | 731 | } |
| 656 | 732 | } |
| 657 | 733 |
src/link/MachO/InternalObject.zig+652-143| ... | ... | @@ -1,13 +1,28 @@ |
| 1 | 1 | index: File.Index, |
| 2 | 2 | |
| 3 | 3 | sections: std.MultiArrayList(Section) = .{}, |
| 4 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 5 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 4 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | |
| 5 | atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 6 | atoms_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 7 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | |
| 8 | strtab: std.ArrayListUnmanaged(u8) = .{}, | |
| 9 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | |
| 10 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 11 | globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{}, | |
| 6 | 12 | |
| 7 | 13 | objc_methnames: std.ArrayListUnmanaged(u8) = .{}, |
| 8 | 14 | objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64), |
| 9 | 15 | |
| 10 | num_rebase_relocs: u32 = 0, | |
| 16 | force_undefined: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 17 | entry_index: ?Symbol.Index = null, | |
| 18 | dyld_stub_binder_index: ?Symbol.Index = null, | |
| 19 | dyld_private_index: ?Symbol.Index = null, | |
| 20 | objc_msg_send_index: ?Symbol.Index = null, | |
| 21 | mh_execute_header_index: ?Symbol.Index = null, | |
| 22 | mh_dylib_header_index: ?Symbol.Index = null, | |
| 23 | dso_handle_index: ?Symbol.Index = null, | |
| 24 | boundary_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 25 | ||
| 11 | 26 | output_symtab_ctx: MachO.SymtabCtx = .{}, |
| 12 | 27 | |
| 13 | 28 | pub fn deinit(self: *InternalObject, allocator: Allocator) void { |
| ... | ... | @@ -16,39 +31,224 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void { |
| 16 | 31 | } |
| 17 | 32 | self.sections.deinit(allocator); |
| 18 | 33 | self.atoms.deinit(allocator); |
| 34 | self.atoms_indexes.deinit(allocator); | |
| 35 | self.atoms_extra.deinit(allocator); | |
| 36 | self.symtab.deinit(allocator); | |
| 37 | self.strtab.deinit(allocator); | |
| 19 | 38 | self.symbols.deinit(allocator); |
| 39 | self.symbols_extra.deinit(allocator); | |
| 40 | self.globals.deinit(allocator); | |
| 20 | 41 | self.objc_methnames.deinit(allocator); |
| 42 | self.force_undefined.deinit(allocator); | |
| 43 | self.boundary_symbols.deinit(allocator); | |
| 44 | } | |
| 45 | ||
| 46 | pub fn init(self: *InternalObject, allocator: Allocator) !void { | |
| 47 | // Atom at index 0 is reserved as null atom. | |
| 48 | try self.atoms.append(allocator, .{}); | |
| 49 | try self.atoms_extra.append(allocator, 0); | |
| 50 | // Null byte in strtab | |
| 51 | try self.strtab.append(allocator, 0); | |
| 21 | 52 | } |
| 22 | 53 | |
| 23 | pub fn addSymbol(self: *InternalObject, name: [:0]const u8, macho_file: *MachO) !Symbol.Index { | |
| 54 | pub fn initSymbols(self: *InternalObject, macho_file: *MachO) !void { | |
| 55 | const newSymbolAssumeCapacity = struct { | |
| 56 | fn newSymbolAssumeCapacity(obj: *InternalObject, name: u32, args: struct { | |
| 57 | type: u8 = macho.N_UNDF | macho.N_EXT, | |
| 58 | desc: u16 = 0, | |
| 59 | }) Symbol.Index { | |
| 60 | const index = obj.addSymbolAssumeCapacity(); | |
| 61 | const symbol = &obj.symbols.items[index]; | |
| 62 | symbol.name = name; | |
| 63 | symbol.extra = obj.addSymbolExtraAssumeCapacity(.{}); | |
| 64 | symbol.flags.dyn_ref = args.desc & macho.REFERENCED_DYNAMICALLY != 0; | |
| 65 | symbol.visibility = if (args.type & macho.N_EXT != 0) blk: { | |
| 66 | break :blk if (args.type & macho.N_PEXT != 0) .hidden else .global; | |
| 67 | } else .local; | |
| 68 | ||
| 69 | const nlist_idx: u32 = @intCast(obj.symtab.items.len); | |
| 70 | const nlist = obj.symtab.addOneAssumeCapacity(); | |
| 71 | nlist.* = .{ | |
| 72 | .n_strx = name, | |
| 73 | .n_type = args.type, | |
| 74 | .n_sect = 0, | |
| 75 | .n_desc = args.desc, | |
| 76 | .n_value = 0, | |
| 77 | }; | |
| 78 | symbol.nlist_idx = nlist_idx; | |
| 79 | return index; | |
| 80 | } | |
| 81 | }.newSymbolAssumeCapacity; | |
| 82 | ||
| 24 | 83 | const gpa = macho_file.base.comp.gpa; |
| 25 | try self.symbols.ensureUnusedCapacity(gpa, 1); | |
| 26 | const off = try macho_file.strings.insert(gpa, name); | |
| 27 | const gop = try macho_file.getOrCreateGlobal(off); | |
| 28 | self.symbols.addOneAssumeCapacity().* = gop.index; | |
| 29 | const sym = macho_file.getSymbol(gop.index); | |
| 30 | sym.file = self.index; | |
| 31 | sym.value = 0; | |
| 32 | sym.atom = 0; | |
| 33 | sym.nlist_idx = 0; | |
| 34 | sym.flags = .{ .global = true }; | |
| 35 | return gop.index; | |
| 84 | var nsyms = macho_file.base.comp.force_undefined_symbols.keys().len; | |
| 85 | nsyms += 1; // dyld_stub_binder | |
| 86 | nsyms += 1; // _objc_msgSend | |
| 87 | if (!macho_file.base.isDynLib()) { | |
| 88 | nsyms += 1; // entry | |
| 89 | nsyms += 1; // __mh_execute_header | |
| 90 | } else { | |
| 91 | nsyms += 1; // __mh_dylib_header | |
| 92 | } | |
| 93 | nsyms += 1; // ___dso_handle | |
| 94 | nsyms += 1; // dyld_private | |
| 95 | ||
| 96 | try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms); | |
| 97 | try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra)); | |
| 98 | try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms); | |
| 99 | try self.globals.ensureTotalCapacityPrecise(gpa, nsyms); | |
| 100 | self.globals.resize(gpa, nsyms) catch unreachable; | |
| 101 | @memset(self.globals.items, 0); | |
| 102 | ||
| 103 | try self.force_undefined.ensureTotalCapacityPrecise(gpa, macho_file.base.comp.force_undefined_symbols.keys().len); | |
| 104 | for (macho_file.base.comp.force_undefined_symbols.keys()) |name| { | |
| 105 | self.force_undefined.addOneAssumeCapacity().* = newSymbolAssumeCapacity(self, try self.addString(gpa, name), .{}); | |
| 106 | } | |
| 107 | ||
| 108 | self.dyld_stub_binder_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "dyld_stub_binder"), .{}); | |
| 109 | self.objc_msg_send_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_objc_msgSend"), .{}); | |
| 110 | ||
| 111 | if (!macho_file.base.isDynLib()) { | |
| 112 | self.entry_index = newSymbolAssumeCapacity(self, try self.addString(gpa, macho_file.entry_name orelse "_main"), .{}); | |
| 113 | self.mh_execute_header_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__mh_execute_header"), .{ | |
| 114 | .type = macho.N_SECT | macho.N_EXT, | |
| 115 | .desc = macho.REFERENCED_DYNAMICALLY, | |
| 116 | }); | |
| 117 | } else { | |
| 118 | self.mh_dylib_header_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__mh_dylib_header"), .{ | |
| 119 | .type = macho.N_SECT | macho.N_EXT, | |
| 120 | }); | |
| 121 | } | |
| 122 | ||
| 123 | self.dso_handle_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "___dso_handle"), .{ | |
| 124 | .type = macho.N_SECT | macho.N_EXT, | |
| 125 | }); | |
| 126 | self.dyld_private_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "dyld_private"), .{ | |
| 127 | .type = macho.N_SECT, | |
| 128 | }); | |
| 36 | 129 | } |
| 37 | 130 | |
| 38 | /// Creates a fake input sections __TEXT,__objc_methname and __DATA,__objc_selrefs. | |
| 39 | pub fn addObjcMsgsendSections(self: *InternalObject, sym_name: []const u8, macho_file: *MachO) !Atom.Index { | |
| 40 | const methname_atom_index = try self.addObjcMethnameSection(sym_name, macho_file); | |
| 41 | return try self.addObjcSelrefsSection(methname_atom_index, macho_file); | |
| 131 | pub fn resolveSymbols(self: *InternalObject, macho_file: *MachO) !void { | |
| 132 | const tracy = trace(@src()); | |
| 133 | defer tracy.end(); | |
| 134 | ||
| 135 | const gpa = macho_file.base.comp.gpa; | |
| 136 | ||
| 137 | for (self.symtab.items, self.globals.items, 0..) |nlist, *global, i| { | |
| 138 | const gop = try macho_file.resolver.getOrPut(gpa, .{ | |
| 139 | .index = @intCast(i), | |
| 140 | .file = self.index, | |
| 141 | }, macho_file); | |
| 142 | if (!gop.found_existing) { | |
| 143 | gop.ref.* = .{ .index = 0, .file = 0 }; | |
| 144 | } | |
| 145 | global.* = gop.index; | |
| 146 | ||
| 147 | if (nlist.undf()) continue; | |
| 148 | if (gop.ref.getFile(macho_file) == null) { | |
| 149 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; | |
| 150 | continue; | |
| 151 | } | |
| 152 | ||
| 153 | if (self.asFile().getSymbolRank(.{ | |
| 154 | .archive = false, | |
| 155 | .weak = false, | |
| 156 | .tentative = false, | |
| 157 | }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) { | |
| 158 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; | |
| 159 | } | |
| 160 | } | |
| 42 | 161 | } |
| 43 | 162 | |
| 44 | fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_file: *MachO) !Atom.Index { | |
| 163 | pub fn resolveBoundarySymbols(self: *InternalObject, macho_file: *MachO) !void { | |
| 164 | const tracy = trace(@src()); | |
| 165 | defer tracy.end(); | |
| 166 | ||
| 45 | 167 | const gpa = macho_file.base.comp.gpa; |
| 46 | const atom_index = try macho_file.addAtom(); | |
| 47 | try self.atoms.append(gpa, atom_index); | |
| 168 | var boundary_symbols = std.StringArrayHashMap(MachO.Ref).init(gpa); | |
| 169 | defer boundary_symbols.deinit(); | |
| 170 | ||
| 171 | for (macho_file.objects.items) |index| { | |
| 172 | const object = macho_file.getFile(index).?.object; | |
| 173 | for (object.symbols.items, 0..) |sym, i| { | |
| 174 | const nlist = object.symtab.items(.nlist)[i]; | |
| 175 | if (!nlist.undf() or !nlist.ext()) continue; | |
| 176 | const ref = object.getSymbolRef(@intCast(i), macho_file); | |
| 177 | if (ref.getFile(macho_file) != null) continue; | |
| 178 | const name = sym.getName(macho_file); | |
| 179 | if (mem.startsWith(u8, name, "segment$start$") or | |
| 180 | mem.startsWith(u8, name, "segment$stop$") or | |
| 181 | mem.startsWith(u8, name, "section$start$") or | |
| 182 | mem.startsWith(u8, name, "section$stop$")) | |
| 183 | { | |
| 184 | const gop = try boundary_symbols.getOrPut(name); | |
| 185 | if (!gop.found_existing) { | |
| 186 | gop.value_ptr.* = .{ .index = @intCast(i), .file = index }; | |
| 187 | } | |
| 188 | } | |
| 189 | } | |
| 190 | } | |
| 191 | ||
| 192 | const nsyms = boundary_symbols.values().len; | |
| 193 | try self.boundary_symbols.ensureTotalCapacityPrecise(gpa, nsyms); | |
| 194 | try self.symbols.ensureUnusedCapacity(gpa, nsyms); | |
| 195 | try self.symtab.ensureUnusedCapacity(gpa, nsyms); | |
| 196 | try self.symbols_extra.ensureUnusedCapacity(gpa, nsyms * @sizeOf(Symbol.Extra)); | |
| 197 | try self.globals.ensureUnusedCapacity(gpa, nsyms); | |
| 198 | ||
| 199 | for (boundary_symbols.keys(), boundary_symbols.values()) |name, ref| { | |
| 200 | const name_off = try self.addString(gpa, name); | |
| 201 | const sym_index = self.addSymbolAssumeCapacity(); | |
| 202 | self.boundary_symbols.appendAssumeCapacity(sym_index); | |
| 203 | const sym = &self.symbols.items[sym_index]; | |
| 204 | sym.name = name_off; | |
| 205 | sym.visibility = .local; | |
| 206 | const nlist_idx: u32 = @intCast(self.symtab.items.len); | |
| 207 | const nlist = self.symtab.addOneAssumeCapacity(); | |
| 208 | nlist.* = .{ | |
| 209 | .n_strx = name_off, | |
| 210 | .n_type = macho.N_SECT, | |
| 211 | .n_sect = 0, | |
| 212 | .n_desc = 0, | |
| 213 | .n_value = 0, | |
| 214 | }; | |
| 215 | sym.nlist_idx = nlist_idx; | |
| 216 | sym.extra = self.addSymbolExtraAssumeCapacity(.{}); | |
| 217 | ||
| 218 | const idx = ref.getFile(macho_file).?.object.globals.items[ref.index]; | |
| 219 | self.globals.addOneAssumeCapacity().* = idx; | |
| 220 | macho_file.resolver.values.items[idx - 1] = .{ .index = sym_index, .file = self.index }; | |
| 221 | } | |
| 222 | } | |
| 223 | ||
| 224 | pub fn markLive(self: *InternalObject, macho_file: *MachO) void { | |
| 225 | const tracy = trace(@src()); | |
| 226 | defer tracy.end(); | |
| 227 | ||
| 228 | for (0..self.symbols.items.len) |i| { | |
| 229 | const nlist = self.symtab.items[i]; | |
| 230 | if (!nlist.ext()) continue; | |
| 231 | ||
| 232 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 233 | const file = ref.getFile(macho_file) orelse continue; | |
| 234 | if (file == .object and !file.object.alive) { | |
| 235 | file.object.alive = true; | |
| 236 | file.object.markLive(macho_file); | |
| 237 | } | |
| 238 | } | |
| 239 | } | |
| 48 | 240 | |
| 49 | const atom = macho_file.getAtom(atom_index).?; | |
| 50 | atom.atom_index = atom_index; | |
| 51 | atom.file = self.index; | |
| 241 | /// Creates a fake input sections __TEXT,__objc_methname and __DATA,__objc_selrefs. | |
| 242 | pub fn addObjcMsgsendSections(self: *InternalObject, sym_name: []const u8, macho_file: *MachO) !Symbol.Index { | |
| 243 | const methname_sym_index = try self.addObjcMethnameSection(sym_name, macho_file); | |
| 244 | return try self.addObjcSelrefsSection(methname_sym_index, macho_file); | |
| 245 | } | |
| 246 | ||
| 247 | fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_file: *MachO) !Symbol.Index { | |
| 248 | const gpa = macho_file.base.comp.gpa; | |
| 249 | const atom_index = try self.addAtom(gpa); | |
| 250 | try self.atoms_indexes.append(gpa, atom_index); | |
| 251 | const atom = self.getAtom(atom_index).?; | |
| 52 | 252 | atom.size = methname.len + 1; |
| 53 | 253 | atom.alignment = .@"1"; |
| 54 | 254 | |
| ... | ... | @@ -64,17 +264,32 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil |
| 64 | 264 | try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1); |
| 65 | 265 | self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable; |
| 66 | 266 | |
| 267 | const name_str = try self.addString(gpa, "ltmp"); | |
| 268 | const sym_index = try self.addSymbol(gpa); | |
| 269 | const sym = &self.symbols.items[sym_index]; | |
| 270 | sym.name = name_str; | |
| 271 | sym.atom_ref = .{ .index = atom_index, .file = self.index }; | |
| 272 | sym.extra = try self.addSymbolExtra(gpa, .{}); | |
| 273 | const nlist_idx: u32 = @intCast(self.symtab.items.len); | |
| 274 | const nlist = try self.symtab.addOne(gpa); | |
| 275 | nlist.* = .{ | |
| 276 | .n_strx = name_str, | |
| 277 | .n_type = macho.N_SECT, | |
| 278 | .n_sect = @intCast(n_sect + 1), | |
| 279 | .n_desc = 0, | |
| 280 | .n_value = 0, | |
| 281 | }; | |
| 282 | sym.nlist_idx = nlist_idx; | |
| 283 | try self.globals.append(gpa, 0); | |
| 284 | ||
| 67 | 285 | return atom_index; |
| 68 | 286 | } |
| 69 | 287 | |
| 70 | fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, macho_file: *MachO) !Atom.Index { | |
| 288 | fn addObjcSelrefsSection(self: *InternalObject, methname_sym_index: Symbol.Index, macho_file: *MachO) !Symbol.Index { | |
| 71 | 289 | const gpa = macho_file.base.comp.gpa; |
| 72 | const atom_index = try macho_file.addAtom(); | |
| 73 | try self.atoms.append(gpa, atom_index); | |
| 74 | ||
| 75 | const atom = macho_file.getAtom(atom_index).?; | |
| 76 | atom.atom_index = atom_index; | |
| 77 | atom.file = self.index; | |
| 290 | const atom_index = try self.addAtom(gpa); | |
| 291 | try self.atoms_indexes.append(gpa, atom_index); | |
| 292 | const atom = self.getAtom(atom_index).?; | |
| 78 | 293 | atom.size = @sizeOf(u64); |
| 79 | 294 | atom.alignment = .@"8"; |
| 80 | 295 | |
| ... | ... | @@ -90,9 +305,9 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, |
| 90 | 305 | const relocs = &self.sections.items(.relocs)[n_sect]; |
| 91 | 306 | try relocs.ensureUnusedCapacity(gpa, 1); |
| 92 | 307 | relocs.appendAssumeCapacity(.{ |
| 93 | .tag = .local, | |
| 308 | .tag = .@"extern", | |
| 94 | 309 | .offset = 0, |
| 95 | .target = methname_atom_index, | |
| 310 | .target = methname_sym_index, | |
| 96 | 311 | .addend = 0, |
| 97 | 312 | .type = .unsigned, |
| 98 | 313 | .meta = .{ |
| ... | ... | @@ -102,140 +317,285 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, |
| 102 | 317 | .has_subtractor = false, |
| 103 | 318 | }, |
| 104 | 319 | }); |
| 105 | try atom.addExtra(.{ .rel_index = 0, .rel_count = 1 }, macho_file); | |
| 106 | atom.flags.relocs = true; | |
| 107 | self.num_rebase_relocs += 1; | |
| 320 | atom.addExtra(.{ .rel_index = 0, .rel_count = 1 }, macho_file); | |
| 321 | ||
| 322 | const sym_index = try self.addSymbol(gpa); | |
| 323 | const sym = &self.symbols.items[sym_index]; | |
| 324 | sym.atom_ref = .{ .index = atom_index, .file = self.index }; | |
| 325 | sym.extra = try self.addSymbolExtra(gpa, .{}); | |
| 326 | const nlist_idx: u32 = @intCast(self.symtab.items.len); | |
| 327 | const nlist = try self.symtab.addOne(gpa); | |
| 328 | nlist.* = .{ | |
| 329 | .n_strx = 0, | |
| 330 | .n_type = macho.N_SECT, | |
| 331 | .n_sect = @intCast(n_sect + 1), | |
| 332 | .n_desc = 0, | |
| 333 | .n_value = 0, | |
| 334 | }; | |
| 335 | sym.nlist_idx = nlist_idx; | |
| 336 | try self.globals.append(gpa, 0); | |
| 337 | atom.addExtra(.{ .literal_symbol_index = sym_index }, macho_file); | |
| 108 | 338 | |
| 109 | return atom_index; | |
| 339 | return sym_index; | |
| 110 | 340 | } |
| 111 | 341 | |
| 112 | pub fn resolveLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void { | |
| 342 | pub fn resolveObjcMsgSendSymbols(self: *InternalObject, macho_file: *MachO) !void { | |
| 343 | const tracy = trace(@src()); | |
| 344 | defer tracy.end(); | |
| 345 | ||
| 346 | const gpa = macho_file.base.comp.gpa; | |
| 347 | ||
| 348 | var objc_msgsend_syms = std.StringArrayHashMap(MachO.Ref).init(gpa); | |
| 349 | defer objc_msgsend_syms.deinit(); | |
| 350 | ||
| 351 | for (macho_file.objects.items) |index| { | |
| 352 | const object = macho_file.getFile(index).?.object; | |
| 353 | ||
| 354 | for (object.symbols.items, 0..) |sym, i| { | |
| 355 | const nlist = object.symtab.items(.nlist)[i]; | |
| 356 | if (!nlist.ext()) continue; | |
| 357 | if (!nlist.undf()) continue; | |
| 358 | ||
| 359 | const ref = object.getSymbolRef(@intCast(i), macho_file); | |
| 360 | if (ref.getFile(macho_file) != null) continue; | |
| 361 | ||
| 362 | const name = sym.getName(macho_file); | |
| 363 | if (mem.startsWith(u8, name, "_objc_msgSend$")) { | |
| 364 | const gop = try objc_msgsend_syms.getOrPut(name); | |
| 365 | if (!gop.found_existing) { | |
| 366 | gop.value_ptr.* = .{ .index = @intCast(i), .file = index }; | |
| 367 | } | |
| 368 | } | |
| 369 | } | |
| 370 | } | |
| 371 | ||
| 372 | for (objc_msgsend_syms.keys(), objc_msgsend_syms.values()) |sym_name, ref| { | |
| 373 | const name = MachO.eatPrefix(sym_name, "_objc_msgSend$").?; | |
| 374 | const selrefs_index = try self.addObjcMsgsendSections(name, macho_file); | |
| 375 | ||
| 376 | const name_off = try self.addString(gpa, sym_name); | |
| 377 | const sym_index = try self.addSymbol(gpa); | |
| 378 | const sym = &self.symbols.items[sym_index]; | |
| 379 | sym.name = name_off; | |
| 380 | sym.visibility = .hidden; | |
| 381 | const nlist_idx: u32 = @intCast(self.symtab.items.len); | |
| 382 | const nlist = try self.symtab.addOne(gpa); | |
| 383 | nlist.* = .{ | |
| 384 | .n_strx = name_off, | |
| 385 | .n_type = macho.N_SECT | macho.N_EXT | macho.N_PEXT, | |
| 386 | .n_sect = 0, | |
| 387 | .n_desc = 0, | |
| 388 | .n_value = 0, | |
| 389 | }; | |
| 390 | sym.nlist_idx = nlist_idx; | |
| 391 | sym.extra = try self.addSymbolExtra(gpa, .{ .objc_selrefs = selrefs_index }); | |
| 392 | sym.flags.objc_stubs = true; | |
| 393 | ||
| 394 | const idx = ref.getFile(macho_file).?.object.globals.items[ref.index]; | |
| 395 | try self.globals.append(gpa, idx); | |
| 396 | macho_file.resolver.values.items[idx - 1] = .{ .index = sym_index, .file = self.index }; | |
| 397 | } | |
| 398 | } | |
| 399 | ||
| 400 | pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void { | |
| 401 | const tracy = trace(@src()); | |
| 402 | defer tracy.end(); | |
| 403 | ||
| 113 | 404 | const gpa = macho_file.base.comp.gpa; |
| 114 | 405 | |
| 115 | 406 | var buffer = std.ArrayList(u8).init(gpa); |
| 116 | 407 | defer buffer.deinit(); |
| 117 | 408 | |
| 118 | 409 | const slice = self.sections.slice(); |
| 119 | for (slice.items(.header), self.atoms.items, 0..) |header, atom_index, n_sect| { | |
| 120 | if (Object.isCstringLiteral(header) or Object.isFixedSizeLiteral(header)) { | |
| 121 | const data = try self.getSectionData(@intCast(n_sect)); | |
| 122 | const atom = macho_file.getAtom(atom_index).?; | |
| 123 | const res = try lp.insert(gpa, header.type(), data); | |
| 124 | if (!res.found_existing) { | |
| 125 | res.atom.* = atom_index; | |
| 126 | } | |
| 127 | atom.flags.literal_pool = true; | |
| 128 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); | |
| 129 | } else if (Object.isPtrLiteral(header)) { | |
| 130 | const atom = macho_file.getAtom(atom_index).?; | |
| 131 | const relocs = atom.getRelocs(macho_file); | |
| 132 | assert(relocs.len == 1); | |
| 133 | const rel = relocs[0]; | |
| 134 | assert(rel.tag == .local); | |
| 135 | const target = macho_file.getAtom(rel.target).?; | |
| 136 | const addend = std.math.cast(u32, rel.addend) orelse return error.Overflow; | |
| 137 | const target_size = std.math.cast(usize, target.size) orelse return error.Overflow; | |
| 138 | try buffer.ensureUnusedCapacity(target_size); | |
| 139 | buffer.resize(target_size) catch unreachable; | |
| 140 | try target.getData(macho_file, buffer.items); | |
| 141 | const res = try lp.insert(gpa, header.type(), buffer.items[addend..]); | |
| 142 | buffer.clearRetainingCapacity(); | |
| 143 | if (!res.found_existing) { | |
| 144 | res.atom.* = atom_index; | |
| 145 | } | |
| 146 | atom.flags.literal_pool = true; | |
| 147 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); | |
| 410 | for (slice.items(.header), self.getAtoms()) |header, atom_index| { | |
| 411 | if (!Object.isPtrLiteral(header)) continue; | |
| 412 | const atom = self.getAtom(atom_index).?; | |
| 413 | const relocs = atom.getRelocs(macho_file); | |
| 414 | assert(relocs.len == 1); | |
| 415 | const rel = relocs[0]; | |
| 416 | assert(rel.tag == .@"extern"); | |
| 417 | const target = rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?; | |
| 418 | const target_size = std.math.cast(usize, target.size) orelse return error.Overflow; | |
| 419 | try buffer.ensureUnusedCapacity(target_size); | |
| 420 | buffer.resize(target_size) catch unreachable; | |
| 421 | @memcpy(buffer.items, try self.getSectionData(target.n_sect)); | |
| 422 | const res = try lp.insert(gpa, header.type(), buffer.items); | |
| 423 | buffer.clearRetainingCapacity(); | |
| 424 | if (!res.found_existing) { | |
| 425 | res.ref.* = .{ .index = atom.getExtra(macho_file).literal_symbol_index, .file = self.index }; | |
| 426 | } else { | |
| 427 | const lp_sym = lp.getSymbol(res.index, macho_file); | |
| 428 | const lp_atom = lp_sym.getAtom(macho_file).?; | |
| 429 | lp_atom.alignment = lp_atom.alignment.max(atom.alignment); | |
| 430 | atom.flags.alive = false; | |
| 148 | 431 | } |
| 432 | atom.addExtra(.{ .literal_pool_index = res.index }, macho_file); | |
| 149 | 433 | } |
| 150 | 434 | } |
| 151 | 435 | |
| 152 | pub fn dedupLiterals(self: InternalObject, lp: MachO.LiteralPool, macho_file: *MachO) void { | |
| 153 | for (self.atoms.items) |atom_index| { | |
| 154 | const atom = macho_file.getAtom(atom_index) orelse continue; | |
| 436 | pub fn dedupLiterals(self: *InternalObject, lp: MachO.LiteralPool, macho_file: *MachO) void { | |
| 437 | const tracy = trace(@src()); | |
| 438 | defer tracy.end(); | |
| 439 | ||
| 440 | for (self.getAtoms()) |atom_index| { | |
| 441 | const atom = self.getAtom(atom_index) orelse continue; | |
| 155 | 442 | if (!atom.flags.alive) continue; |
| 156 | if (!atom.flags.relocs) continue; | |
| 157 | 443 | |
| 158 | 444 | const relocs = blk: { |
| 159 | const extra = atom.getExtra(macho_file).?; | |
| 445 | const extra = atom.getExtra(macho_file); | |
| 160 | 446 | const relocs = self.sections.items(.relocs)[atom.n_sect].items; |
| 161 | 447 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; |
| 162 | 448 | }; |
| 163 | for (relocs) |*rel| switch (rel.tag) { | |
| 164 | .local => { | |
| 165 | const target = macho_file.getAtom(rel.target).?; | |
| 166 | if (target.getLiteralPoolIndex(macho_file)) |lp_index| { | |
| 167 | const lp_atom = lp.getAtom(lp_index, macho_file); | |
| 168 | if (target.atom_index != lp_atom.atom_index) { | |
| 169 | lp_atom.alignment = lp_atom.alignment.max(target.alignment); | |
| 170 | target.flags.alive = false; | |
| 171 | rel.target = lp_atom.atom_index; | |
| 172 | } | |
| 173 | } | |
| 174 | }, | |
| 175 | .@"extern" => { | |
| 176 | const target_sym = rel.getTargetSymbol(macho_file); | |
| 177 | if (target_sym.getAtom(macho_file)) |target_atom| { | |
| 178 | if (target_atom.getLiteralPoolIndex(macho_file)) |lp_index| { | |
| 179 | const lp_atom = lp.getAtom(lp_index, macho_file); | |
| 180 | if (target_atom.atom_index != lp_atom.atom_index) { | |
| 181 | lp_atom.alignment = lp_atom.alignment.max(target_atom.alignment); | |
| 182 | target_atom.flags.alive = false; | |
| 183 | target_sym.atom = lp_atom.atom_index; | |
| 184 | } | |
| 185 | } | |
| 186 | } | |
| 187 | }, | |
| 188 | }; | |
| 449 | for (relocs) |*rel| { | |
| 450 | if (rel.tag != .@"extern") continue; | |
| 451 | const target_sym_ref = rel.getTargetSymbolRef(atom.*, macho_file); | |
| 452 | const file = target_sym_ref.getFile(macho_file) orelse continue; | |
| 453 | if (file.getIndex() != self.index) continue; | |
| 454 | const target_sym = target_sym_ref.getSymbol(macho_file).?; | |
| 455 | const target_atom = target_sym.getAtom(macho_file) orelse continue; | |
| 456 | if (!Object.isPtrLiteral(target_atom.getInputSection(macho_file))) continue; | |
| 457 | const lp_index = target_atom.getExtra(macho_file).literal_pool_index; | |
| 458 | const lp_sym = lp.getSymbol(lp_index, macho_file); | |
| 459 | const lp_atom_ref = lp_sym.atom_ref; | |
| 460 | if (target_atom.atom_index != lp_atom_ref.index or target_atom.file != lp_atom_ref.file) { | |
| 461 | target_sym.atom_ref = lp_atom_ref; | |
| 462 | } | |
| 463 | } | |
| 189 | 464 | } |
| 190 | 465 | |
| 191 | for (self.symbols.items) |sym_index| { | |
| 192 | const sym = macho_file.getSymbol(sym_index); | |
| 466 | for (self.symbols.items) |*sym| { | |
| 193 | 467 | if (!sym.flags.objc_stubs) continue; |
| 194 | var extra = sym.getExtra(macho_file).?; | |
| 195 | const atom = macho_file.getAtom(extra.objc_selrefs).?; | |
| 196 | if (atom.getLiteralPoolIndex(macho_file)) |lp_index| { | |
| 197 | const lp_atom = lp.getAtom(lp_index, macho_file); | |
| 198 | if (atom.atom_index != lp_atom.atom_index) { | |
| 199 | lp_atom.alignment = lp_atom.alignment.max(atom.alignment); | |
| 200 | atom.flags.alive = false; | |
| 201 | extra.objc_selrefs = lp_atom.atom_index; | |
| 202 | sym.setExtra(extra, macho_file); | |
| 468 | const extra = sym.getExtra(macho_file); | |
| 469 | const file = sym.getFile(macho_file).?; | |
| 470 | if (file.getIndex() != self.index) continue; | |
| 471 | const tsym = switch (file) { | |
| 472 | .dylib => unreachable, | |
| 473 | inline else => |x| &x.symbols.items[extra.objc_selrefs], | |
| 474 | }; | |
| 475 | const atom = tsym.getAtom(macho_file) orelse continue; | |
| 476 | if (!Object.isPtrLiteral(atom.getInputSection(macho_file))) continue; | |
| 477 | const lp_index = atom.getExtra(macho_file).literal_pool_index; | |
| 478 | const lp_sym = lp.getSymbol(lp_index, macho_file); | |
| 479 | const lp_atom_ref = lp_sym.atom_ref; | |
| 480 | if (atom.atom_index != lp_atom_ref.index or atom.file != lp_atom_ref.file) { | |
| 481 | tsym.atom_ref = lp_atom_ref; | |
| 482 | } | |
| 483 | } | |
| 484 | } | |
| 485 | ||
| 486 | pub fn scanRelocs(self: *InternalObject, macho_file: *MachO) void { | |
| 487 | const tracy = trace(@src()); | |
| 488 | defer tracy.end(); | |
| 489 | ||
| 490 | if (self.getEntryRef(macho_file)) |ref| { | |
| 491 | if (ref.getFile(macho_file) != null) { | |
| 492 | const sym = ref.getSymbol(macho_file).?; | |
| 493 | if (sym.flags.import) sym.flags.stubs = true; | |
| 494 | } | |
| 495 | } | |
| 496 | if (self.getDyldStubBinderRef(macho_file)) |ref| { | |
| 497 | if (ref.getFile(macho_file) != null) { | |
| 498 | const sym = ref.getSymbol(macho_file).?; | |
| 499 | sym.flags.needs_got = true; | |
| 500 | } | |
| 501 | } | |
| 502 | if (self.getObjcMsgSendRef(macho_file)) |ref| { | |
| 503 | if (ref.getFile(macho_file) != null) { | |
| 504 | const sym = ref.getSymbol(macho_file).?; | |
| 505 | // TODO is it always needed, or only if we are synthesising fast stubs | |
| 506 | sym.flags.needs_got = true; | |
| 507 | } | |
| 508 | } | |
| 509 | } | |
| 510 | ||
| 511 | pub fn allocateSyntheticSymbols(self: *InternalObject, macho_file: *MachO) void { | |
| 512 | const text_seg = macho_file.getTextSegment(); | |
| 513 | ||
| 514 | if (self.mh_execute_header_index) |index| { | |
| 515 | const ref = self.getSymbolRef(index, macho_file); | |
| 516 | if (ref.getFile(macho_file)) |file| { | |
| 517 | if (file.getIndex() == self.index) { | |
| 518 | const sym = &self.symbols.items[index]; | |
| 519 | sym.value = text_seg.vmaddr; | |
| 520 | } | |
| 521 | } | |
| 522 | } | |
| 523 | ||
| 524 | if (macho_file.data_sect_index) |idx| { | |
| 525 | const sect = macho_file.sections.items(.header)[idx]; | |
| 526 | for (&[_]?Symbol.Index{ | |
| 527 | self.dso_handle_index, | |
| 528 | self.mh_dylib_header_index, | |
| 529 | self.dyld_private_index, | |
| 530 | }) |maybe_index| { | |
| 531 | if (maybe_index) |index| { | |
| 532 | const ref = self.getSymbolRef(index, macho_file); | |
| 533 | if (ref.getFile(macho_file)) |file| { | |
| 534 | if (file.getIndex() == self.index) { | |
| 535 | const sym = &self.symbols.items[index]; | |
| 536 | sym.value = sect.addr; | |
| 537 | sym.out_n_sect = idx; | |
| 538 | } | |
| 539 | } | |
| 203 | 540 | } |
| 204 | 541 | } |
| 205 | 542 | } |
| 206 | 543 | } |
| 207 | 544 | |
| 208 | pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) !void { | |
| 209 | for (self.symbols.items) |sym_index| { | |
| 210 | const sym = macho_file.getSymbol(sym_index); | |
| 211 | if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue; | |
| 545 | pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) void { | |
| 546 | for (self.symbols.items, 0..) |*sym, i| { | |
| 547 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 548 | const file = ref.getFile(macho_file) orelse continue; | |
| 549 | if (file.getIndex() != self.index) continue; | |
| 550 | if (sym.getName(macho_file).len == 0) continue; | |
| 212 | 551 | sym.flags.output_symtab = true; |
| 213 | 552 | if (sym.isLocal()) { |
| 214 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); | |
| 553 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); | |
| 215 | 554 | self.output_symtab_ctx.nlocals += 1; |
| 216 | 555 | } else if (sym.flags.@"export") { |
| 217 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file); | |
| 556 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file); | |
| 218 | 557 | self.output_symtab_ctx.nexports += 1; |
| 219 | 558 | } else { |
| 220 | 559 | assert(sym.flags.import); |
| 221 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | |
| 560 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | |
| 222 | 561 | self.output_symtab_ctx.nimports += 1; |
| 223 | 562 | } |
| 224 | 563 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1)); |
| 225 | 564 | } |
| 226 | 565 | } |
| 227 | 566 | |
| 567 | pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void { | |
| 568 | const tracy = trace(@src()); | |
| 569 | defer tracy.end(); | |
| 570 | ||
| 571 | for (self.getAtoms()) |atom_index| { | |
| 572 | const atom = self.getAtom(atom_index) orelse continue; | |
| 573 | if (!atom.flags.alive) continue; | |
| 574 | const sect = atom.getInputSection(macho_file); | |
| 575 | if (sect.isZerofill()) continue; | |
| 576 | const off = std.math.cast(usize, atom.value) orelse return error.Overflow; | |
| 577 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 578 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items[off..][0..size]; | |
| 579 | @memcpy(buffer, try self.getSectionData(atom.n_sect)); | |
| 580 | try atom.resolveRelocs(macho_file, buffer); | |
| 581 | } | |
| 582 | } | |
| 583 | ||
| 228 | 584 | pub fn writeSymtab(self: InternalObject, macho_file: *MachO, ctx: anytype) void { |
| 229 | for (self.symbols.items) |sym_index| { | |
| 230 | const sym = macho_file.getSymbol(sym_index); | |
| 231 | if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue; | |
| 585 | var n_strx = self.output_symtab_ctx.stroff; | |
| 586 | for (self.symbols.items, 0..) |sym, i| { | |
| 587 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 588 | const file = ref.getFile(macho_file) orelse continue; | |
| 589 | if (file.getIndex() != self.index) continue; | |
| 232 | 590 | const idx = sym.getOutputSymtabIndex(macho_file) orelse continue; |
| 233 | const n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 234 | ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file)); | |
| 235 | ctx.strtab.appendAssumeCapacity(0); | |
| 236 | 591 | const out_sym = &ctx.symtab.items[idx]; |
| 237 | 592 | out_sym.n_strx = n_strx; |
| 238 | 593 | sym.setOutputSym(macho_file, out_sym); |
| 594 | const name = sym.getName(macho_file); | |
| 595 | @memcpy(ctx.strtab.items[n_strx..][0..name.len], name); | |
| 596 | n_strx += @intCast(name.len); | |
| 597 | ctx.strtab.items[n_strx] = 0; | |
| 598 | n_strx += 1; | |
| 239 | 599 | } |
| 240 | 600 | } |
| 241 | 601 | |
| ... | ... | @@ -264,30 +624,171 @@ fn getSectionData(self: *const InternalObject, index: u32) error{Overflow}![]con |
| 264 | 624 | @panic("ref to non-existent section"); |
| 265 | 625 | } |
| 266 | 626 | |
| 267 | pub fn getAtomData(self: *const InternalObject, atom: Atom, buffer: []u8) error{Overflow}!void { | |
| 268 | assert(buffer.len == atom.size); | |
| 269 | const data = try self.getSectionData(atom.n_sect); | |
| 270 | const off = std.math.cast(usize, atom.off) orelse return error.Overflow; | |
| 271 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 272 | @memcpy(buffer, data[off..][0..size]); | |
| 627 | pub fn addString(self: *InternalObject, allocator: Allocator, name: []const u8) !u32 { | |
| 628 | const off: u32 = @intCast(self.strtab.items.len); | |
| 629 | try self.strtab.ensureUnusedCapacity(allocator, name.len + 1); | |
| 630 | self.strtab.appendSliceAssumeCapacity(name); | |
| 631 | self.strtab.appendAssumeCapacity(0); | |
| 632 | return off; | |
| 633 | } | |
| 634 | ||
| 635 | pub fn getString(self: InternalObject, off: u32) [:0]const u8 { | |
| 636 | assert(off < self.strtab.items.len); | |
| 637 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); | |
| 638 | } | |
| 639 | ||
| 640 | pub fn asFile(self: *InternalObject) File { | |
| 641 | return .{ .internal = self }; | |
| 273 | 642 | } |
| 274 | 643 | |
| 275 | 644 | pub fn getAtomRelocs(self: *const InternalObject, atom: Atom, macho_file: *MachO) []const Relocation { |
| 276 | if (!atom.flags.relocs) return &[0]Relocation{}; | |
| 277 | const extra = atom.getExtra(macho_file).?; | |
| 645 | const extra = atom.getExtra(macho_file); | |
| 278 | 646 | const relocs = self.sections.items(.relocs)[atom.n_sect]; |
| 279 | 647 | return relocs.items[extra.rel_index..][0..extra.rel_count]; |
| 280 | 648 | } |
| 281 | 649 | |
| 282 | pub fn getString(self: InternalObject, off: u32) [:0]const u8 { | |
| 283 | _ = self; | |
| 284 | _ = off; | |
| 285 | // We don't have any local strings for synthetic atoms. | |
| 286 | return ""; | |
| 650 | fn addAtom(self: *InternalObject, allocator: Allocator) !Atom.Index { | |
| 651 | const atom_index: Atom.Index = @intCast(self.atoms.items.len); | |
| 652 | const atom = try self.atoms.addOne(allocator); | |
| 653 | atom.* = .{ | |
| 654 | .file = self.index, | |
| 655 | .atom_index = atom_index, | |
| 656 | .extra = try self.addAtomExtra(allocator, .{}), | |
| 657 | }; | |
| 658 | return atom_index; | |
| 287 | 659 | } |
| 288 | 660 | |
| 289 | pub fn asFile(self: *InternalObject) File { | |
| 290 | return .{ .internal = self }; | |
| 661 | pub fn getAtom(self: *InternalObject, atom_index: Atom.Index) ?*Atom { | |
| 662 | if (atom_index == 0) return null; | |
| 663 | assert(atom_index < self.atoms.items.len); | |
| 664 | return &self.atoms.items[atom_index]; | |
| 665 | } | |
| 666 | ||
| 667 | pub fn getAtoms(self: InternalObject) []const Atom.Index { | |
| 668 | return self.atoms_indexes.items; | |
| 669 | } | |
| 670 | ||
| 671 | fn addAtomExtra(self: *InternalObject, allocator: Allocator, extra: Atom.Extra) !u32 { | |
| 672 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 673 | try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len); | |
| 674 | return self.addAtomExtraAssumeCapacity(extra); | |
| 675 | } | |
| 676 | ||
| 677 | fn addAtomExtraAssumeCapacity(self: *InternalObject, extra: Atom.Extra) u32 { | |
| 678 | const index = @as(u32, @intCast(self.atoms_extra.items.len)); | |
| 679 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 680 | inline for (fields) |field| { | |
| 681 | self.atoms_extra.appendAssumeCapacity(switch (field.type) { | |
| 682 | u32 => @field(extra, field.name), | |
| 683 | else => @compileError("bad field type"), | |
| 684 | }); | |
| 685 | } | |
| 686 | return index; | |
| 687 | } | |
| 688 | ||
| 689 | pub fn getAtomExtra(self: InternalObject, index: u32) Atom.Extra { | |
| 690 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 691 | var i: usize = index; | |
| 692 | var result: Atom.Extra = undefined; | |
| 693 | inline for (fields) |field| { | |
| 694 | @field(result, field.name) = switch (field.type) { | |
| 695 | u32 => self.atoms_extra.items[i], | |
| 696 | else => @compileError("bad field type"), | |
| 697 | }; | |
| 698 | i += 1; | |
| 699 | } | |
| 700 | return result; | |
| 701 | } | |
| 702 | ||
| 703 | pub fn setAtomExtra(self: *InternalObject, index: u32, extra: Atom.Extra) void { | |
| 704 | assert(index > 0); | |
| 705 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 706 | inline for (fields, 0..) |field, i| { | |
| 707 | self.atoms_extra.items[index + i] = switch (field.type) { | |
| 708 | u32 => @field(extra, field.name), | |
| 709 | else => @compileError("bad field type"), | |
| 710 | }; | |
| 711 | } | |
| 712 | } | |
| 713 | ||
| 714 | pub fn getEntryRef(self: InternalObject, macho_file: *MachO) ?MachO.Ref { | |
| 715 | const index = self.entry_index orelse return null; | |
| 716 | return self.getSymbolRef(index, macho_file); | |
| 717 | } | |
| 718 | ||
| 719 | pub fn getDyldStubBinderRef(self: InternalObject, macho_file: *MachO) ?MachO.Ref { | |
| 720 | const index = self.dyld_stub_binder_index orelse return null; | |
| 721 | return self.getSymbolRef(index, macho_file); | |
| 722 | } | |
| 723 | ||
| 724 | pub fn getDyldPrivateRef(self: InternalObject, macho_file: *MachO) ?MachO.Ref { | |
| 725 | const index = self.dyld_private_index orelse return null; | |
| 726 | return self.getSymbolRef(index, macho_file); | |
| 727 | } | |
| 728 | ||
| 729 | pub fn getObjcMsgSendRef(self: InternalObject, macho_file: *MachO) ?MachO.Ref { | |
| 730 | const index = self.objc_msg_send_index orelse return null; | |
| 731 | return self.getSymbolRef(index, macho_file); | |
| 732 | } | |
| 733 | ||
| 734 | pub fn addSymbol(self: *InternalObject, allocator: Allocator) !Symbol.Index { | |
| 735 | try self.symbols.ensureUnusedCapacity(allocator, 1); | |
| 736 | return self.addSymbolAssumeCapacity(); | |
| 737 | } | |
| 738 | ||
| 739 | pub fn addSymbolAssumeCapacity(self: *InternalObject) Symbol.Index { | |
| 740 | const index: Symbol.Index = @intCast(self.symbols.items.len); | |
| 741 | const symbol = self.symbols.addOneAssumeCapacity(); | |
| 742 | symbol.* = .{ .file = self.index }; | |
| 743 | return index; | |
| 744 | } | |
| 745 | ||
| 746 | pub fn getSymbolRef(self: InternalObject, index: Symbol.Index, macho_file: *MachO) MachO.Ref { | |
| 747 | const global_index = self.globals.items[index]; | |
| 748 | if (macho_file.resolver.get(global_index)) |ref| return ref; | |
| 749 | return .{ .index = index, .file = self.index }; | |
| 750 | } | |
| 751 | ||
| 752 | pub fn addSymbolExtra(self: *InternalObject, allocator: Allocator, extra: Symbol.Extra) !u32 { | |
| 753 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 754 | try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); | |
| 755 | return self.addSymbolExtraAssumeCapacity(extra); | |
| 756 | } | |
| 757 | ||
| 758 | fn addSymbolExtraAssumeCapacity(self: *InternalObject, extra: Symbol.Extra) u32 { | |
| 759 | const index = @as(u32, @intCast(self.symbols_extra.items.len)); | |
| 760 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 761 | inline for (fields) |field| { | |
| 762 | self.symbols_extra.appendAssumeCapacity(switch (field.type) { | |
| 763 | u32 => @field(extra, field.name), | |
| 764 | else => @compileError("bad field type"), | |
| 765 | }); | |
| 766 | } | |
| 767 | return index; | |
| 768 | } | |
| 769 | ||
| 770 | pub fn getSymbolExtra(self: InternalObject, index: u32) Symbol.Extra { | |
| 771 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 772 | var i: usize = index; | |
| 773 | var result: Symbol.Extra = undefined; | |
| 774 | inline for (fields) |field| { | |
| 775 | @field(result, field.name) = switch (field.type) { | |
| 776 | u32 => self.symbols_extra.items[i], | |
| 777 | else => @compileError("bad field type"), | |
| 778 | }; | |
| 779 | i += 1; | |
| 780 | } | |
| 781 | return result; | |
| 782 | } | |
| 783 | ||
| 784 | pub fn setSymbolExtra(self: *InternalObject, index: u32, extra: Symbol.Extra) void { | |
| 785 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 786 | inline for (fields, 0..) |field, i| { | |
| 787 | self.symbols_extra.items[index + i] = switch (field.type) { | |
| 788 | u32 => @field(extra, field.name), | |
| 789 | else => @compileError("bad field type"), | |
| 790 | }; | |
| 791 | } | |
| 291 | 792 | } |
| 292 | 793 | |
| 293 | 794 | const FormatContext = struct { |
| ... | ... | @@ -311,8 +812,8 @@ fn formatAtoms( |
| 311 | 812 | _ = unused_fmt_string; |
| 312 | 813 | _ = options; |
| 313 | 814 | try writer.writeAll(" atoms\n"); |
| 314 | for (ctx.self.atoms.items) |atom_index| { | |
| 315 | const atom = ctx.macho_file.getAtom(atom_index).?; | |
| 815 | for (ctx.self.getAtoms()) |atom_index| { | |
| 816 | const atom = ctx.self.getAtom(atom_index) orelse continue; | |
| 316 | 817 | try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)}); |
| 317 | 818 | } |
| 318 | 819 | } |
| ... | ... | @@ -332,10 +833,17 @@ fn formatSymtab( |
| 332 | 833 | ) !void { |
| 333 | 834 | _ = unused_fmt_string; |
| 334 | 835 | _ = options; |
| 836 | const macho_file = ctx.macho_file; | |
| 837 | const self = ctx.self; | |
| 335 | 838 | try writer.writeAll(" symbols\n"); |
| 336 | for (ctx.self.symbols.items) |index| { | |
| 337 | const global = ctx.macho_file.getSymbol(index); | |
| 338 | try writer.print(" {}\n", .{global.fmt(ctx.macho_file)}); | |
| 839 | for (self.symbols.items, 0..) |sym, i| { | |
| 840 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 841 | if (ref.getFile(macho_file) == null) { | |
| 842 | // TODO any better way of handling this? | |
| 843 | try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); | |
| 844 | } else { | |
| 845 | try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); | |
| 846 | } | |
| 339 | 847 | } |
| 340 | 848 | } |
| 341 | 849 | |
| ... | ... | @@ -354,6 +862,7 @@ const assert = std.debug.assert; |
| 354 | 862 | const macho = std.macho; |
| 355 | 863 | const mem = std.mem; |
| 356 | 864 | const std = @import("std"); |
| 865 | const trace = @import("../../tracy.zig").trace; | |
| 357 | 866 | |
| 358 | 867 | const Allocator = std.mem.Allocator; |
| 359 | 868 | const Atom = @import("Atom.zig"); |
src/link/MachO/Object.zig+1005-488| ... | ... | @@ -1,16 +1,22 @@ |
| 1 | archive: ?InArchive = null, | |
| 1 | /// Non-zero for fat object files or archives | |
| 2 | offset: u64, | |
| 2 | 3 | path: []const u8, |
| 3 | 4 | file_handle: File.HandleIndex, |
| 4 | 5 | mtime: u64, |
| 5 | 6 | index: File.Index, |
| 7 | in_archive: ?InArchive = null, | |
| 6 | 8 | |
| 7 | 9 | header: ?macho.mach_header_64 = null, |
| 8 | 10 | sections: std.MultiArrayList(Section) = .{}, |
| 9 | 11 | symtab: std.MultiArrayList(Nlist) = .{}, |
| 10 | 12 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 11 | 13 | |
| 12 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 13 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 14 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | |
| 15 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 16 | globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{}, | |
| 17 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | |
| 18 | atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 19 | atoms_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 14 | 20 | |
| 15 | 21 | platform: ?MachO.Platform = null, |
| 16 | 22 | compile_unit: ?CompileUnit = null, |
| ... | ... | @@ -21,13 +27,14 @@ compact_unwind_sect_index: ?u8 = null, |
| 21 | 27 | cies: std.ArrayListUnmanaged(Cie) = .{}, |
| 22 | 28 | fdes: std.ArrayListUnmanaged(Fde) = .{}, |
| 23 | 29 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, |
| 24 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{}, | |
| 30 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{}, | |
| 31 | unwind_records_indexes: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{}, | |
| 25 | 32 | data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, |
| 26 | 33 | |
| 27 | 34 | alive: bool = true, |
| 28 | 35 | hidden: bool = false, |
| 29 | 36 | |
| 30 | dynamic_relocs: MachO.DynamicRelocs = .{}, | |
| 37 | compact_unwind_ctx: CompactUnwindCtx = .{}, | |
| 31 | 38 | output_symtab_ctx: MachO.SymtabCtx = .{}, |
| 32 | 39 | output_ar_state: Archive.ArState = .{}, |
| 33 | 40 | |
| ... | ... | @@ -39,7 +46,7 @@ pub fn isObject(path: []const u8) !bool { |
| 39 | 46 | } |
| 40 | 47 | |
| 41 | 48 | pub fn deinit(self: *Object, allocator: Allocator) void { |
| 42 | if (self.archive) |*ar| allocator.free(ar.path); | |
| 49 | if (self.in_archive) |*ar| allocator.free(ar.path); | |
| 43 | 50 | allocator.free(self.path); |
| 44 | 51 | for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { |
| 45 | 52 | relocs.deinit(allocator); |
| ... | ... | @@ -49,11 +56,16 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 49 | 56 | self.symtab.deinit(allocator); |
| 50 | 57 | self.strtab.deinit(allocator); |
| 51 | 58 | self.symbols.deinit(allocator); |
| 59 | self.symbols_extra.deinit(allocator); | |
| 60 | self.globals.deinit(allocator); | |
| 52 | 61 | self.atoms.deinit(allocator); |
| 62 | self.atoms_indexes.deinit(allocator); | |
| 63 | self.atoms_extra.deinit(allocator); | |
| 53 | 64 | self.cies.deinit(allocator); |
| 54 | 65 | self.fdes.deinit(allocator); |
| 55 | 66 | self.eh_frame_data.deinit(allocator); |
| 56 | 67 | self.unwind_records.deinit(allocator); |
| 68 | self.unwind_records_indexes.deinit(allocator); | |
| 57 | 69 | for (self.stab_files.items) |*sf| { |
| 58 | 70 | sf.stabs.deinit(allocator); |
| 59 | 71 | } |
| ... | ... | @@ -65,13 +77,18 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 65 | 77 | const tracy = trace(@src()); |
| 66 | 78 | defer tracy.end(); |
| 67 | 79 | |
| 80 | log.debug("parsing {}", .{self.fmtPath()}); | |
| 81 | ||
| 68 | 82 | const gpa = macho_file.base.comp.gpa; |
| 69 | const offset = if (self.archive) |ar| ar.offset else 0; | |
| 70 | 83 | const handle = macho_file.getFileHandle(self.file_handle); |
| 84 | const cpu_arch = macho_file.getTarget().cpu.arch; | |
| 85 | ||
| 86 | // Atom at index 0 is reserved as null atom | |
| 87 | try self.atoms.append(gpa, .{ .extra = try self.addAtomExtra(gpa, .{}) }); | |
| 71 | 88 | |
| 72 | 89 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 73 | 90 | { |
| 74 | const amt = try handle.preadAll(&header_buffer, offset); | |
| 91 | const amt = try handle.preadAll(&header_buffer, self.offset); | |
| 75 | 92 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 76 | 93 | } |
| 77 | 94 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; |
| ... | ... | @@ -84,7 +101,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 84 | 101 | return error.InvalidCpuArch; |
| 85 | 102 | }, |
| 86 | 103 | }; |
| 87 | if (macho_file.getTarget().cpu.arch != this_cpu_arch) { | |
| 104 | if (cpu_arch != this_cpu_arch) { | |
| 88 | 105 | try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)}); |
| 89 | 106 | return error.InvalidCpuArch; |
| 90 | 107 | } |
| ... | ... | @@ -92,7 +109,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 92 | 109 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 93 | 110 | defer gpa.free(lc_buffer); |
| 94 | 111 | { |
| 95 | const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); | |
| 112 | const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); | |
| 96 | 113 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; |
| 97 | 114 | } |
| 98 | 115 | |
| ... | ... | @@ -119,14 +136,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 119 | 136 | const cmd = lc.cast(macho.symtab_command).?; |
| 120 | 137 | try self.strtab.resize(gpa, cmd.strsize); |
| 121 | 138 | { |
| 122 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset); | |
| 139 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset); | |
| 123 | 140 | if (amt != self.strtab.items.len) return error.InputOutput; |
| 124 | 141 | } |
| 125 | 142 | |
| 126 | 143 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); |
| 127 | 144 | defer gpa.free(symtab_buffer); |
| 128 | 145 | { |
| 129 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset); | |
| 146 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset); | |
| 130 | 147 | if (amt != symtab_buffer.len) return error.InputOutput; |
| 131 | 148 | } |
| 132 | 149 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; |
| ... | ... | @@ -144,7 +161,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 144 | 161 | const buffer = try gpa.alloc(u8, cmd.datasize); |
| 145 | 162 | defer gpa.free(buffer); |
| 146 | 163 | { |
| 147 | const amt = try handle.preadAll(buffer, offset + cmd.dataoff); | |
| 164 | const amt = try handle.preadAll(buffer, self.offset + cmd.dataoff); | |
| 148 | 165 | if (amt != buffer.len) return error.InputOutput; |
| 149 | 166 | } |
| 150 | 167 | const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry)); |
| ... | ... | @@ -196,39 +213,39 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 196 | 213 | mem.sort(NlistIdx, nlists.items, self, NlistIdx.lessThan); |
| 197 | 214 | |
| 198 | 215 | if (self.hasSubsections()) { |
| 199 | try self.initSubsections(nlists.items, macho_file); | |
| 216 | try self.initSubsections(gpa, nlists.items); | |
| 200 | 217 | } else { |
| 201 | try self.initSections(nlists.items, macho_file); | |
| 218 | try self.initSections(gpa, nlists.items); | |
| 202 | 219 | } |
| 203 | 220 | |
| 204 | try self.initCstringLiterals(macho_file); | |
| 205 | try self.initFixedSizeLiterals(macho_file); | |
| 206 | try self.initPointerLiterals(macho_file); | |
| 221 | try self.initCstringLiterals(gpa, handle, macho_file); | |
| 222 | try self.initFixedSizeLiterals(gpa, macho_file); | |
| 223 | try self.initPointerLiterals(gpa, macho_file); | |
| 207 | 224 | try self.linkNlistToAtom(macho_file); |
| 208 | 225 | |
| 209 | 226 | try self.sortAtoms(macho_file); |
| 210 | try self.initSymbols(macho_file); | |
| 211 | try self.initSymbolStabs(nlists.items, macho_file); | |
| 212 | try self.initRelocs(macho_file); | |
| 227 | try self.initSymbols(gpa, macho_file); | |
| 228 | try self.initSymbolStabs(gpa, nlists.items, macho_file); | |
| 229 | try self.initRelocs(handle, cpu_arch, macho_file); | |
| 213 | 230 | |
| 214 | 231 | // Parse DWARF __TEXT,__eh_frame section |
| 215 | 232 | if (self.eh_frame_sect_index) |index| { |
| 216 | try self.initEhFrameRecords(index, macho_file); | |
| 233 | try self.initEhFrameRecords(gpa, index, handle, macho_file); | |
| 217 | 234 | } |
| 218 | 235 | |
| 219 | 236 | // Parse Apple's __LD,__compact_unwind section |
| 220 | 237 | if (self.compact_unwind_sect_index) |index| { |
| 221 | try self.initUnwindRecords(index, macho_file); | |
| 238 | try self.initUnwindRecords(gpa, index, handle, macho_file); | |
| 222 | 239 | } |
| 223 | 240 | |
| 224 | 241 | if (self.hasUnwindRecords() or self.hasEhFrameRecords()) { |
| 225 | try self.parseUnwindRecords(macho_file); | |
| 242 | try self.parseUnwindRecords(gpa, cpu_arch, macho_file); | |
| 226 | 243 | } |
| 227 | 244 | |
| 228 | 245 | if (self.platform) |platform| { |
| 229 | 246 | if (!macho_file.platform.eqlTarget(platform)) { |
| 230 | 247 | try macho_file.reportParseError2(self.index, "invalid platform: {}", .{ |
| 231 | platform.fmtTarget(macho_file.getTarget().cpu.arch), | |
| 248 | platform.fmtTarget(cpu_arch), | |
| 232 | 249 | }); |
| 233 | 250 | return error.InvalidTarget; |
| 234 | 251 | } |
| ... | ... | @@ -244,8 +261,10 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 244 | 261 | // } |
| 245 | 262 | } |
| 246 | 263 | |
| 247 | for (self.atoms.items) |atom_index| { | |
| 248 | const atom = macho_file.getAtom(atom_index).?; | |
| 264 | try self.parseDebugInfo(macho_file); | |
| 265 | ||
| 266 | for (self.getAtoms()) |atom_index| { | |
| 267 | const atom = self.getAtom(atom_index) orelse continue; | |
| 249 | 268 | const isec = atom.getInputSection(macho_file); |
| 250 | 269 | if (mem.eql(u8, isec.sectName(), "__eh_frame") or |
| 251 | 270 | mem.eql(u8, isec.sectName(), "__compact_unwind") or |
| ... | ... | @@ -274,10 +293,9 @@ pub fn isPtrLiteral(sect: macho.section_64) bool { |
| 274 | 293 | return sect.type() == macho.S_LITERAL_POINTERS; |
| 275 | 294 | } |
| 276 | 295 | |
| 277 | fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { | |
| 296 | fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void { | |
| 278 | 297 | const tracy = trace(@src()); |
| 279 | 298 | defer tracy.end(); |
| 280 | const gpa = macho_file.base.comp.gpa; | |
| 281 | 299 | const slice = self.sections.slice(); |
| 282 | 300 | for (slice.items(.header), slice.items(.subsections), 0..) |sect, *subsections, n_sect| { |
| 283 | 301 | if (isCstringLiteral(sect)) continue; |
| ... | ... | @@ -292,17 +310,18 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 292 | 310 | } else nlists.len; |
| 293 | 311 | |
| 294 | 312 | if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) { |
| 295 | const name = try std.fmt.allocPrintZ(gpa, "{s}${s}", .{ sect.segName(), sect.sectName() }); | |
| 296 | defer gpa.free(name); | |
| 313 | const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() }); | |
| 314 | defer allocator.free(name); | |
| 297 | 315 | const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr; |
| 298 | const atom_index = try self.addAtom(.{ | |
| 299 | .name = try self.addString(gpa, name), | |
| 316 | const atom_index = try self.addAtom(allocator, .{ | |
| 317 | .name = try self.addString(allocator, name), | |
| 300 | 318 | .n_sect = @intCast(n_sect), |
| 301 | 319 | .off = 0, |
| 302 | 320 | .size = size, |
| 303 | 321 | .alignment = sect.@"align", |
| 304 | }, macho_file); | |
| 305 | try subsections.append(gpa, .{ | |
| 322 | }); | |
| 323 | try self.atoms_indexes.append(allocator, atom_index); | |
| 324 | try subsections.append(allocator, .{ | |
| 306 | 325 | .atom = atom_index, |
| 307 | 326 | .off = 0, |
| 308 | 327 | }); |
| ... | ... | @@ -325,14 +344,15 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 325 | 344 | @min(@ctz(nlist.nlist.n_value), sect.@"align") |
| 326 | 345 | else |
| 327 | 346 | sect.@"align"; |
| 328 | const atom_index = try self.addAtom(.{ | |
| 347 | const atom_index = try self.addAtom(allocator, .{ | |
| 329 | 348 | .name = nlist.nlist.n_strx, |
| 330 | 349 | .n_sect = @intCast(n_sect), |
| 331 | 350 | .off = nlist.nlist.n_value - sect.addr, |
| 332 | 351 | .size = size, |
| 333 | 352 | .alignment = alignment, |
| 334 | }, macho_file); | |
| 335 | try subsections.append(gpa, .{ | |
| 353 | }); | |
| 354 | try self.atoms_indexes.append(allocator, atom_index); | |
| 355 | try subsections.append(allocator, .{ | |
| 336 | 356 | .atom = atom_index, |
| 337 | 357 | .off = nlist.nlist.n_value - sect.addr, |
| 338 | 358 | }); |
| ... | ... | @@ -344,30 +364,31 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 344 | 364 | } |
| 345 | 365 | } |
| 346 | 366 | |
| 347 | fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void { | |
| 367 | fn initSections(self: *Object, allocator: Allocator, nlists: anytype) !void { | |
| 348 | 368 | const tracy = trace(@src()); |
| 349 | 369 | defer tracy.end(); |
| 350 | const gpa = macho_file.base.comp.gpa; | |
| 351 | 370 | const slice = self.sections.slice(); |
| 352 | 371 | |
| 353 | try self.atoms.ensureUnusedCapacity(gpa, self.sections.items(.header).len); | |
| 372 | try self.atoms.ensureUnusedCapacity(allocator, self.sections.items(.header).len); | |
| 373 | try self.atoms_indexes.ensureUnusedCapacity(allocator, self.sections.items(.header).len); | |
| 354 | 374 | |
| 355 | 375 | for (slice.items(.header), 0..) |sect, n_sect| { |
| 356 | 376 | if (isCstringLiteral(sect)) continue; |
| 357 | 377 | if (isFixedSizeLiteral(sect)) continue; |
| 358 | 378 | if (isPtrLiteral(sect)) continue; |
| 359 | 379 | |
| 360 | const name = try std.fmt.allocPrintZ(gpa, "{s}${s}", .{ sect.segName(), sect.sectName() }); | |
| 361 | defer gpa.free(name); | |
| 380 | const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() }); | |
| 381 | defer allocator.free(name); | |
| 362 | 382 | |
| 363 | const atom_index = try self.addAtom(.{ | |
| 364 | .name = try self.addString(gpa, name), | |
| 383 | const atom_index = try self.addAtom(allocator, .{ | |
| 384 | .name = try self.addString(allocator, name), | |
| 365 | 385 | .n_sect = @intCast(n_sect), |
| 366 | 386 | .off = 0, |
| 367 | 387 | .size = sect.size, |
| 368 | 388 | .alignment = sect.@"align", |
| 369 | }, macho_file); | |
| 370 | try slice.items(.subsections)[n_sect].append(gpa, .{ .atom = atom_index, .off = 0 }); | |
| 389 | }); | |
| 390 | try self.atoms_indexes.append(allocator, atom_index); | |
| 391 | try slice.items(.subsections)[n_sect].append(allocator, .{ .atom = atom_index, .off = 0 }); | |
| 371 | 392 | |
| 372 | 393 | const nlist_start = for (nlists, 0..) |nlist, i| { |
| 373 | 394 | if (nlist.nlist.n_sect - 1 == n_sect) break i; |
| ... | ... | @@ -396,21 +417,25 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 396 | 417 | } |
| 397 | 418 | } |
| 398 | 419 | |
| 399 | fn initCstringLiterals(self: *Object, macho_file: *MachO) !void { | |
| 420 | fn initCstringLiterals(self: *Object, allocator: Allocator, file: File.Handle, macho_file: *MachO) !void { | |
| 400 | 421 | const tracy = trace(@src()); |
| 401 | 422 | defer tracy.end(); |
| 402 | 423 | |
| 403 | const gpa = macho_file.base.comp.gpa; | |
| 404 | 424 | const slice = self.sections.slice(); |
| 405 | 425 | |
| 406 | 426 | for (slice.items(.header), 0..) |sect, n_sect| { |
| 407 | 427 | if (!isCstringLiteral(sect)) continue; |
| 408 | 428 | |
| 409 | const data = try self.getSectionData(@intCast(n_sect), macho_file); | |
| 410 | defer gpa.free(data); | |
| 429 | const sect_size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 430 | const data = try allocator.alloc(u8, sect_size); | |
| 431 | defer allocator.free(data); | |
| 432 | const amt = try file.preadAll(data, sect.offset + self.offset); | |
| 433 | if (amt != data.len) return error.InputOutput; | |
| 411 | 434 | |
| 435 | var count: u32 = 0; | |
| 412 | 436 | var start: u32 = 0; |
| 413 | 437 | while (start < data.len) { |
| 438 | defer count += 1; | |
| 414 | 439 | var end = start; |
| 415 | 440 | while (end < data.len - 1 and data[end] != 0) : (end += 1) {} |
| 416 | 441 | if (data[end] != 0) { |
| ... | ... | @@ -423,32 +448,52 @@ fn initCstringLiterals(self: *Object, macho_file: *MachO) !void { |
| 423 | 448 | } |
| 424 | 449 | end += 1; |
| 425 | 450 | |
| 426 | const atom_index = try self.addAtom(.{ | |
| 427 | .name = 0, | |
| 451 | const name = try std.fmt.allocPrintZ(allocator, "l._str{d}", .{count}); | |
| 452 | defer allocator.free(name); | |
| 453 | const name_str = try self.addString(allocator, name); | |
| 454 | ||
| 455 | const atom_index = try self.addAtom(allocator, .{ | |
| 456 | .name = name_str, | |
| 428 | 457 | .n_sect = @intCast(n_sect), |
| 429 | 458 | .off = start, |
| 430 | 459 | .size = end - start, |
| 431 | 460 | .alignment = sect.@"align", |
| 432 | }, macho_file); | |
| 433 | try slice.items(.subsections)[n_sect].append(gpa, .{ | |
| 461 | }); | |
| 462 | try self.atoms_indexes.append(allocator, atom_index); | |
| 463 | try slice.items(.subsections)[n_sect].append(allocator, .{ | |
| 434 | 464 | .atom = atom_index, |
| 435 | 465 | .off = start, |
| 436 | 466 | }); |
| 437 | 467 | |
| 468 | const atom = self.getAtom(atom_index).?; | |
| 469 | const nlist_index: u32 = @intCast(try self.symtab.addOne(allocator)); | |
| 470 | self.symtab.set(nlist_index, .{ | |
| 471 | .nlist = .{ | |
| 472 | .n_strx = name_str, | |
| 473 | .n_type = macho.N_SECT, | |
| 474 | .n_sect = @intCast(atom.n_sect + 1), | |
| 475 | .n_desc = 0, | |
| 476 | .n_value = atom.getInputAddress(macho_file), | |
| 477 | }, | |
| 478 | .size = atom.size, | |
| 479 | .atom = atom_index, | |
| 480 | }); | |
| 481 | atom.addExtra(.{ .literal_symbol_index = nlist_index }, macho_file); | |
| 482 | ||
| 438 | 483 | start = end; |
| 439 | 484 | } |
| 440 | 485 | } |
| 441 | 486 | } |
| 442 | 487 | |
| 443 | fn initFixedSizeLiterals(self: *Object, macho_file: *MachO) !void { | |
| 488 | fn initFixedSizeLiterals(self: *Object, allocator: Allocator, macho_file: *MachO) !void { | |
| 444 | 489 | const tracy = trace(@src()); |
| 445 | 490 | defer tracy.end(); |
| 446 | 491 | |
| 447 | const gpa = macho_file.base.comp.gpa; | |
| 448 | 492 | const slice = self.sections.slice(); |
| 449 | 493 | |
| 450 | 494 | for (slice.items(.header), 0..) |sect, n_sect| { |
| 451 | 495 | if (!isFixedSizeLiteral(sect)) continue; |
| 496 | ||
| 452 | 497 | const rec_size: u8 = switch (sect.type()) { |
| 453 | 498 | macho.S_4BYTE_LITERALS => 4, |
| 454 | 499 | macho.S_8BYTE_LITERALS => 8, |
| ... | ... | @@ -463,28 +508,52 @@ fn initFixedSizeLiterals(self: *Object, macho_file: *MachO) !void { |
| 463 | 508 | ); |
| 464 | 509 | return error.MalformedObject; |
| 465 | 510 | } |
| 511 | ||
| 466 | 512 | var pos: u32 = 0; |
| 467 | while (pos < sect.size) : (pos += rec_size) { | |
| 468 | const atom_index = try self.addAtom(.{ | |
| 469 | .name = 0, | |
| 513 | var count: u32 = 0; | |
| 514 | while (pos < sect.size) : ({ | |
| 515 | pos += rec_size; | |
| 516 | count += 1; | |
| 517 | }) { | |
| 518 | const name = try std.fmt.allocPrintZ(allocator, "l._literal{d}", .{count}); | |
| 519 | defer allocator.free(name); | |
| 520 | const name_str = try self.addString(allocator, name); | |
| 521 | ||
| 522 | const atom_index = try self.addAtom(allocator, .{ | |
| 523 | .name = name_str, | |
| 470 | 524 | .n_sect = @intCast(n_sect), |
| 471 | 525 | .off = pos, |
| 472 | 526 | .size = rec_size, |
| 473 | 527 | .alignment = sect.@"align", |
| 474 | }, macho_file); | |
| 475 | try slice.items(.subsections)[n_sect].append(gpa, .{ | |
| 528 | }); | |
| 529 | try self.atoms_indexes.append(allocator, atom_index); | |
| 530 | try slice.items(.subsections)[n_sect].append(allocator, .{ | |
| 476 | 531 | .atom = atom_index, |
| 477 | 532 | .off = pos, |
| 478 | 533 | }); |
| 534 | ||
| 535 | const atom = self.getAtom(atom_index).?; | |
| 536 | const nlist_index: u32 = @intCast(try self.symtab.addOne(allocator)); | |
| 537 | self.symtab.set(nlist_index, .{ | |
| 538 | .nlist = .{ | |
| 539 | .n_strx = name_str, | |
| 540 | .n_type = macho.N_SECT, | |
| 541 | .n_sect = @intCast(atom.n_sect + 1), | |
| 542 | .n_desc = 0, | |
| 543 | .n_value = atom.getInputAddress(macho_file), | |
| 544 | }, | |
| 545 | .size = atom.size, | |
| 546 | .atom = atom_index, | |
| 547 | }); | |
| 548 | atom.addExtra(.{ .literal_symbol_index = nlist_index }, macho_file); | |
| 479 | 549 | } |
| 480 | 550 | } |
| 481 | 551 | } |
| 482 | 552 | |
| 483 | fn initPointerLiterals(self: *Object, macho_file: *MachO) !void { | |
| 553 | fn initPointerLiterals(self: *Object, allocator: Allocator, macho_file: *MachO) !void { | |
| 484 | 554 | const tracy = trace(@src()); |
| 485 | 555 | defer tracy.end(); |
| 486 | 556 | |
| 487 | const gpa = macho_file.base.comp.gpa; | |
| 488 | 557 | const slice = self.sections.slice(); |
| 489 | 558 | |
| 490 | 559 | for (slice.items(.header), 0..) |sect, n_sect| { |
| ... | ... | @@ -503,134 +572,171 @@ fn initPointerLiterals(self: *Object, macho_file: *MachO) !void { |
| 503 | 572 | |
| 504 | 573 | for (0..num_ptrs) |i| { |
| 505 | 574 | const pos: u32 = @as(u32, @intCast(i)) * rec_size; |
| 506 | const atom_index = try self.addAtom(.{ | |
| 507 | .name = 0, | |
| 575 | ||
| 576 | const name = try std.fmt.allocPrintZ(allocator, "l._ptr{d}", .{i}); | |
| 577 | defer allocator.free(name); | |
| 578 | const name_str = try self.addString(allocator, name); | |
| 579 | ||
| 580 | const atom_index = try self.addAtom(allocator, .{ | |
| 581 | .name = name_str, | |
| 508 | 582 | .n_sect = @intCast(n_sect), |
| 509 | 583 | .off = pos, |
| 510 | 584 | .size = rec_size, |
| 511 | 585 | .alignment = sect.@"align", |
| 512 | }, macho_file); | |
| 513 | try slice.items(.subsections)[n_sect].append(gpa, .{ | |
| 586 | }); | |
| 587 | try self.atoms_indexes.append(allocator, atom_index); | |
| 588 | try slice.items(.subsections)[n_sect].append(allocator, .{ | |
| 514 | 589 | .atom = atom_index, |
| 515 | 590 | .off = pos, |
| 516 | 591 | }); |
| 592 | ||
| 593 | const atom = self.getAtom(atom_index).?; | |
| 594 | const nlist_index: u32 = @intCast(try self.symtab.addOne(allocator)); | |
| 595 | self.symtab.set(nlist_index, .{ | |
| 596 | .nlist = .{ | |
| 597 | .n_strx = name_str, | |
| 598 | .n_type = macho.N_SECT, | |
| 599 | .n_sect = @intCast(atom.n_sect + 1), | |
| 600 | .n_desc = 0, | |
| 601 | .n_value = atom.getInputAddress(macho_file), | |
| 602 | }, | |
| 603 | .size = atom.size, | |
| 604 | .atom = atom_index, | |
| 605 | }); | |
| 606 | atom.addExtra(.{ .literal_symbol_index = nlist_index }, macho_file); | |
| 517 | 607 | } |
| 518 | 608 | } |
| 519 | 609 | } |
| 520 | 610 | |
| 521 | pub fn resolveLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) !void { | |
| 611 | pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO) !void { | |
| 612 | const tracy = trace(@src()); | |
| 613 | defer tracy.end(); | |
| 614 | ||
| 522 | 615 | const gpa = macho_file.base.comp.gpa; |
| 616 | const file = macho_file.getFileHandle(self.file_handle); | |
| 523 | 617 | |
| 524 | 618 | var buffer = std.ArrayList(u8).init(gpa); |
| 525 | 619 | defer buffer.deinit(); |
| 526 | 620 | |
| 621 | var sections_data = std.AutoHashMap(u32, []const u8).init(gpa); | |
| 622 | try sections_data.ensureTotalCapacity(@intCast(self.sections.items(.header).len)); | |
| 623 | defer { | |
| 624 | var it = sections_data.iterator(); | |
| 625 | while (it.next()) |entry| { | |
| 626 | gpa.free(entry.value_ptr.*); | |
| 627 | } | |
| 628 | sections_data.deinit(); | |
| 629 | } | |
| 630 | ||
| 527 | 631 | const slice = self.sections.slice(); |
| 528 | for (slice.items(.header), slice.items(.subsections), 0..) |header, subs, n_sect| { | |
| 632 | for (slice.items(.header), slice.items(.subsections)) |header, subs| { | |
| 529 | 633 | if (isCstringLiteral(header) or isFixedSizeLiteral(header)) { |
| 530 | const data = try self.getSectionData(@intCast(n_sect), macho_file); | |
| 634 | const sect_size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 635 | const data = try gpa.alloc(u8, sect_size); | |
| 531 | 636 | defer gpa.free(data); |
| 637 | const amt = try file.preadAll(data, header.offset + self.offset); | |
| 638 | if (amt != data.len) return error.InputOutput; | |
| 532 | 639 | |
| 533 | 640 | for (subs.items) |sub| { |
| 534 | const atom = macho_file.getAtom(sub.atom).?; | |
| 641 | const atom = self.getAtom(sub.atom).?; | |
| 535 | 642 | const atom_off = math.cast(usize, atom.off) orelse return error.Overflow; |
| 536 | 643 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 537 | 644 | const atom_data = data[atom_off..][0..atom_size]; |
| 538 | 645 | const res = try lp.insert(gpa, header.type(), atom_data); |
| 539 | 646 | if (!res.found_existing) { |
| 540 | res.atom.* = sub.atom; | |
| 647 | res.ref.* = .{ .index = atom.getExtra(macho_file).literal_symbol_index, .file = self.index }; | |
| 648 | } else { | |
| 649 | const lp_sym = lp.getSymbol(res.index, macho_file); | |
| 650 | const lp_atom = lp_sym.getAtom(macho_file).?; | |
| 651 | lp_atom.alignment = lp_atom.alignment.max(atom.alignment); | |
| 652 | atom.flags.alive = false; | |
| 541 | 653 | } |
| 542 | atom.flags.literal_pool = true; | |
| 543 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); | |
| 654 | atom.addExtra(.{ .literal_pool_index = res.index }, macho_file); | |
| 544 | 655 | } |
| 545 | 656 | } else if (isPtrLiteral(header)) { |
| 546 | 657 | for (subs.items) |sub| { |
| 547 | const atom = macho_file.getAtom(sub.atom).?; | |
| 658 | const atom = self.getAtom(sub.atom).?; | |
| 548 | 659 | const relocs = atom.getRelocs(macho_file); |
| 549 | 660 | assert(relocs.len == 1); |
| 550 | 661 | const rel = relocs[0]; |
| 551 | 662 | const target = switch (rel.tag) { |
| 552 | .local => rel.target, | |
| 553 | .@"extern" => rel.getTargetSymbol(macho_file).atom, | |
| 663 | .local => rel.getTargetAtom(atom.*, macho_file), | |
| 664 | .@"extern" => rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?, | |
| 554 | 665 | }; |
| 555 | 666 | const addend = math.cast(u32, rel.addend) orelse return error.Overflow; |
| 556 | const target_atom = macho_file.getAtom(target).?; | |
| 557 | const target_atom_size = math.cast(usize, target_atom.size) orelse return error.Overflow; | |
| 558 | try buffer.ensureUnusedCapacity(target_atom_size); | |
| 559 | buffer.resize(target_atom_size) catch unreachable; | |
| 560 | try target_atom.getData(macho_file, buffer.items); | |
| 667 | const target_size = math.cast(usize, target.size) orelse return error.Overflow; | |
| 668 | try buffer.ensureUnusedCapacity(target_size); | |
| 669 | buffer.resize(target_size) catch unreachable; | |
| 670 | const gop = try sections_data.getOrPut(target.n_sect); | |
| 671 | if (!gop.found_existing) { | |
| 672 | const target_sect = slice.items(.header)[target.n_sect]; | |
| 673 | const target_sect_size = math.cast(usize, target_sect.size) orelse return error.Overflow; | |
| 674 | const data = try gpa.alloc(u8, target_sect_size); | |
| 675 | const amt = try file.preadAll(data, target_sect.offset + self.offset); | |
| 676 | if (amt != data.len) return error.InputOutput; | |
| 677 | gop.value_ptr.* = data; | |
| 678 | } | |
| 679 | const data = gop.value_ptr.*; | |
| 680 | const target_off = math.cast(usize, target.off) orelse return error.Overflow; | |
| 681 | @memcpy(buffer.items, data[target_off..][0..target_size]); | |
| 561 | 682 | const res = try lp.insert(gpa, header.type(), buffer.items[addend..]); |
| 562 | 683 | buffer.clearRetainingCapacity(); |
| 563 | 684 | if (!res.found_existing) { |
| 564 | res.atom.* = sub.atom; | |
| 685 | res.ref.* = .{ .index = atom.getExtra(macho_file).literal_symbol_index, .file = self.index }; | |
| 686 | } else { | |
| 687 | const lp_sym = lp.getSymbol(res.index, macho_file); | |
| 688 | const lp_atom = lp_sym.getAtom(macho_file).?; | |
| 689 | lp_atom.alignment = lp_atom.alignment.max(atom.alignment); | |
| 690 | atom.flags.alive = false; | |
| 565 | 691 | } |
| 566 | atom.flags.literal_pool = true; | |
| 567 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); | |
| 692 | atom.addExtra(.{ .literal_pool_index = res.index }, macho_file); | |
| 568 | 693 | } |
| 569 | 694 | } |
| 570 | 695 | } |
| 571 | 696 | } |
| 572 | 697 | |
| 573 | pub fn dedupLiterals(self: Object, lp: MachO.LiteralPool, macho_file: *MachO) void { | |
| 574 | for (self.atoms.items) |atom_index| { | |
| 575 | const atom = macho_file.getAtom(atom_index) orelse continue; | |
| 698 | pub fn dedupLiterals(self: *Object, lp: MachO.LiteralPool, macho_file: *MachO) void { | |
| 699 | const tracy = trace(@src()); | |
| 700 | defer tracy.end(); | |
| 701 | ||
| 702 | for (self.getAtoms()) |atom_index| { | |
| 703 | const atom = self.getAtom(atom_index) orelse continue; | |
| 576 | 704 | if (!atom.flags.alive) continue; |
| 577 | if (!atom.flags.relocs) continue; | |
| 578 | 705 | |
| 579 | 706 | const relocs = blk: { |
| 580 | const extra = atom.getExtra(macho_file).?; | |
| 707 | const extra = atom.getExtra(macho_file); | |
| 581 | 708 | const relocs = self.sections.items(.relocs)[atom.n_sect].items; |
| 582 | 709 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; |
| 583 | 710 | }; |
| 584 | for (relocs) |*rel| switch (rel.tag) { | |
| 585 | .local => { | |
| 586 | const target = macho_file.getAtom(rel.target).?; | |
| 587 | if (target.getLiteralPoolIndex(macho_file)) |lp_index| { | |
| 588 | const lp_atom = lp.getAtom(lp_index, macho_file); | |
| 589 | if (target.atom_index != lp_atom.atom_index) { | |
| 590 | lp_atom.alignment = lp_atom.alignment.max(target.alignment); | |
| 591 | target.flags.alive = false; | |
| 592 | rel.target = lp_atom.atom_index; | |
| 593 | } | |
| 594 | } | |
| 595 | }, | |
| 596 | .@"extern" => { | |
| 597 | const target_sym = rel.getTargetSymbol(macho_file); | |
| 598 | if (target_sym.getAtom(macho_file)) |target_atom| { | |
| 599 | if (target_atom.getLiteralPoolIndex(macho_file)) |lp_index| { | |
| 600 | const lp_atom = lp.getAtom(lp_index, macho_file); | |
| 601 | if (target_atom.atom_index != lp_atom.atom_index) { | |
| 602 | lp_atom.alignment = lp_atom.alignment.max(target_atom.alignment); | |
| 603 | target_atom.flags.alive = false; | |
| 604 | target_sym.atom = lp_atom.atom_index; | |
| 605 | } | |
| 606 | } | |
| 607 | } | |
| 608 | }, | |
| 609 | }; | |
| 711 | for (relocs) |*rel| { | |
| 712 | if (rel.tag != .@"extern") continue; | |
| 713 | const target_sym_ref = rel.getTargetSymbolRef(atom.*, macho_file); | |
| 714 | const file = target_sym_ref.getFile(macho_file) orelse continue; | |
| 715 | if (file.getIndex() != self.index) continue; | |
| 716 | const target_sym = target_sym_ref.getSymbol(macho_file).?; | |
| 717 | const target_atom = target_sym.getAtom(macho_file) orelse continue; | |
| 718 | const isec = target_atom.getInputSection(macho_file); | |
| 719 | if (!Object.isCstringLiteral(isec) and !Object.isFixedSizeLiteral(isec) and !Object.isPtrLiteral(isec)) continue; | |
| 720 | const lp_index = target_atom.getExtra(macho_file).literal_pool_index; | |
| 721 | const lp_sym = lp.getSymbol(lp_index, macho_file); | |
| 722 | const lp_atom_ref = lp_sym.atom_ref; | |
| 723 | if (target_atom.atom_index != lp_atom_ref.index or target_atom.file != lp_atom_ref.file) { | |
| 724 | target_sym.atom_ref = lp_atom_ref; | |
| 725 | } | |
| 726 | } | |
| 610 | 727 | } |
| 611 | } | |
| 612 | 728 | |
| 613 | const AddAtomArgs = struct { | |
| 614 | name: u32, | |
| 615 | n_sect: u8, | |
| 616 | off: u64, | |
| 617 | size: u64, | |
| 618 | alignment: u32, | |
| 619 | }; | |
| 620 | ||
| 621 | fn addAtom(self: *Object, args: AddAtomArgs, macho_file: *MachO) !Atom.Index { | |
| 622 | const gpa = macho_file.base.comp.gpa; | |
| 623 | const atom_index = try macho_file.addAtom(); | |
| 624 | const atom = macho_file.getAtom(atom_index).?; | |
| 625 | atom.file = self.index; | |
| 626 | atom.atom_index = atom_index; | |
| 627 | atom.name = args.name; | |
| 628 | atom.n_sect = args.n_sect; | |
| 629 | atom.size = args.size; | |
| 630 | atom.alignment = Atom.Alignment.fromLog2Units(args.alignment); | |
| 631 | atom.off = args.off; | |
| 632 | try self.atoms.append(gpa, atom_index); | |
| 633 | return atom_index; | |
| 729 | for (self.symbols.items) |*sym| { | |
| 730 | const atom = sym.getAtom(macho_file) orelse continue; | |
| 731 | const isec = atom.getInputSection(macho_file); | |
| 732 | if (!Object.isCstringLiteral(isec) and !Object.isFixedSizeLiteral(isec) and !Object.isPtrLiteral(isec)) continue; | |
| 733 | const lp_index = atom.getExtra(macho_file).literal_pool_index; | |
| 734 | const lp_sym = lp.getSymbol(lp_index, macho_file); | |
| 735 | const lp_atom_ref = lp_sym.atom_ref; | |
| 736 | if (atom.atom_index != lp_atom_ref.index or self.index != lp_atom_ref.file) { | |
| 737 | sym.atom_ref = lp_atom_ref; | |
| 738 | } | |
| 739 | } | |
| 634 | 740 | } |
| 635 | 741 | |
| 636 | 742 | pub fn findAtom(self: Object, addr: u64) ?Atom.Index { |
| ... | ... | @@ -702,55 +808,61 @@ fn linkNlistToAtom(self: *Object, macho_file: *MachO) !void { |
| 702 | 808 | } |
| 703 | 809 | } |
| 704 | 810 | |
| 705 | fn initSymbols(self: *Object, macho_file: *MachO) !void { | |
| 811 | fn initSymbols(self: *Object, allocator: Allocator, macho_file: *MachO) !void { | |
| 706 | 812 | const tracy = trace(@src()); |
| 707 | 813 | defer tracy.end(); |
| 708 | const gpa = macho_file.base.comp.gpa; | |
| 814 | ||
| 709 | 815 | const slice = self.symtab.slice(); |
| 816 | const nsyms = slice.items(.nlist).len; | |
| 710 | 817 | |
| 711 | try self.symbols.ensureUnusedCapacity(gpa, slice.items(.nlist).len); | |
| 818 | try self.symbols.ensureTotalCapacityPrecise(allocator, nsyms); | |
| 819 | try self.symbols_extra.ensureTotalCapacityPrecise(allocator, nsyms * @sizeOf(Symbol.Extra)); | |
| 820 | try self.globals.ensureTotalCapacityPrecise(allocator, nsyms); | |
| 821 | self.globals.resize(allocator, nsyms) catch unreachable; | |
| 822 | @memset(self.globals.items, 0); | |
| 712 | 823 | |
| 713 | 824 | for (slice.items(.nlist), slice.items(.atom), 0..) |nlist, atom_index, i| { |
| 714 | if (nlist.ext()) { | |
| 715 | const name = self.getString(nlist.n_strx); | |
| 716 | const off = try macho_file.strings.insert(gpa, name); | |
| 717 | const gop = try macho_file.getOrCreateGlobal(off); | |
| 718 | self.symbols.addOneAssumeCapacity().* = gop.index; | |
| 719 | if (nlist.undf() and nlist.weakRef()) { | |
| 720 | macho_file.getSymbol(gop.index).flags.weak_ref = true; | |
| 721 | } | |
| 722 | continue; | |
| 723 | } | |
| 724 | ||
| 725 | const index = try macho_file.addSymbol(); | |
| 726 | self.symbols.appendAssumeCapacity(index); | |
| 727 | const symbol = macho_file.getSymbol(index); | |
| 728 | symbol.* = .{ | |
| 729 | .value = nlist.n_value, | |
| 730 | .name = nlist.n_strx, | |
| 731 | .nlist_idx = @intCast(i), | |
| 732 | .atom = 0, | |
| 733 | .file = self.index, | |
| 734 | }; | |
| 735 | ||
| 736 | if (macho_file.getAtom(atom_index)) |atom| { | |
| 825 | const index = self.addSymbolAssumeCapacity(); | |
| 826 | const symbol = &self.symbols.items[index]; | |
| 827 | symbol.value = nlist.n_value; | |
| 828 | symbol.name = nlist.n_strx; | |
| 829 | symbol.nlist_idx = @intCast(i); | |
| 830 | symbol.extra = self.addSymbolExtraAssumeCapacity(.{}); | |
| 831 | ||
| 832 | if (self.getAtom(atom_index)) |atom| { | |
| 737 | 833 | assert(!nlist.abs()); |
| 738 | 834 | symbol.value -= atom.getInputAddress(macho_file); |
| 739 | symbol.atom = atom_index; | |
| 835 | symbol.atom_ref = .{ .index = atom_index, .file = self.index }; | |
| 740 | 836 | } |
| 741 | 837 | |
| 838 | symbol.flags.weak = nlist.weakDef(); | |
| 742 | 839 | symbol.flags.abs = nlist.abs(); |
| 840 | symbol.flags.tentative = nlist.tentative(); | |
| 743 | 841 | symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip(); |
| 842 | symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0; | |
| 843 | symbol.flags.interposable = false; | |
| 844 | // TODO | |
| 845 | // symbol.flags.interposable = nlist.ext() and (nlist.sect() or nlist.abs()) and macho_file.base.isDynLib() and macho_file.options.namespace == .flat and !nlist.pext(); | |
| 744 | 846 | |
| 745 | 847 | if (nlist.sect() and |
| 746 | 848 | self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES) |
| 747 | 849 | { |
| 748 | 850 | symbol.flags.tlv = true; |
| 749 | 851 | } |
| 852 | ||
| 853 | if (nlist.ext()) { | |
| 854 | if (nlist.undf()) { | |
| 855 | symbol.flags.weak_ref = nlist.weakRef(); | |
| 856 | } else if (nlist.pext() or (nlist.weakDef() and nlist.weakRef()) or self.hidden) { | |
| 857 | symbol.visibility = .hidden; | |
| 858 | } else { | |
| 859 | symbol.visibility = .global; | |
| 860 | } | |
| 861 | } | |
| 750 | 862 | } |
| 751 | 863 | } |
| 752 | 864 | |
| 753 | fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { | |
| 865 | fn initSymbolStabs(self: *Object, allocator: Allocator, nlists: anytype, macho_file: *MachO) !void { | |
| 754 | 866 | const tracy = trace(@src()); |
| 755 | 867 | defer tracy.end(); |
| 756 | 868 | |
| ... | ... | @@ -761,7 +873,7 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 761 | 873 | fn find(fs: @This(), addr: u64) ?Symbol.Index { |
| 762 | 874 | // TODO binary search since we have the list sorted |
| 763 | 875 | for (fs.entries) |nlist| { |
| 764 | if (nlist.nlist.n_value == addr) return fs.ctx.symbols.items[nlist.idx]; | |
| 876 | if (nlist.nlist.n_value == addr) return @intCast(nlist.idx); | |
| 765 | 877 | } |
| 766 | 878 | return null; |
| 767 | 879 | } |
| ... | ... | @@ -776,14 +888,13 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 776 | 888 | |
| 777 | 889 | if (start == end) return; |
| 778 | 890 | |
| 779 | const gpa = macho_file.base.comp.gpa; | |
| 780 | 891 | const syms = self.symtab.items(.nlist); |
| 781 | 892 | const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists }; |
| 782 | 893 | |
| 783 | 894 | // We need to cache nlists by name so that we can properly resolve local N_GSYM stabs. |
| 784 | 895 | // What happens is `ld -r` will emit an N_GSYM stab for a symbol that may be either an |
| 785 | 896 | // external or private external. |
| 786 | var addr_lookup = std.StringHashMap(u64).init(gpa); | |
| 897 | var addr_lookup = std.StringHashMap(u64).init(allocator); | |
| 787 | 898 | defer addr_lookup.deinit(); |
| 788 | 899 | for (syms) |sym| { |
| 789 | 900 | if (sym.sect() and (sym.ext() or sym.pext())) { |
| ... | ... | @@ -813,17 +924,17 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 813 | 924 | switch (nlist.n_type) { |
| 814 | 925 | macho.N_BNSYM => { |
| 815 | 926 | stab.is_func = true; |
| 816 | stab.symbol = sym_lookup.find(nlist.n_value); | |
| 927 | stab.index = sym_lookup.find(nlist.n_value); | |
| 817 | 928 | // TODO validate |
| 818 | 929 | i += 3; |
| 819 | 930 | }, |
| 820 | 931 | macho.N_GSYM => { |
| 821 | 932 | stab.is_func = false; |
| 822 | stab.symbol = sym_lookup.find(addr_lookup.get(self.getString(nlist.n_strx)).?); | |
| 933 | stab.index = sym_lookup.find(addr_lookup.get(self.getString(nlist.n_strx)).?); | |
| 823 | 934 | }, |
| 824 | 935 | macho.N_STSYM => { |
| 825 | 936 | stab.is_func = false; |
| 826 | stab.symbol = sym_lookup.find(nlist.n_value); | |
| 937 | stab.index = sym_lookup.find(nlist.n_value); | |
| 827 | 938 | }, |
| 828 | 939 | else => { |
| 829 | 940 | try macho_file.reportParseError2(self.index, "unhandled symbol stab type 0x{x}", .{ |
| ... | ... | @@ -832,29 +943,35 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 832 | 943 | return error.MalformedObject; |
| 833 | 944 | }, |
| 834 | 945 | } |
| 835 | try sf.stabs.append(gpa, stab); | |
| 946 | try sf.stabs.append(allocator, stab); | |
| 836 | 947 | } |
| 837 | 948 | |
| 838 | try self.stab_files.append(gpa, sf); | |
| 949 | try self.stab_files.append(allocator, sf); | |
| 839 | 950 | } |
| 840 | 951 | } |
| 841 | 952 | |
| 842 | 953 | fn sortAtoms(self: *Object, macho_file: *MachO) !void { |
| 843 | const lessThanAtom = struct { | |
| 844 | fn lessThanAtom(ctx: *MachO, lhs: Atom.Index, rhs: Atom.Index) bool { | |
| 845 | return ctx.getAtom(lhs).?.getInputAddress(ctx) < ctx.getAtom(rhs).?.getInputAddress(ctx); | |
| 954 | const Ctx = struct { | |
| 955 | object: *Object, | |
| 956 | mfile: *MachO, | |
| 957 | ||
| 958 | fn lessThanAtom(ctx: @This(), lhs: Atom.Index, rhs: Atom.Index) bool { | |
| 959 | return ctx.object.getAtom(lhs).?.getInputAddress(ctx.mfile) < | |
| 960 | ctx.object.getAtom(rhs).?.getInputAddress(ctx.mfile); | |
| 846 | 961 | } |
| 847 | }.lessThanAtom; | |
| 848 | mem.sort(Atom.Index, self.atoms.items, macho_file, lessThanAtom); | |
| 962 | }; | |
| 963 | mem.sort(Atom.Index, self.atoms_indexes.items, Ctx{ | |
| 964 | .object = self, | |
| 965 | .mfile = macho_file, | |
| 966 | }, Ctx.lessThanAtom); | |
| 849 | 967 | } |
| 850 | 968 | |
| 851 | fn initRelocs(self: *Object, macho_file: *MachO) !void { | |
| 969 | fn initRelocs(self: *Object, file: File.Handle, cpu_arch: std.Target.Cpu.Arch, macho_file: *MachO) !void { | |
| 852 | 970 | const tracy = trace(@src()); |
| 853 | 971 | defer tracy.end(); |
| 854 | const cpu_arch = macho_file.getTarget().cpu.arch; | |
| 855 | 972 | const slice = self.sections.slice(); |
| 856 | 973 | |
| 857 | for (slice.items(.header), slice.items(.relocs), 0..) |sect, *out, n_sect| { | |
| 974 | for (slice.items(.header), slice.items(.relocs)) |sect, *out| { | |
| 858 | 975 | if (sect.nreloc == 0) continue; |
| 859 | 976 | // We skip relocs for __DWARF since even in -r mode, the linker is expected to emit |
| 860 | 977 | // debug symbol stabs in the relocatable. This made me curious why that is. For now, |
| ... | ... | @@ -863,8 +980,8 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { |
| 863 | 980 | !mem.eql(u8, sect.sectName(), "__compact_unwind")) continue; |
| 864 | 981 | |
| 865 | 982 | switch (cpu_arch) { |
| 866 | .x86_64 => try x86_64.parseRelocs(self, @intCast(n_sect), sect, out, macho_file), | |
| 867 | .aarch64 => try aarch64.parseRelocs(self, @intCast(n_sect), sect, out, macho_file), | |
| 983 | .x86_64 => try x86_64.parseRelocs(self, sect, out, file, macho_file), | |
| 984 | .aarch64 => try aarch64.parseRelocs(self, sect, out, file, macho_file), | |
| 868 | 985 | else => unreachable, |
| 869 | 986 | } |
| 870 | 987 | |
| ... | ... | @@ -876,7 +993,7 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { |
| 876 | 993 | |
| 877 | 994 | var next_reloc: u32 = 0; |
| 878 | 995 | for (subsections.items) |subsection| { |
| 879 | const atom = macho_file.getAtom(subsection.atom).?; | |
| 996 | const atom = self.getAtom(subsection.atom).?; | |
| 880 | 997 | if (!atom.flags.alive) continue; |
| 881 | 998 | if (next_reloc >= relocs.items.len) break; |
| 882 | 999 | const end_addr = atom.off + atom.size; |
| ... | ... | @@ -885,27 +1002,23 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { |
| 885 | 1002 | while (next_reloc < relocs.items.len and relocs.items[next_reloc].offset < end_addr) : (next_reloc += 1) {} |
| 886 | 1003 | |
| 887 | 1004 | const rel_count = next_reloc - rel_index; |
| 888 | try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, macho_file); | |
| 889 | atom.flags.relocs = true; | |
| 1005 | atom.addExtra(.{ .rel_index = @intCast(rel_index), .rel_count = @intCast(rel_count) }, macho_file); | |
| 890 | 1006 | } |
| 891 | 1007 | } |
| 892 | 1008 | } |
| 893 | 1009 | |
| 894 | fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | |
| 1010 | fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: File.Handle, macho_file: *MachO) !void { | |
| 895 | 1011 | const tracy = trace(@src()); |
| 896 | 1012 | defer tracy.end(); |
| 897 | const gpa = macho_file.base.comp.gpa; | |
| 898 | 1013 | const nlists = self.symtab.items(.nlist); |
| 899 | 1014 | const slice = self.sections.slice(); |
| 900 | 1015 | const sect = slice.items(.header)[sect_id]; |
| 901 | 1016 | const relocs = slice.items(.relocs)[sect_id]; |
| 902 | 1017 | |
| 903 | // TODO: read into buffer directly | |
| 904 | const data = try self.getSectionData(sect_id, macho_file); | |
| 905 | defer gpa.free(data); | |
| 906 | ||
| 907 | try self.eh_frame_data.ensureTotalCapacityPrecise(gpa, data.len); | |
| 908 | self.eh_frame_data.appendSliceAssumeCapacity(data); | |
| 1018 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 1019 | try self.eh_frame_data.resize(allocator, size); | |
| 1020 | const amt = try file.preadAll(self.eh_frame_data.items, sect.offset + self.offset); | |
| 1021 | if (amt != self.eh_frame_data.items.len) return error.InputOutput; | |
| 909 | 1022 | |
| 910 | 1023 | // Check for non-personality relocs in FDEs and apply them |
| 911 | 1024 | for (relocs.items, 0..) |rel, i| { |
| ... | ... | @@ -937,12 +1050,12 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 937 | 1050 | var it = eh_frame.Iterator{ .data = self.eh_frame_data.items }; |
| 938 | 1051 | while (try it.next()) |rec| { |
| 939 | 1052 | switch (rec.tag) { |
| 940 | .cie => try self.cies.append(gpa, .{ | |
| 1053 | .cie => try self.cies.append(allocator, .{ | |
| 941 | 1054 | .offset = rec.offset, |
| 942 | 1055 | .size = rec.size, |
| 943 | 1056 | .file = self.index, |
| 944 | 1057 | }), |
| 945 | .fde => try self.fdes.append(gpa, .{ | |
| 1058 | .fde => try self.fdes.append(allocator, .{ | |
| 946 | 1059 | .offset = rec.offset, |
| 947 | 1060 | .size = rec.size, |
| 948 | 1061 | .cie = undefined, |
| ... | ... | @@ -987,7 +1100,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 987 | 1100 | } |
| 988 | 1101 | } |
| 989 | 1102 | |
| 990 | fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | |
| 1103 | fn initUnwindRecords(self: *Object, allocator: Allocator, sect_id: u8, file: File.Handle, macho_file: *MachO) !void { | |
| 991 | 1104 | const tracy = trace(@src()); |
| 992 | 1105 | defer tracy.end(); |
| 993 | 1106 | |
| ... | ... | @@ -995,27 +1108,31 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 995 | 1108 | ctx: *const Object, |
| 996 | 1109 | |
| 997 | 1110 | fn find(fs: @This(), addr: u64) ?Symbol.Index { |
| 998 | for (fs.ctx.symbols.items, 0..) |sym_index, i| { | |
| 1111 | for (0..fs.ctx.symbols.items.len) |i| { | |
| 999 | 1112 | const nlist = fs.ctx.symtab.items(.nlist)[i]; |
| 1000 | if (nlist.ext() and nlist.n_value == addr) return sym_index; | |
| 1113 | if (nlist.ext() and nlist.n_value == addr) return @intCast(i); | |
| 1001 | 1114 | } |
| 1002 | 1115 | return null; |
| 1003 | 1116 | } |
| 1004 | 1117 | }; |
| 1005 | 1118 | |
| 1006 | const gpa = macho_file.base.comp.gpa; | |
| 1007 | const data = try self.getSectionData(sect_id, macho_file); | |
| 1008 | defer gpa.free(data); | |
| 1119 | const header = self.sections.items(.header)[sect_id]; | |
| 1120 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 1121 | const data = try allocator.alloc(u8, size); | |
| 1122 | defer allocator.free(data); | |
| 1123 | const amt = try file.preadAll(data, header.offset + self.offset); | |
| 1124 | if (amt != data.len) return error.InputOutput; | |
| 1125 | ||
| 1009 | 1126 | const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); |
| 1010 | 1127 | const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs]; |
| 1011 | 1128 | const sym_lookup = SymbolLookup{ .ctx = self }; |
| 1012 | 1129 | |
| 1013 | try self.unwind_records.resize(gpa, nrecs); | |
| 1130 | try self.unwind_records.ensureTotalCapacityPrecise(allocator, nrecs); | |
| 1131 | try self.unwind_records_indexes.ensureTotalCapacityPrecise(allocator, nrecs); | |
| 1014 | 1132 | |
| 1015 | const header = self.sections.items(.header)[sect_id]; | |
| 1016 | 1133 | const relocs = self.sections.items(.relocs)[sect_id].items; |
| 1017 | 1134 | var reloc_idx: usize = 0; |
| 1018 | for (recs, self.unwind_records.items, 0..) |rec, *out_index, rec_idx| { | |
| 1135 | for (recs, 0..) |rec, rec_idx| { | |
| 1019 | 1136 | const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry); |
| 1020 | 1137 | const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry); |
| 1021 | 1138 | const reloc_start = reloc_idx; |
| ... | ... | @@ -1023,11 +1140,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 1023 | 1140 | relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1) |
| 1024 | 1141 | {} |
| 1025 | 1142 | |
| 1026 | out_index.* = try macho_file.addUnwindRecord(); | |
| 1027 | const out = macho_file.getUnwindRecord(out_index.*); | |
| 1143 | const out_index = self.addUnwindRecordAssumeCapacity(); | |
| 1144 | self.unwind_records_indexes.appendAssumeCapacity(out_index); | |
| 1145 | const out = self.getUnwindRecord(out_index); | |
| 1028 | 1146 | out.length = rec.rangeLength; |
| 1029 | 1147 | out.enc = .{ .enc = rec.compactUnwindEncoding }; |
| 1030 | out.file = self.index; | |
| 1031 | 1148 | |
| 1032 | 1149 | for (relocs[reloc_start..reloc_idx]) |rel| { |
| 1033 | 1150 | if (rel.type != .unsigned or rel.meta.length != 3) { |
| ... | ... | @@ -1090,7 +1207,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 1090 | 1207 | } |
| 1091 | 1208 | } |
| 1092 | 1209 | |
| 1093 | fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | |
| 1210 | fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch, macho_file: *MachO) !void { | |
| 1094 | 1211 | // Synthesise missing unwind records. |
| 1095 | 1212 | // The logic here is as follows: |
| 1096 | 1213 | // 1. if an atom has unwind info record that is not DWARF, FDE is marked dead |
| ... | ... | @@ -1100,8 +1217,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1100 | 1217 | |
| 1101 | 1218 | const Superposition = struct { atom: Atom.Index, size: u64, cu: ?UnwindInfo.Record.Index = null, fde: ?Fde.Index = null }; |
| 1102 | 1219 | |
| 1103 | const gpa = macho_file.base.comp.gpa; | |
| 1104 | var superposition = std.AutoArrayHashMap(u64, Superposition).init(gpa); | |
| 1220 | var superposition = std.AutoArrayHashMap(u64, Superposition).init(allocator); | |
| 1105 | 1221 | defer superposition.deinit(); |
| 1106 | 1222 | |
| 1107 | 1223 | const slice = self.symtab.slice(); |
| ... | ... | @@ -1119,8 +1235,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1119 | 1235 | } |
| 1120 | 1236 | } |
| 1121 | 1237 | |
| 1122 | for (self.unwind_records.items) |rec_index| { | |
| 1123 | const rec = macho_file.getUnwindRecord(rec_index); | |
| 1238 | for (self.unwind_records_indexes.items) |rec_index| { | |
| 1239 | const rec = self.getUnwindRecord(rec_index); | |
| 1124 | 1240 | const atom = rec.getAtom(macho_file); |
| 1125 | 1241 | const addr = atom.getInputAddress(macho_file) + rec.atom_offset; |
| 1126 | 1242 | superposition.getPtr(addr).?.cu = rec_index; |
| ... | ... | @@ -1137,7 +1253,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1137 | 1253 | const fde = &self.fdes.items[fde_index]; |
| 1138 | 1254 | |
| 1139 | 1255 | if (meta.cu) |rec_index| { |
| 1140 | const rec = macho_file.getUnwindRecord(rec_index); | |
| 1256 | const rec = self.getUnwindRecord(rec_index); | |
| 1141 | 1257 | if (!rec.enc.isDwarf(macho_file)) { |
| 1142 | 1258 | // Mark FDE dead |
| 1143 | 1259 | fde.alive = false; |
| ... | ... | @@ -1147,15 +1263,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1147 | 1263 | } |
| 1148 | 1264 | } else { |
| 1149 | 1265 | // Synthesise new unwind info record |
| 1150 | const rec_index = try macho_file.addUnwindRecord(); | |
| 1151 | const rec = macho_file.getUnwindRecord(rec_index); | |
| 1152 | try self.unwind_records.append(gpa, rec_index); | |
| 1266 | const rec_index = try self.addUnwindRecord(allocator); | |
| 1267 | const rec = self.getUnwindRecord(rec_index); | |
| 1268 | try self.unwind_records_indexes.append(allocator, rec_index); | |
| 1153 | 1269 | rec.length = @intCast(meta.size); |
| 1154 | 1270 | rec.atom = fde.atom; |
| 1155 | 1271 | rec.atom_offset = fde.atom_offset; |
| 1156 | 1272 | rec.fde = fde_index; |
| 1157 | rec.file = fde.file; | |
| 1158 | switch (macho_file.getTarget().cpu.arch) { | |
| 1273 | switch (cpu_arch) { | |
| 1159 | 1274 | .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF), |
| 1160 | 1275 | .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF), |
| 1161 | 1276 | else => unreachable, |
| ... | ... | @@ -1163,10 +1278,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1163 | 1278 | } |
| 1164 | 1279 | } else if (meta.cu == null and meta.fde == null) { |
| 1165 | 1280 | // Create a null record |
| 1166 | const rec_index = try macho_file.addUnwindRecord(); | |
| 1167 | const rec = macho_file.getUnwindRecord(rec_index); | |
| 1168 | const atom = macho_file.getAtom(meta.atom).?; | |
| 1169 | try self.unwind_records.append(gpa, rec_index); | |
| 1281 | const rec_index = try self.addUnwindRecord(allocator); | |
| 1282 | const rec = self.getUnwindRecord(rec_index); | |
| 1283 | const atom = self.getAtom(meta.atom).?; | |
| 1284 | try self.unwind_records_indexes.append(allocator, rec_index); | |
| 1170 | 1285 | rec.length = @intCast(meta.size); |
| 1171 | 1286 | rec.atom = meta.atom; |
| 1172 | 1287 | rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file)); |
| ... | ... | @@ -1174,30 +1289,35 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1174 | 1289 | } |
| 1175 | 1290 | } |
| 1176 | 1291 | |
| 1177 | const sortFn = struct { | |
| 1178 | fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool { | |
| 1179 | const lhs = ctx.getUnwindRecord(lhs_index); | |
| 1180 | const rhs = ctx.getUnwindRecord(rhs_index); | |
| 1181 | const lhsa = lhs.getAtom(ctx); | |
| 1182 | const rhsa = rhs.getAtom(ctx); | |
| 1183 | return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset; | |
| 1292 | const SortCtx = struct { | |
| 1293 | object: *Object, | |
| 1294 | mfile: *MachO, | |
| 1295 | ||
| 1296 | fn sort(ctx: @This(), lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool { | |
| 1297 | const lhs = ctx.object.getUnwindRecord(lhs_index); | |
| 1298 | const rhs = ctx.object.getUnwindRecord(rhs_index); | |
| 1299 | const lhsa = lhs.getAtom(ctx.mfile); | |
| 1300 | const rhsa = rhs.getAtom(ctx.mfile); | |
| 1301 | return lhsa.getInputAddress(ctx.mfile) + lhs.atom_offset < rhsa.getInputAddress(ctx.mfile) + rhs.atom_offset; | |
| 1184 | 1302 | } |
| 1185 | }.sortFn; | |
| 1186 | mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn); | |
| 1303 | }; | |
| 1304 | mem.sort(UnwindInfo.Record.Index, self.unwind_records_indexes.items, SortCtx{ | |
| 1305 | .object = self, | |
| 1306 | .mfile = macho_file, | |
| 1307 | }, SortCtx.sort); | |
| 1187 | 1308 | |
| 1188 | 1309 | // Associate unwind records to atoms |
| 1189 | 1310 | var next_cu: u32 = 0; |
| 1190 | while (next_cu < self.unwind_records.items.len) { | |
| 1311 | while (next_cu < self.unwind_records_indexes.items.len) { | |
| 1191 | 1312 | const start = next_cu; |
| 1192 | const rec_index = self.unwind_records.items[start]; | |
| 1193 | const rec = macho_file.getUnwindRecord(rec_index); | |
| 1194 | while (next_cu < self.unwind_records.items.len and | |
| 1195 | macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1) | |
| 1313 | const rec_index = self.unwind_records_indexes.items[start]; | |
| 1314 | const rec = self.getUnwindRecord(rec_index); | |
| 1315 | while (next_cu < self.unwind_records_indexes.items.len and | |
| 1316 | self.getUnwindRecord(self.unwind_records_indexes.items[next_cu]).atom == rec.atom) : (next_cu += 1) | |
| 1196 | 1317 | {} |
| 1197 | 1318 | |
| 1198 | 1319 | const atom = rec.getAtom(macho_file); |
| 1199 | try atom.addExtra(.{ .unwind_index = start, .unwind_count = next_cu - start }, macho_file); | |
| 1200 | atom.flags.unwind = true; | |
| 1320 | atom.addExtra(.{ .unwind_index = start, .unwind_count = next_cu - start }, macho_file); | |
| 1201 | 1321 | } |
| 1202 | 1322 | } |
| 1203 | 1323 | |
| ... | ... | @@ -1205,7 +1325,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1205 | 1325 | /// and record that so that we can emit symbol stabs. |
| 1206 | 1326 | /// TODO in the future, we want parse debug info and debug line sections so that |
| 1207 | 1327 | /// we can provide nice error locations to the user. |
| 1208 | pub fn parseDebugInfo(self: *Object, macho_file: *MachO) !void { | |
| 1328 | fn parseDebugInfo(self: *Object, macho_file: *MachO) !void { | |
| 1209 | 1329 | const tracy = trace(@src()); |
| 1210 | 1330 | defer tracy.end(); |
| 1211 | 1331 | |
| ... | ... | @@ -1224,11 +1344,34 @@ pub fn parseDebugInfo(self: *Object, macho_file: *MachO) !void { |
| 1224 | 1344 | |
| 1225 | 1345 | if (debug_info_index == null or debug_abbrev_index == null) return; |
| 1226 | 1346 | |
| 1227 | const debug_info = try self.getSectionData(@intCast(debug_info_index.?), macho_file); | |
| 1347 | const slice = self.sections.slice(); | |
| 1348 | const file = macho_file.getFileHandle(self.file_handle); | |
| 1349 | const debug_info = blk: { | |
| 1350 | const sect = slice.items(.header)[debug_info_index.?]; | |
| 1351 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 1352 | const data = try gpa.alloc(u8, size); | |
| 1353 | const amt = try file.preadAll(data, sect.offset + self.offset); | |
| 1354 | if (amt != data.len) return error.InputOutput; | |
| 1355 | break :blk data; | |
| 1356 | }; | |
| 1228 | 1357 | defer gpa.free(debug_info); |
| 1229 | const debug_abbrev = try self.getSectionData(@intCast(debug_abbrev_index.?), macho_file); | |
| 1358 | const debug_abbrev = blk: { | |
| 1359 | const sect = slice.items(.header)[debug_abbrev_index.?]; | |
| 1360 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 1361 | const data = try gpa.alloc(u8, size); | |
| 1362 | const amt = try file.preadAll(data, sect.offset + self.offset); | |
| 1363 | if (amt != data.len) return error.InputOutput; | |
| 1364 | break :blk data; | |
| 1365 | }; | |
| 1230 | 1366 | defer gpa.free(debug_abbrev); |
| 1231 | const debug_str = if (debug_str_index) |index| try self.getSectionData(@intCast(index), macho_file) else &[0]u8{}; | |
| 1367 | const debug_str = if (debug_str_index) |sid| blk: { | |
| 1368 | const sect = slice.items(.header)[sid]; | |
| 1369 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 1370 | const data = try gpa.alloc(u8, size); | |
| 1371 | const amt = try file.preadAll(data, sect.offset + self.offset); | |
| 1372 | if (amt != data.len) return error.InputOutput; | |
| 1373 | break :blk data; | |
| 1374 | } else &[0]u8{}; | |
| 1232 | 1375 | defer gpa.free(debug_str); |
| 1233 | 1376 | |
| 1234 | 1377 | self.compile_unit = self.findCompileUnit(.{ |
| ... | ... | @@ -1334,87 +1477,55 @@ fn findCompileUnit(self: *Object, args: struct { |
| 1334 | 1477 | }; |
| 1335 | 1478 | } |
| 1336 | 1479 | |
| 1337 | pub fn resolveSymbols(self: *Object, macho_file: *MachO) void { | |
| 1480 | pub fn resolveSymbols(self: *Object, macho_file: *MachO) !void { | |
| 1338 | 1481 | const tracy = trace(@src()); |
| 1339 | 1482 | defer tracy.end(); |
| 1340 | 1483 | |
| 1341 | for (self.symbols.items, 0..) |index, i| { | |
| 1342 | const nlist_idx = @as(Symbol.Index, @intCast(i)); | |
| 1343 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | |
| 1344 | const atom_index = self.symtab.items(.atom)[nlist_idx]; | |
| 1484 | const gpa = macho_file.base.comp.gpa; | |
| 1345 | 1485 | |
| 1486 | for (self.symtab.items(.nlist), self.symtab.items(.atom), self.globals.items, 0..) |nlist, atom_index, *global, i| { | |
| 1346 | 1487 | if (!nlist.ext()) continue; |
| 1347 | if (nlist.undf() and !nlist.tentative()) continue; | |
| 1348 | 1488 | if (nlist.sect()) { |
| 1349 | const atom = macho_file.getAtom(atom_index).?; | |
| 1489 | const atom = self.getAtom(atom_index).?; | |
| 1350 | 1490 | if (!atom.flags.alive) continue; |
| 1351 | 1491 | } |
| 1352 | 1492 | |
| 1353 | const symbol = macho_file.getSymbol(index); | |
| 1493 | const gop = try macho_file.resolver.getOrPut(gpa, .{ | |
| 1494 | .index = @intCast(i), | |
| 1495 | .file = self.index, | |
| 1496 | }, macho_file); | |
| 1497 | if (!gop.found_existing) { | |
| 1498 | gop.ref.* = .{ .index = 0, .file = 0 }; | |
| 1499 | } | |
| 1500 | global.* = gop.index; | |
| 1501 | ||
| 1502 | if (nlist.undf() and !nlist.tentative()) continue; | |
| 1503 | if (gop.ref.getFile(macho_file) == null) { | |
| 1504 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; | |
| 1505 | continue; | |
| 1506 | } | |
| 1507 | ||
| 1354 | 1508 | if (self.asFile().getSymbolRank(.{ |
| 1355 | 1509 | .archive = !self.alive, |
| 1356 | 1510 | .weak = nlist.weakDef(), |
| 1357 | 1511 | .tentative = nlist.tentative(), |
| 1358 | }) < symbol.getSymbolRank(macho_file)) { | |
| 1359 | const value = if (nlist.sect()) blk: { | |
| 1360 | const atom = macho_file.getAtom(atom_index).?; | |
| 1361 | break :blk nlist.n_value - atom.getInputAddress(macho_file); | |
| 1362 | } else nlist.n_value; | |
| 1363 | symbol.value = value; | |
| 1364 | symbol.atom = atom_index; | |
| 1365 | symbol.nlist_idx = nlist_idx; | |
| 1366 | symbol.file = self.index; | |
| 1367 | symbol.flags.weak = nlist.weakDef(); | |
| 1368 | symbol.flags.abs = nlist.abs(); | |
| 1369 | symbol.flags.tentative = nlist.tentative(); | |
| 1370 | symbol.flags.weak_ref = false; | |
| 1371 | symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0; | |
| 1372 | symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip(); | |
| 1373 | // TODO: symbol.flags.interposable = macho_file.base.isDynLib() and macho_file.options.namespace == .flat and !nlist.pext(); | |
| 1374 | symbol.flags.interposable = false; | |
| 1375 | ||
| 1376 | if (nlist.sect() and | |
| 1377 | self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES) | |
| 1378 | { | |
| 1379 | symbol.flags.tlv = true; | |
| 1380 | } | |
| 1381 | } | |
| 1382 | ||
| 1383 | // Regardless of who the winner is, we still merge symbol visibility here. | |
| 1384 | if (nlist.pext() or (nlist.weakDef() and nlist.weakRef()) or self.hidden) { | |
| 1385 | if (symbol.visibility != .global) { | |
| 1386 | symbol.visibility = .hidden; | |
| 1387 | } | |
| 1388 | } else { | |
| 1389 | symbol.visibility = .global; | |
| 1512 | }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) { | |
| 1513 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; | |
| 1390 | 1514 | } |
| 1391 | 1515 | } |
| 1392 | 1516 | } |
| 1393 | 1517 | |
| 1394 | pub fn resetGlobals(self: *Object, macho_file: *MachO) void { | |
| 1395 | for (self.symbols.items, 0..) |sym_index, nlist_idx| { | |
| 1396 | if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue; | |
| 1397 | const sym = macho_file.getSymbol(sym_index); | |
| 1398 | const name = sym.name; | |
| 1399 | const global = sym.flags.global; | |
| 1400 | const weak_ref = sym.flags.weak_ref; | |
| 1401 | sym.* = .{}; | |
| 1402 | sym.name = name; | |
| 1403 | sym.flags.global = global; | |
| 1404 | sym.flags.weak_ref = weak_ref; | |
| 1405 | } | |
| 1406 | } | |
| 1407 | ||
| 1408 | 1518 | pub fn markLive(self: *Object, macho_file: *MachO) void { |
| 1409 | 1519 | const tracy = trace(@src()); |
| 1410 | 1520 | defer tracy.end(); |
| 1411 | 1521 | |
| 1412 | for (self.symbols.items, 0..) |index, nlist_idx| { | |
| 1413 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | |
| 1522 | for (0..self.symbols.items.len) |i| { | |
| 1523 | const nlist = self.symtab.items(.nlist)[i]; | |
| 1414 | 1524 | if (!nlist.ext()) continue; |
| 1415 | 1525 | |
| 1416 | const sym = macho_file.getSymbol(index); | |
| 1417 | const file = sym.getFile(macho_file) orelse continue; | |
| 1526 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 1527 | const file = ref.getFile(macho_file) orelse continue; | |
| 1528 | const sym = ref.getSymbol(macho_file).?; | |
| 1418 | 1529 | const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative); |
| 1419 | 1530 | if (should_keep and file == .object and !file.object.alive) { |
| 1420 | 1531 | file.object.alive = true; |
| ... | ... | @@ -1423,38 +1534,36 @@ pub fn markLive(self: *Object, macho_file: *MachO) void { |
| 1423 | 1534 | } |
| 1424 | 1535 | } |
| 1425 | 1536 | |
| 1426 | pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{OutOfMemory}!void { | |
| 1427 | for (self.symbols.items, 0..) |index, nlist_idx| { | |
| 1428 | const sym = macho_file.getSymbol(index); | |
| 1429 | if (sym.visibility != .global) continue; | |
| 1430 | const file = sym.getFile(macho_file) orelse continue; | |
| 1431 | if (file.getIndex() == self.index) continue; | |
| 1537 | pub fn mergeSymbolVisibility(self: *Object, macho_file: *MachO) void { | |
| 1538 | const tracy = trace(@src()); | |
| 1539 | defer tracy.end(); | |
| 1432 | 1540 | |
| 1433 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | |
| 1434 | if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) { | |
| 1435 | const gop = try dupes.getOrPut(index); | |
| 1436 | if (!gop.found_existing) { | |
| 1437 | gop.value_ptr.* = .{}; | |
| 1438 | } | |
| 1439 | try gop.value_ptr.append(macho_file.base.comp.gpa, self.index); | |
| 1541 | for (self.symbols.items, 0..) |sym, i| { | |
| 1542 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 1543 | const global = ref.getSymbol(macho_file) orelse continue; | |
| 1544 | if (sym.visibility.rank() < global.visibility.rank()) { | |
| 1545 | global.visibility = sym.visibility; | |
| 1546 | } | |
| 1547 | if (sym.flags.weak_ref) { | |
| 1548 | global.flags.weak_ref = true; | |
| 1440 | 1549 | } |
| 1441 | 1550 | } |
| 1442 | 1551 | } |
| 1443 | 1552 | |
| 1444 | pub fn scanRelocs(self: Object, macho_file: *MachO) !void { | |
| 1553 | pub fn scanRelocs(self: *Object, macho_file: *MachO) !void { | |
| 1445 | 1554 | const tracy = trace(@src()); |
| 1446 | 1555 | defer tracy.end(); |
| 1447 | 1556 | |
| 1448 | for (self.atoms.items) |atom_index| { | |
| 1449 | const atom = macho_file.getAtom(atom_index).?; | |
| 1557 | for (self.getAtoms()) |atom_index| { | |
| 1558 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1450 | 1559 | if (!atom.flags.alive) continue; |
| 1451 | 1560 | const sect = atom.getInputSection(macho_file); |
| 1452 | 1561 | if (sect.isZerofill()) continue; |
| 1453 | 1562 | try atom.scanRelocs(macho_file); |
| 1454 | 1563 | } |
| 1455 | 1564 | |
| 1456 | for (self.unwind_records.items) |rec_index| { | |
| 1457 | const rec = macho_file.getUnwindRecord(rec_index); | |
| 1565 | for (self.unwind_records_indexes.items) |rec_index| { | |
| 1566 | const rec = self.getUnwindRecord(rec_index); | |
| 1458 | 1567 | if (!rec.alive) continue; |
| 1459 | 1568 | if (rec.getFde(macho_file)) |fde| { |
| 1460 | 1569 | if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| { |
| ... | ... | @@ -1471,38 +1580,35 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { |
| 1471 | 1580 | defer tracy.end(); |
| 1472 | 1581 | const gpa = macho_file.base.comp.gpa; |
| 1473 | 1582 | |
| 1474 | for (self.symbols.items, 0..) |index, i| { | |
| 1475 | const sym = macho_file.getSymbol(index); | |
| 1583 | for (self.symbols.items, self.globals.items, 0..) |*sym, off, i| { | |
| 1476 | 1584 | if (!sym.flags.tentative) continue; |
| 1477 | const sym_file = sym.getFile(macho_file).?; | |
| 1478 | if (sym_file.getIndex() != self.index) continue; | |
| 1585 | if (macho_file.resolver.get(off).?.file != self.index) continue; | |
| 1479 | 1586 | |
| 1480 | 1587 | const nlist_idx = @as(Symbol.Index, @intCast(i)); |
| 1481 | 1588 | const nlist = &self.symtab.items(.nlist)[nlist_idx]; |
| 1482 | 1589 | const nlist_atom = &self.symtab.items(.atom)[nlist_idx]; |
| 1483 | 1590 | |
| 1484 | const atom_index = try macho_file.addAtom(); | |
| 1485 | try self.atoms.append(gpa, atom_index); | |
| 1486 | ||
| 1487 | 1591 | const name = try std.fmt.allocPrintZ(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)}); |
| 1488 | 1592 | defer gpa.free(name); |
| 1489 | const atom = macho_file.getAtom(atom_index).?; | |
| 1490 | atom.atom_index = atom_index; | |
| 1491 | atom.name = try self.addString(gpa, name); | |
| 1492 | atom.file = self.index; | |
| 1493 | atom.size = nlist.n_value; | |
| 1494 | atom.alignment = Atom.Alignment.fromLog2Units((nlist.n_desc >> 8) & 0x0f); | |
| 1495 | 1593 | |
| 1594 | const alignment = (nlist.n_desc >> 8) & 0x0f; | |
| 1496 | 1595 | const n_sect = try self.addSection(gpa, "__DATA", "__common"); |
| 1596 | const atom_index = try self.addAtom(gpa, .{ | |
| 1597 | .name = try self.addString(gpa, name), | |
| 1598 | .n_sect = n_sect, | |
| 1599 | .off = 0, | |
| 1600 | .size = nlist.n_value, | |
| 1601 | .alignment = alignment, | |
| 1602 | }); | |
| 1603 | try self.atoms_indexes.append(gpa, atom_index); | |
| 1604 | ||
| 1497 | 1605 | const sect = &self.sections.items(.header)[n_sect]; |
| 1498 | 1606 | sect.flags = macho.S_ZEROFILL; |
| 1499 | sect.size = atom.size; | |
| 1500 | sect.@"align" = atom.alignment.toLog2Units(); | |
| 1501 | atom.n_sect = n_sect; | |
| 1607 | sect.size = nlist.n_value; | |
| 1608 | sect.@"align" = alignment; | |
| 1502 | 1609 | |
| 1503 | 1610 | sym.value = 0; |
| 1504 | sym.atom = atom_index; | |
| 1505 | sym.flags.global = true; | |
| 1611 | sym.atom_ref = .{ .index = atom_index, .file = self.index }; | |
| 1506 | 1612 | sym.flags.weak = false; |
| 1507 | 1613 | sym.flags.weak_ref = false; |
| 1508 | 1614 | sym.flags.tentative = false; |
| ... | ... | @@ -1516,8 +1622,8 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { |
| 1516 | 1622 | } |
| 1517 | 1623 | } |
| 1518 | 1624 | |
| 1519 | fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname: []const u8) !u32 { | |
| 1520 | const n_sect = @as(u32, @intCast(try self.sections.addOne(allocator))); | |
| 1625 | fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname: []const u8) !u8 { | |
| 1626 | const n_sect = @as(u8, @intCast(try self.sections.addOne(allocator))); | |
| 1521 | 1627 | self.sections.set(n_sect, .{ |
| 1522 | 1628 | .header = .{ |
| 1523 | 1629 | .sectname = MachO.makeStaticString(sectname), |
| ... | ... | @@ -1532,12 +1638,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1532 | 1638 | defer tracy.end(); |
| 1533 | 1639 | |
| 1534 | 1640 | const gpa = macho_file.base.comp.gpa; |
| 1535 | const offset = if (self.archive) |ar| ar.offset else 0; | |
| 1536 | 1641 | const handle = macho_file.getFileHandle(self.file_handle); |
| 1537 | 1642 | |
| 1538 | 1643 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 1539 | 1644 | { |
| 1540 | const amt = try handle.preadAll(&header_buffer, offset); | |
| 1645 | const amt = try handle.preadAll(&header_buffer, self.offset); | |
| 1541 | 1646 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 1542 | 1647 | } |
| 1543 | 1648 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; |
| ... | ... | @@ -1558,7 +1663,7 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1558 | 1663 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 1559 | 1664 | defer gpa.free(lc_buffer); |
| 1560 | 1665 | { |
| 1561 | const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); | |
| 1666 | const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); | |
| 1562 | 1667 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; |
| 1563 | 1668 | } |
| 1564 | 1669 | |
| ... | ... | @@ -1571,14 +1676,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1571 | 1676 | const cmd = lc.cast(macho.symtab_command).?; |
| 1572 | 1677 | try self.strtab.resize(gpa, cmd.strsize); |
| 1573 | 1678 | { |
| 1574 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset); | |
| 1679 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset); | |
| 1575 | 1680 | if (amt != self.strtab.items.len) return error.InputOutput; |
| 1576 | 1681 | } |
| 1577 | 1682 | |
| 1578 | 1683 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); |
| 1579 | 1684 | defer gpa.free(symtab_buffer); |
| 1580 | 1685 | { |
| 1581 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset); | |
| 1686 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset); | |
| 1582 | 1687 | if (amt != symtab_buffer.len) return error.InputOutput; |
| 1583 | 1688 | } |
| 1584 | 1689 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; |
| ... | ... | @@ -1613,7 +1718,7 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, macho_file: *M |
| 1613 | 1718 | } |
| 1614 | 1719 | |
| 1615 | 1720 | pub fn updateArSize(self: *Object, macho_file: *MachO) !void { |
| 1616 | self.output_ar_state.size = if (self.archive) |ar| ar.size else size: { | |
| 1721 | self.output_ar_state.size = if (self.in_archive) |ar| ar.size else size: { | |
| 1617 | 1722 | const file = macho_file.getFileHandle(self.file_handle); |
| 1618 | 1723 | break :size (try file.stat()).size; |
| 1619 | 1724 | }; |
| ... | ... | @@ -1622,7 +1727,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { |
| 1622 | 1727 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { |
| 1623 | 1728 | // Header |
| 1624 | 1729 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; |
| 1625 | const offset: u64 = if (self.archive) |ar| ar.offset else 0; | |
| 1626 | 1730 | try Archive.writeHeader(self.path, size, ar_format, writer); |
| 1627 | 1731 | // Data |
| 1628 | 1732 | const file = macho_file.getFileHandle(self.file_handle); |
| ... | ... | @@ -1630,72 +1734,75 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ |
| 1630 | 1734 | const gpa = macho_file.base.comp.gpa; |
| 1631 | 1735 | const data = try gpa.alloc(u8, size); |
| 1632 | 1736 | defer gpa.free(data); |
| 1633 | const amt = try file.preadAll(data, offset); | |
| 1737 | const amt = try file.preadAll(data, self.offset); | |
| 1634 | 1738 | if (amt != size) return error.InputOutput; |
| 1635 | 1739 | try writer.writeAll(data); |
| 1636 | 1740 | } |
| 1637 | 1741 | |
| 1638 | pub fn calcSymtabSize(self: *Object, macho_file: *MachO) !void { | |
| 1742 | pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void { | |
| 1639 | 1743 | const tracy = trace(@src()); |
| 1640 | 1744 | defer tracy.end(); |
| 1641 | 1745 | |
| 1642 | for (self.symbols.items) |sym_index| { | |
| 1643 | const sym = macho_file.getSymbol(sym_index); | |
| 1644 | const file = sym.getFile(macho_file) orelse continue; | |
| 1746 | const is_obj = macho_file.base.isObject(); | |
| 1747 | ||
| 1748 | for (self.symbols.items, 0..) |*sym, i| { | |
| 1749 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 1750 | const file = ref.getFile(macho_file) orelse continue; | |
| 1645 | 1751 | if (file.getIndex() != self.index) continue; |
| 1646 | 1752 | if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; |
| 1647 | 1753 | if (sym.isSymbolStab(macho_file)) continue; |
| 1648 | 1754 | const name = sym.getName(macho_file); |
| 1755 | if (name.len == 0) continue; | |
| 1649 | 1756 | // TODO in -r mode, we actually want to merge symbol names and emit only one |
| 1650 | 1757 | // work it out when emitting relocs |
| 1651 | if (name.len > 0 and | |
| 1652 | (name[0] == 'L' or name[0] == 'l' or | |
| 1758 | if ((name[0] == 'L' or name[0] == 'l' or | |
| 1653 | 1759 | mem.startsWith(u8, name, "_OBJC_SELECTOR_REFERENCES_")) and |
| 1654 | !macho_file.base.isObject()) continue; | |
| 1760 | !is_obj) | |
| 1761 | continue; | |
| 1655 | 1762 | sym.flags.output_symtab = true; |
| 1656 | 1763 | if (sym.isLocal()) { |
| 1657 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); | |
| 1764 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); | |
| 1658 | 1765 | self.output_symtab_ctx.nlocals += 1; |
| 1659 | 1766 | } else if (sym.flags.@"export") { |
| 1660 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file); | |
| 1767 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file); | |
| 1661 | 1768 | self.output_symtab_ctx.nexports += 1; |
| 1662 | 1769 | } else { |
| 1663 | 1770 | assert(sym.flags.import); |
| 1664 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | |
| 1771 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | |
| 1665 | 1772 | self.output_symtab_ctx.nimports += 1; |
| 1666 | 1773 | } |
| 1667 | 1774 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1)); |
| 1668 | 1775 | } |
| 1669 | 1776 | |
| 1670 | 1777 | if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo()) |
| 1671 | try self.calcStabsSize(macho_file); | |
| 1778 | self.calcStabsSize(macho_file); | |
| 1672 | 1779 | } |
| 1673 | 1780 | |
| 1674 | pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { | |
| 1781 | pub fn calcStabsSize(self: *Object, macho_file: *MachO) void { | |
| 1675 | 1782 | if (self.compile_unit) |cu| { |
| 1676 | const comp_dir = cu.getCompDir(self); | |
| 1677 | const tu_name = cu.getTuName(self); | |
| 1783 | const comp_dir = cu.getCompDir(self.*); | |
| 1784 | const tu_name = cu.getTuName(self.*); | |
| 1678 | 1785 | |
| 1679 | 1786 | self.output_symtab_ctx.nstabs += 4; // N_SO, N_SO, N_OSO, N_SO |
| 1680 | 1787 | self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir |
| 1681 | 1788 | self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name |
| 1682 | 1789 | |
| 1683 | if (self.archive) |ar| { | |
| 1790 | if (self.in_archive) |ar| { | |
| 1684 | 1791 | self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1)); |
| 1685 | 1792 | } else { |
| 1686 | 1793 | self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1)); |
| 1687 | 1794 | } |
| 1688 | 1795 | |
| 1689 | for (self.symbols.items) |sym_index| { | |
| 1690 | const sym = macho_file.getSymbol(sym_index); | |
| 1691 | const file = sym.getFile(macho_file) orelse continue; | |
| 1796 | for (self.symbols.items, 0..) |sym, i| { | |
| 1797 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 1798 | const file = ref.getFile(macho_file) orelse continue; | |
| 1692 | 1799 | if (file.getIndex() != self.index) continue; |
| 1693 | 1800 | if (!sym.flags.output_symtab) continue; |
| 1694 | 1801 | if (macho_file.base.isObject()) { |
| 1695 | 1802 | const name = sym.getName(macho_file); |
| 1696 | 1803 | if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue; |
| 1697 | 1804 | } |
| 1698 | const sect = macho_file.sections.items(.header)[sym.out_n_sect]; | |
| 1805 | const sect = macho_file.sections.items(.header)[sym.getOutputSectionIndex(macho_file)]; | |
| 1699 | 1806 | if (sect.isCode()) { |
| 1700 | 1807 | self.output_symtab_ctx.nstabs += 4; // N_BNSYM, N_FUN, N_FUN, N_ENSYM |
| 1701 | 1808 | } else if (sym.visibility == .global) { |
| ... | ... | @@ -1709,12 +1816,12 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { |
| 1709 | 1816 | |
| 1710 | 1817 | for (self.stab_files.items) |sf| { |
| 1711 | 1818 | self.output_symtab_ctx.nstabs += 4; // N_SO, N_SO, N_OSO, N_SO |
| 1712 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getCompDir(self).len + 1)); // comp_dir | |
| 1713 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getTuName(self).len + 1)); // tu_name | |
| 1714 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getOsoPath(self).len + 1)); // path | |
| 1819 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getCompDir(self.*).len + 1)); // comp_dir | |
| 1820 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getTuName(self.*).len + 1)); // tu_name | |
| 1821 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getOsoPath(self.*).len + 1)); // path | |
| 1715 | 1822 | |
| 1716 | 1823 | for (sf.stabs.items) |stab| { |
| 1717 | const sym = stab.getSymbol(macho_file) orelse continue; | |
| 1824 | const sym = stab.getSymbol(self.*) orelse continue; | |
| 1718 | 1825 | const file = sym.getFile(macho_file).?; |
| 1719 | 1826 | if (file.getIndex() != self.index) continue; |
| 1720 | 1827 | if (!sym.flags.output_symtab) continue; |
| ... | ... | @@ -1725,28 +1832,212 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { |
| 1725 | 1832 | } |
| 1726 | 1833 | } |
| 1727 | 1834 | |
| 1728 | pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) error{Overflow}!void { | |
| 1835 | pub fn writeAtoms(self: *Object, macho_file: *MachO) !void { | |
| 1729 | 1836 | const tracy = trace(@src()); |
| 1730 | 1837 | defer tracy.end(); |
| 1731 | 1838 | |
| 1732 | for (self.symbols.items) |sym_index| { | |
| 1733 | const sym = macho_file.getSymbol(sym_index); | |
| 1734 | const file = sym.getFile(macho_file) orelse continue; | |
| 1839 | const gpa = macho_file.base.comp.gpa; | |
| 1840 | const headers = self.sections.items(.header); | |
| 1841 | const sections_data = try gpa.alloc([]const u8, headers.len); | |
| 1842 | defer { | |
| 1843 | for (sections_data) |data| { | |
| 1844 | gpa.free(data); | |
| 1845 | } | |
| 1846 | gpa.free(sections_data); | |
| 1847 | } | |
| 1848 | @memset(sections_data, &[0]u8{}); | |
| 1849 | const file = macho_file.getFileHandle(self.file_handle); | |
| 1850 | ||
| 1851 | for (headers, 0..) |header, n_sect| { | |
| 1852 | if (header.isZerofill()) continue; | |
| 1853 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 1854 | const data = try gpa.alloc(u8, size); | |
| 1855 | const amt = try file.preadAll(data, header.offset + self.offset); | |
| 1856 | if (amt != data.len) return error.InputOutput; | |
| 1857 | sections_data[n_sect] = data; | |
| 1858 | } | |
| 1859 | for (self.getAtoms()) |atom_index| { | |
| 1860 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1861 | if (!atom.flags.alive) continue; | |
| 1862 | const sect = atom.getInputSection(macho_file); | |
| 1863 | if (sect.isZerofill()) continue; | |
| 1864 | const value = math.cast(usize, atom.value) orelse return error.Overflow; | |
| 1865 | const off = math.cast(usize, atom.off) orelse return error.Overflow; | |
| 1866 | const size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 1867 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items; | |
| 1868 | const data = sections_data[atom.n_sect]; | |
| 1869 | @memcpy(buffer[value..][0..size], data[off..][0..size]); | |
| 1870 | try atom.resolveRelocs(macho_file, buffer[value..][0..size]); | |
| 1871 | } | |
| 1872 | } | |
| 1873 | ||
| 1874 | pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void { | |
| 1875 | const tracy = trace(@src()); | |
| 1876 | defer tracy.end(); | |
| 1877 | ||
| 1878 | const gpa = macho_file.base.comp.gpa; | |
| 1879 | const headers = self.sections.items(.header); | |
| 1880 | const sections_data = try gpa.alloc([]const u8, headers.len); | |
| 1881 | defer { | |
| 1882 | for (sections_data) |data| { | |
| 1883 | gpa.free(data); | |
| 1884 | } | |
| 1885 | gpa.free(sections_data); | |
| 1886 | } | |
| 1887 | @memset(sections_data, &[0]u8{}); | |
| 1888 | const file = macho_file.getFileHandle(self.file_handle); | |
| 1889 | ||
| 1890 | for (headers, 0..) |header, n_sect| { | |
| 1891 | if (header.isZerofill()) continue; | |
| 1892 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 1893 | const data = try gpa.alloc(u8, size); | |
| 1894 | const amt = try file.preadAll(data, header.offset + self.offset); | |
| 1895 | if (amt != data.len) return error.InputOutput; | |
| 1896 | sections_data[n_sect] = data; | |
| 1897 | } | |
| 1898 | for (self.getAtoms()) |atom_index| { | |
| 1899 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1900 | if (!atom.flags.alive) continue; | |
| 1901 | const sect = atom.getInputSection(macho_file); | |
| 1902 | if (sect.isZerofill()) continue; | |
| 1903 | const value = math.cast(usize, atom.value) orelse return error.Overflow; | |
| 1904 | const off = math.cast(usize, atom.off) orelse return error.Overflow; | |
| 1905 | const size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 1906 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items; | |
| 1907 | const data = sections_data[atom.n_sect]; | |
| 1908 | @memcpy(buffer[value..][0..size], data[off..][0..size]); | |
| 1909 | const relocs = macho_file.sections.items(.relocs)[atom.out_n_sect].items; | |
| 1910 | const extra = atom.getExtra(macho_file); | |
| 1911 | try atom.writeRelocs(macho_file, buffer[value..][0..size], relocs[extra.rel_out_index..][0..extra.rel_out_count]); | |
| 1912 | } | |
| 1913 | } | |
| 1914 | ||
| 1915 | pub fn calcCompactUnwindSizeRelocatable(self: *Object, macho_file: *MachO) void { | |
| 1916 | const tracy = trace(@src()); | |
| 1917 | defer tracy.end(); | |
| 1918 | ||
| 1919 | const ctx = &self.compact_unwind_ctx; | |
| 1920 | ||
| 1921 | for (self.unwind_records_indexes.items) |irec| { | |
| 1922 | const rec = self.getUnwindRecord(irec); | |
| 1923 | if (!rec.alive) continue; | |
| 1924 | ||
| 1925 | ctx.rec_count += 1; | |
| 1926 | ctx.reloc_count += 1; | |
| 1927 | if (rec.getPersonality(macho_file)) |_| { | |
| 1928 | ctx.reloc_count += 1; | |
| 1929 | } | |
| 1930 | if (rec.getLsdaAtom(macho_file)) |_| { | |
| 1931 | ctx.reloc_count += 1; | |
| 1932 | } | |
| 1933 | } | |
| 1934 | } | |
| 1935 | ||
| 1936 | pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void { | |
| 1937 | const tracy = trace(@src()); | |
| 1938 | defer tracy.end(); | |
| 1939 | ||
| 1940 | const cpu_arch = macho_file.getTarget().cpu.arch; | |
| 1941 | ||
| 1942 | const addReloc = struct { | |
| 1943 | fn addReloc(offset: u32, arch: std.Target.Cpu.Arch) !macho.relocation_info { | |
| 1944 | return .{ | |
| 1945 | .r_address = math.cast(i32, offset) orelse return error.Overflow, | |
| 1946 | .r_symbolnum = 0, | |
| 1947 | .r_pcrel = 0, | |
| 1948 | .r_length = 3, | |
| 1949 | .r_extern = 0, | |
| 1950 | .r_type = switch (arch) { | |
| 1951 | .aarch64 => @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), | |
| 1952 | .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), | |
| 1953 | else => unreachable, | |
| 1954 | }, | |
| 1955 | }; | |
| 1956 | } | |
| 1957 | }.addReloc; | |
| 1958 | ||
| 1959 | const nsect = macho_file.unwind_info_sect_index.?; | |
| 1960 | const buffer = macho_file.sections.items(.out)[nsect].items; | |
| 1961 | const relocs = macho_file.sections.items(.relocs)[nsect].items; | |
| 1962 | ||
| 1963 | var rec_index: u32 = self.compact_unwind_ctx.rec_index; | |
| 1964 | var reloc_index: u32 = self.compact_unwind_ctx.reloc_index; | |
| 1965 | ||
| 1966 | for (self.unwind_records_indexes.items) |irec| { | |
| 1967 | const rec = self.getUnwindRecord(irec); | |
| 1968 | if (!rec.alive) continue; | |
| 1969 | ||
| 1970 | var out: macho.compact_unwind_entry = .{ | |
| 1971 | .rangeStart = 0, | |
| 1972 | .rangeLength = rec.length, | |
| 1973 | .compactUnwindEncoding = rec.enc.enc, | |
| 1974 | .personalityFunction = 0, | |
| 1975 | .lsda = 0, | |
| 1976 | }; | |
| 1977 | defer rec_index += 1; | |
| 1978 | ||
| 1979 | const offset = rec_index * @sizeOf(macho.compact_unwind_entry); | |
| 1980 | ||
| 1981 | { | |
| 1982 | // Function address | |
| 1983 | const atom = rec.getAtom(macho_file); | |
| 1984 | const addr = rec.getAtomAddress(macho_file); | |
| 1985 | out.rangeStart = addr; | |
| 1986 | var reloc = try addReloc(offset, cpu_arch); | |
| 1987 | reloc.r_symbolnum = atom.out_n_sect + 1; | |
| 1988 | relocs[reloc_index] = reloc; | |
| 1989 | reloc_index += 1; | |
| 1990 | } | |
| 1991 | ||
| 1992 | // Personality function | |
| 1993 | if (rec.getPersonality(macho_file)) |sym| { | |
| 1994 | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; | |
| 1995 | var reloc = try addReloc(offset + 16, cpu_arch); | |
| 1996 | reloc.r_symbolnum = r_symbolnum; | |
| 1997 | reloc.r_extern = 1; | |
| 1998 | relocs[reloc_index] = reloc; | |
| 1999 | reloc_index += 1; | |
| 2000 | } | |
| 2001 | ||
| 2002 | // LSDA address | |
| 2003 | if (rec.getLsdaAtom(macho_file)) |atom| { | |
| 2004 | const addr = rec.getLsdaAddress(macho_file); | |
| 2005 | out.lsda = addr; | |
| 2006 | var reloc = try addReloc(offset + 24, cpu_arch); | |
| 2007 | reloc.r_symbolnum = atom.out_n_sect + 1; | |
| 2008 | relocs[reloc_index] = reloc; | |
| 2009 | reloc_index += 1; | |
| 2010 | } | |
| 2011 | ||
| 2012 | @memcpy(buffer[offset..][0..@sizeOf(macho.compact_unwind_entry)], mem.asBytes(&out)); | |
| 2013 | } | |
| 2014 | } | |
| 2015 | ||
| 2016 | pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) void { | |
| 2017 | const tracy = trace(@src()); | |
| 2018 | defer tracy.end(); | |
| 2019 | ||
| 2020 | var n_strx = self.output_symtab_ctx.stroff; | |
| 2021 | for (self.symbols.items, 0..) |sym, i| { | |
| 2022 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 2023 | const file = ref.getFile(macho_file) orelse continue; | |
| 1735 | 2024 | if (file.getIndex() != self.index) continue; |
| 1736 | 2025 | const idx = sym.getOutputSymtabIndex(macho_file) orelse continue; |
| 1737 | const n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 1738 | ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file)); | |
| 1739 | ctx.strtab.appendAssumeCapacity(0); | |
| 1740 | 2026 | const out_sym = &ctx.symtab.items[idx]; |
| 1741 | 2027 | out_sym.n_strx = n_strx; |
| 1742 | 2028 | sym.setOutputSym(macho_file, out_sym); |
| 2029 | const name = sym.getName(macho_file); | |
| 2030 | @memcpy(ctx.strtab.items[n_strx..][0..name.len], name); | |
| 2031 | n_strx += @intCast(name.len); | |
| 2032 | ctx.strtab.items[n_strx] = 0; | |
| 2033 | n_strx += 1; | |
| 1743 | 2034 | } |
| 1744 | 2035 | |
| 1745 | 2036 | if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo()) |
| 1746 | try self.writeStabs(macho_file, ctx); | |
| 2037 | self.writeStabs(n_strx, macho_file, ctx); | |
| 1747 | 2038 | } |
| 1748 | 2039 | |
| 1749 | pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{Overflow}!void { | |
| 2040 | pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) void { | |
| 1750 | 2041 | const writeFuncStab = struct { |
| 1751 | 2042 | inline fn writeFuncStab( |
| 1752 | 2043 | n_strx: u32, |
| ... | ... | @@ -1788,6 +2079,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1788 | 2079 | }.writeFuncStab; |
| 1789 | 2080 | |
| 1790 | 2081 | var index = self.output_symtab_ctx.istab; |
| 2082 | var n_strx = stroff; | |
| 1791 | 2083 | |
| 1792 | 2084 | if (self.compile_unit) |cu| { |
| 1793 | 2085 | const comp_dir = cu.getCompDir(self); |
| ... | ... | @@ -1795,9 +2087,6 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1795 | 2087 | |
| 1796 | 2088 | // Open scope |
| 1797 | 2089 | // N_SO comp_dir |
| 1798 | var n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 1799 | ctx.strtab.appendSliceAssumeCapacity(comp_dir); | |
| 1800 | ctx.strtab.appendAssumeCapacity(0); | |
| 1801 | 2090 | ctx.symtab.items[index] = .{ |
| 1802 | 2091 | .n_strx = n_strx, |
| 1803 | 2092 | .n_type = macho.N_SO, |
| ... | ... | @@ -1806,11 +2095,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1806 | 2095 | .n_value = 0, |
| 1807 | 2096 | }; |
| 1808 | 2097 | index += 1; |
| 2098 | @memcpy(ctx.strtab.items[n_strx..][0..comp_dir.len], comp_dir); | |
| 2099 | n_strx += @intCast(comp_dir.len); | |
| 2100 | ctx.strtab.items[n_strx] = 0; | |
| 2101 | n_strx += 1; | |
| 1809 | 2102 | // N_SO tu_name |
| 1810 | n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 1811 | ctx.strtab.appendSliceAssumeCapacity(tu_name); | |
| 1812 | ctx.strtab.appendAssumeCapacity(0); | |
| 1813 | ctx.symtab.items[index] = .{ | |
| 2103 | macho_file.symtab.items[index] = .{ | |
| 1814 | 2104 | .n_strx = n_strx, |
| 1815 | 2105 | .n_type = macho.N_SO, |
| 1816 | 2106 | .n_sect = 0, |
| ... | ... | @@ -1818,18 +2108,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1818 | 2108 | .n_value = 0, |
| 1819 | 2109 | }; |
| 1820 | 2110 | index += 1; |
| 2111 | @memcpy(ctx.strtab.items[n_strx..][0..tu_name.len], tu_name); | |
| 2112 | n_strx += @intCast(tu_name.len); | |
| 2113 | ctx.strtab.items[n_strx] = 0; | |
| 2114 | n_strx += 1; | |
| 1821 | 2115 | // N_OSO path |
| 1822 | n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 1823 | if (self.archive) |ar| { | |
| 1824 | ctx.strtab.appendSliceAssumeCapacity(ar.path); | |
| 1825 | ctx.strtab.appendAssumeCapacity('('); | |
| 1826 | ctx.strtab.appendSliceAssumeCapacity(self.path); | |
| 1827 | ctx.strtab.appendAssumeCapacity(')'); | |
| 1828 | ctx.strtab.appendAssumeCapacity(0); | |
| 1829 | } else { | |
| 1830 | ctx.strtab.appendSliceAssumeCapacity(self.path); | |
| 1831 | ctx.strtab.appendAssumeCapacity(0); | |
| 1832 | } | |
| 1833 | 2116 | ctx.symtab.items[index] = .{ |
| 1834 | 2117 | .n_strx = n_strx, |
| 1835 | 2118 | .n_type = macho.N_OSO, |
| ... | ... | @@ -1838,23 +2121,40 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1838 | 2121 | .n_value = self.mtime, |
| 1839 | 2122 | }; |
| 1840 | 2123 | index += 1; |
| 2124 | if (self.in_archive) |ar| { | |
| 2125 | @memcpy(ctx.strtab.items[n_strx..][0..ar.path.len], ar.path); | |
| 2126 | n_strx += @intCast(ar.path.len); | |
| 2127 | ctx.strtab.items[n_strx] = '('; | |
| 2128 | n_strx += 1; | |
| 2129 | @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path); | |
| 2130 | n_strx += @intCast(self.path.len); | |
| 2131 | ctx.strtab.items[n_strx] = ')'; | |
| 2132 | n_strx += 1; | |
| 2133 | ctx.strtab.items[n_strx] = 0; | |
| 2134 | n_strx += 1; | |
| 2135 | } else { | |
| 2136 | @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path); | |
| 2137 | n_strx += @intCast(self.path.len); | |
| 2138 | ctx.strtab.items[n_strx] = 0; | |
| 2139 | n_strx += 1; | |
| 2140 | } | |
| 1841 | 2141 | |
| 1842 | for (self.symbols.items) |sym_index| { | |
| 1843 | const sym = macho_file.getSymbol(sym_index); | |
| 1844 | const file = sym.getFile(macho_file) orelse continue; | |
| 2142 | for (self.symbols.items, 0..) |sym, i| { | |
| 2143 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 2144 | const file = ref.getFile(macho_file) orelse continue; | |
| 1845 | 2145 | if (file.getIndex() != self.index) continue; |
| 1846 | 2146 | if (!sym.flags.output_symtab) continue; |
| 1847 | 2147 | if (macho_file.base.isObject()) { |
| 1848 | 2148 | const name = sym.getName(macho_file); |
| 1849 | 2149 | if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue; |
| 1850 | 2150 | } |
| 1851 | const sect = macho_file.sections.items(.header)[sym.out_n_sect]; | |
| 2151 | const sect = macho_file.sections.items(.header)[sym.getOutputSectionIndex(macho_file)]; | |
| 1852 | 2152 | const sym_n_strx = n_strx: { |
| 1853 | 2153 | const symtab_index = sym.getOutputSymtabIndex(macho_file).?; |
| 1854 | 2154 | const osym = ctx.symtab.items[symtab_index]; |
| 1855 | 2155 | break :n_strx osym.n_strx; |
| 1856 | 2156 | }; |
| 1857 | const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0; | |
| 2157 | const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.getOutputSectionIndex(macho_file) + 1) else 0; | |
| 1858 | 2158 | const sym_n_value = sym.getAddress(.{}, macho_file); |
| 1859 | 2159 | const sym_size = sym.getSize(macho_file); |
| 1860 | 2160 | if (sect.isCode()) { |
| ... | ... | @@ -1894,11 +2194,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1894 | 2194 | assert(self.hasSymbolStabs()); |
| 1895 | 2195 | |
| 1896 | 2196 | for (self.stab_files.items) |sf| { |
| 2197 | const comp_dir = sf.getCompDir(self); | |
| 2198 | const tu_name = sf.getTuName(self); | |
| 2199 | const oso_path = sf.getOsoPath(self); | |
| 2200 | ||
| 1897 | 2201 | // Open scope |
| 1898 | 2202 | // N_SO comp_dir |
| 1899 | var n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 1900 | ctx.strtab.appendSliceAssumeCapacity(sf.getCompDir(self)); | |
| 1901 | ctx.strtab.appendAssumeCapacity(0); | |
| 1902 | 2203 | ctx.symtab.items[index] = .{ |
| 1903 | 2204 | .n_strx = n_strx, |
| 1904 | 2205 | .n_type = macho.N_SO, |
| ... | ... | @@ -1907,10 +2208,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1907 | 2208 | .n_value = 0, |
| 1908 | 2209 | }; |
| 1909 | 2210 | index += 1; |
| 2211 | @memcpy(ctx.strtab.items[n_strx..][0..comp_dir.len], comp_dir); | |
| 2212 | n_strx += @intCast(comp_dir.len); | |
| 2213 | ctx.strtab.items[n_strx] = 0; | |
| 2214 | n_strx += 1; | |
| 1910 | 2215 | // N_SO tu_name |
| 1911 | n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 1912 | ctx.strtab.appendSliceAssumeCapacity(sf.getTuName(self)); | |
| 1913 | ctx.strtab.appendAssumeCapacity(0); | |
| 1914 | 2216 | ctx.symtab.items[index] = .{ |
| 1915 | 2217 | .n_strx = n_strx, |
| 1916 | 2218 | .n_type = macho.N_SO, |
| ... | ... | @@ -1919,10 +2221,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1919 | 2221 | .n_value = 0, |
| 1920 | 2222 | }; |
| 1921 | 2223 | index += 1; |
| 2224 | @memcpy(ctx.strtab.items[n_strx..][0..tu_name.len], tu_name); | |
| 2225 | n_strx += @intCast(tu_name.len); | |
| 2226 | ctx.strtab.items[n_strx] = 0; | |
| 2227 | n_strx += 1; | |
| 1922 | 2228 | // N_OSO path |
| 1923 | n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 1924 | ctx.strtab.appendSliceAssumeCapacity(sf.getOsoPath(self)); | |
| 1925 | ctx.strtab.appendAssumeCapacity(0); | |
| 1926 | 2229 | ctx.symtab.items[index] = .{ |
| 1927 | 2230 | .n_strx = n_strx, |
| 1928 | 2231 | .n_type = macho.N_OSO, |
| ... | ... | @@ -1931,9 +2234,13 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1931 | 2234 | .n_value = sf.getOsoModTime(self), |
| 1932 | 2235 | }; |
| 1933 | 2236 | index += 1; |
| 2237 | @memcpy(ctx.strtab.items[n_strx..][0..oso_path.len], oso_path); | |
| 2238 | n_strx += @intCast(oso_path.len); | |
| 2239 | ctx.strtab.items[n_strx] = 0; | |
| 2240 | n_strx += 1; | |
| 1934 | 2241 | |
| 1935 | 2242 | for (sf.stabs.items) |stab| { |
| 1936 | const sym = stab.getSymbol(macho_file) orelse continue; | |
| 2243 | const sym = stab.getSymbol(self) orelse continue; | |
| 1937 | 2244 | const file = sym.getFile(macho_file).?; |
| 1938 | 2245 | if (file.getIndex() != self.index) continue; |
| 1939 | 2246 | if (!sym.flags.output_symtab) continue; |
| ... | ... | @@ -1942,7 +2249,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1942 | 2249 | const osym = ctx.symtab.items[symtab_index]; |
| 1943 | 2250 | break :n_strx osym.n_strx; |
| 1944 | 2251 | }; |
| 1945 | const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0; | |
| 2252 | const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.getOutputSectionIndex(macho_file) + 1) else 0; | |
| 1946 | 2253 | const sym_n_value = sym.getAddress(.{}, macho_file); |
| 1947 | 2254 | const sym_size = sym.getSize(macho_file); |
| 1948 | 2255 | if (stab.is_func) { |
| ... | ... | @@ -1983,34 +2290,8 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1983 | 2290 | } |
| 1984 | 2291 | } |
| 1985 | 2292 | |
| 1986 | fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 { | |
| 1987 | const gpa = macho_file.base.comp.gpa; | |
| 1988 | const slice = self.sections.slice(); | |
| 1989 | assert(index < slice.items(.header).len); | |
| 1990 | const sect = slice.items(.header)[index]; | |
| 1991 | const handle = macho_file.getFileHandle(self.file_handle); | |
| 1992 | const offset = if (self.archive) |ar| ar.offset else 0; | |
| 1993 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 1994 | const buffer = try gpa.alloc(u8, size); | |
| 1995 | errdefer gpa.free(buffer); | |
| 1996 | const amt = try handle.preadAll(buffer, sect.offset + offset); | |
| 1997 | if (amt != buffer.len) return error.InputOutput; | |
| 1998 | return buffer; | |
| 1999 | } | |
| 2000 | ||
| 2001 | pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer: []u8) !void { | |
| 2002 | assert(buffer.len == atom.size); | |
| 2003 | const slice = self.sections.slice(); | |
| 2004 | const handle = macho_file.getFileHandle(self.file_handle); | |
| 2005 | const offset = if (self.archive) |ar| ar.offset else 0; | |
| 2006 | const sect = slice.items(.header)[atom.n_sect]; | |
| 2007 | const amt = try handle.preadAll(buffer, sect.offset + offset + atom.off); | |
| 2008 | if (amt != buffer.len) return error.InputOutput; | |
| 2009 | } | |
| 2010 | ||
| 2011 | 2293 | pub fn getAtomRelocs(self: *const Object, atom: Atom, macho_file: *MachO) []const Relocation { |
| 2012 | if (!atom.flags.relocs) return &[0]Relocation{}; | |
| 2013 | const extra = atom.getExtra(macho_file).?; | |
| 2294 | const extra = atom.getExtra(macho_file); | |
| 2014 | 2295 | const relocs = self.sections.items(.relocs)[atom.n_sect]; |
| 2015 | 2296 | return relocs.items[extra.rel_index..][0..extra.rel_count]; |
| 2016 | 2297 | } |
| ... | ... | @@ -2068,6 +2349,160 @@ pub fn asFile(self: *Object) File { |
| 2068 | 2349 | return .{ .object = self }; |
| 2069 | 2350 | } |
| 2070 | 2351 | |
| 2352 | const AddAtomArgs = struct { | |
| 2353 | name: u32, | |
| 2354 | n_sect: u8, | |
| 2355 | off: u64, | |
| 2356 | size: u64, | |
| 2357 | alignment: u32, | |
| 2358 | }; | |
| 2359 | ||
| 2360 | fn addAtom(self: *Object, allocator: Allocator, args: AddAtomArgs) !Atom.Index { | |
| 2361 | const atom_index: Atom.Index = @intCast(self.atoms.items.len); | |
| 2362 | const atom = try self.atoms.addOne(allocator); | |
| 2363 | atom.* = .{ | |
| 2364 | .file = self.index, | |
| 2365 | .atom_index = atom_index, | |
| 2366 | .name = args.name, | |
| 2367 | .n_sect = args.n_sect, | |
| 2368 | .size = args.size, | |
| 2369 | .off = args.off, | |
| 2370 | .extra = try self.addAtomExtra(allocator, .{}), | |
| 2371 | .alignment = Atom.Alignment.fromLog2Units(args.alignment), | |
| 2372 | }; | |
| 2373 | return atom_index; | |
| 2374 | } | |
| 2375 | ||
| 2376 | pub fn getAtom(self: *Object, atom_index: Atom.Index) ?*Atom { | |
| 2377 | if (atom_index == 0) return null; | |
| 2378 | assert(atom_index < self.atoms.items.len); | |
| 2379 | return &self.atoms.items[atom_index]; | |
| 2380 | } | |
| 2381 | ||
| 2382 | pub fn getAtoms(self: *Object) []const Atom.Index { | |
| 2383 | return self.atoms_indexes.items; | |
| 2384 | } | |
| 2385 | ||
| 2386 | fn addAtomExtra(self: *Object, allocator: Allocator, extra: Atom.Extra) !u32 { | |
| 2387 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 2388 | try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len); | |
| 2389 | return self.addAtomExtraAssumeCapacity(extra); | |
| 2390 | } | |
| 2391 | ||
| 2392 | fn addAtomExtraAssumeCapacity(self: *Object, extra: Atom.Extra) u32 { | |
| 2393 | const index = @as(u32, @intCast(self.atoms_extra.items.len)); | |
| 2394 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 2395 | inline for (fields) |field| { | |
| 2396 | self.atoms_extra.appendAssumeCapacity(switch (field.type) { | |
| 2397 | u32 => @field(extra, field.name), | |
| 2398 | else => @compileError("bad field type"), | |
| 2399 | }); | |
| 2400 | } | |
| 2401 | return index; | |
| 2402 | } | |
| 2403 | ||
| 2404 | pub fn getAtomExtra(self: Object, index: u32) Atom.Extra { | |
| 2405 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 2406 | var i: usize = index; | |
| 2407 | var result: Atom.Extra = undefined; | |
| 2408 | inline for (fields) |field| { | |
| 2409 | @field(result, field.name) = switch (field.type) { | |
| 2410 | u32 => self.atoms_extra.items[i], | |
| 2411 | else => @compileError("bad field type"), | |
| 2412 | }; | |
| 2413 | i += 1; | |
| 2414 | } | |
| 2415 | return result; | |
| 2416 | } | |
| 2417 | ||
| 2418 | pub fn setAtomExtra(self: *Object, index: u32, extra: Atom.Extra) void { | |
| 2419 | assert(index > 0); | |
| 2420 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 2421 | inline for (fields, 0..) |field, i| { | |
| 2422 | self.atoms_extra.items[index + i] = switch (field.type) { | |
| 2423 | u32 => @field(extra, field.name), | |
| 2424 | else => @compileError("bad field type"), | |
| 2425 | }; | |
| 2426 | } | |
| 2427 | } | |
| 2428 | ||
| 2429 | fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index { | |
| 2430 | try self.symbols.ensureUnusedCapacity(allocator, 1); | |
| 2431 | return self.addSymbolAssumeCapacity(); | |
| 2432 | } | |
| 2433 | ||
| 2434 | fn addSymbolAssumeCapacity(self: *Object) Symbol.Index { | |
| 2435 | const index: Symbol.Index = @intCast(self.symbols.items.len); | |
| 2436 | const symbol = self.symbols.addOneAssumeCapacity(); | |
| 2437 | symbol.* = .{ .file = self.index }; | |
| 2438 | return index; | |
| 2439 | } | |
| 2440 | ||
| 2441 | pub fn getSymbolRef(self: Object, index: Symbol.Index, macho_file: *MachO) MachO.Ref { | |
| 2442 | const global_index = self.globals.items[index]; | |
| 2443 | if (macho_file.resolver.get(global_index)) |ref| return ref; | |
| 2444 | return .{ .index = index, .file = self.index }; | |
| 2445 | } | |
| 2446 | ||
| 2447 | pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 { | |
| 2448 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 2449 | try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); | |
| 2450 | return self.addSymbolExtraAssumeCapacity(extra); | |
| 2451 | } | |
| 2452 | ||
| 2453 | fn addSymbolExtraAssumeCapacity(self: *Object, extra: Symbol.Extra) u32 { | |
| 2454 | const index = @as(u32, @intCast(self.symbols_extra.items.len)); | |
| 2455 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 2456 | inline for (fields) |field| { | |
| 2457 | self.symbols_extra.appendAssumeCapacity(switch (field.type) { | |
| 2458 | u32 => @field(extra, field.name), | |
| 2459 | else => @compileError("bad field type"), | |
| 2460 | }); | |
| 2461 | } | |
| 2462 | return index; | |
| 2463 | } | |
| 2464 | ||
| 2465 | pub fn getSymbolExtra(self: Object, index: u32) Symbol.Extra { | |
| 2466 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 2467 | var i: usize = index; | |
| 2468 | var result: Symbol.Extra = undefined; | |
| 2469 | inline for (fields) |field| { | |
| 2470 | @field(result, field.name) = switch (field.type) { | |
| 2471 | u32 => self.symbols_extra.items[i], | |
| 2472 | else => @compileError("bad field type"), | |
| 2473 | }; | |
| 2474 | i += 1; | |
| 2475 | } | |
| 2476 | return result; | |
| 2477 | } | |
| 2478 | ||
| 2479 | pub fn setSymbolExtra(self: *Object, index: u32, extra: Symbol.Extra) void { | |
| 2480 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 2481 | inline for (fields, 0..) |field, i| { | |
| 2482 | self.symbols_extra.items[index + i] = switch (field.type) { | |
| 2483 | u32 => @field(extra, field.name), | |
| 2484 | else => @compileError("bad field type"), | |
| 2485 | }; | |
| 2486 | } | |
| 2487 | } | |
| 2488 | ||
| 2489 | fn addUnwindRecord(self: *Object, allocator: Allocator) !UnwindInfo.Record.Index { | |
| 2490 | try self.unwind_records.ensureUnusedCapacity(allocator, 1); | |
| 2491 | return self.addUnwindRecordAssumeCapacity(); | |
| 2492 | } | |
| 2493 | ||
| 2494 | fn addUnwindRecordAssumeCapacity(self: *Object) UnwindInfo.Record.Index { | |
| 2495 | const index = @as(UnwindInfo.Record.Index, @intCast(self.unwind_records.items.len)); | |
| 2496 | const rec = self.unwind_records.addOneAssumeCapacity(); | |
| 2497 | rec.* = .{ .file = self.index }; | |
| 2498 | return index; | |
| 2499 | } | |
| 2500 | ||
| 2501 | pub fn getUnwindRecord(self: *Object, index: UnwindInfo.Record.Index) *UnwindInfo.Record { | |
| 2502 | assert(index < self.unwind_records.items.len); | |
| 2503 | return &self.unwind_records.items[index]; | |
| 2504 | } | |
| 2505 | ||
| 2071 | 2506 | pub fn format( |
| 2072 | 2507 | self: *Object, |
| 2073 | 2508 | comptime unused_fmt_string: []const u8, |
| ... | ... | @@ -2102,10 +2537,11 @@ fn formatAtoms( |
| 2102 | 2537 | _ = unused_fmt_string; |
| 2103 | 2538 | _ = options; |
| 2104 | 2539 | const object = ctx.object; |
| 2540 | const macho_file = ctx.macho_file; | |
| 2105 | 2541 | try writer.writeAll(" atoms\n"); |
| 2106 | for (object.atoms.items) |atom_index| { | |
| 2107 | const atom = ctx.macho_file.getAtom(atom_index).?; | |
| 2108 | try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)}); | |
| 2542 | for (object.getAtoms()) |atom_index| { | |
| 2543 | const atom = object.getAtom(atom_index) orelse continue; | |
| 2544 | try writer.print(" {}\n", .{atom.fmt(macho_file)}); | |
| 2109 | 2545 | } |
| 2110 | 2546 | } |
| 2111 | 2547 | |
| ... | ... | @@ -2171,8 +2607,8 @@ fn formatUnwindRecords( |
| 2171 | 2607 | const object = ctx.object; |
| 2172 | 2608 | const macho_file = ctx.macho_file; |
| 2173 | 2609 | try writer.writeAll(" unwind records\n"); |
| 2174 | for (object.unwind_records.items) |rec| { | |
| 2175 | try writer.print(" rec({d}) : {}\n", .{ rec, macho_file.getUnwindRecord(rec).fmt(macho_file) }); | |
| 2610 | for (object.unwind_records_indexes.items) |rec| { | |
| 2611 | try writer.print(" rec({d}) : {}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) }); | |
| 2176 | 2612 | } |
| 2177 | 2613 | } |
| 2178 | 2614 | |
| ... | ... | @@ -2192,10 +2628,26 @@ fn formatSymtab( |
| 2192 | 2628 | _ = unused_fmt_string; |
| 2193 | 2629 | _ = options; |
| 2194 | 2630 | const object = ctx.object; |
| 2631 | const macho_file = ctx.macho_file; | |
| 2195 | 2632 | try writer.writeAll(" symbols\n"); |
| 2196 | for (object.symbols.items) |index| { | |
| 2197 | const sym = ctx.macho_file.getSymbol(index); | |
| 2198 | try writer.print(" {}\n", .{sym.fmt(ctx.macho_file)}); | |
| 2633 | for (object.symbols.items, 0..) |sym, i| { | |
| 2634 | const ref = object.getSymbolRef(@intCast(i), macho_file); | |
| 2635 | if (ref.getFile(macho_file) == null) { | |
| 2636 | // TODO any better way of handling this? | |
| 2637 | try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); | |
| 2638 | } else { | |
| 2639 | try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); | |
| 2640 | } | |
| 2641 | } | |
| 2642 | for (object.stab_files.items) |sf| { | |
| 2643 | try writer.print(" stabs({s},{s},{s})\n", .{ | |
| 2644 | sf.getCompDir(object.*), | |
| 2645 | sf.getTuName(object.*), | |
| 2646 | sf.getOsoPath(object.*), | |
| 2647 | }); | |
| 2648 | for (sf.stabs.items) |stab| { | |
| 2649 | try writer.print(" {}", .{stab.fmt(object.*)}); | |
| 2650 | } | |
| 2199 | 2651 | } |
| 2200 | 2652 | } |
| 2201 | 2653 | |
| ... | ... | @@ -2211,7 +2663,7 @@ fn formatPath( |
| 2211 | 2663 | ) !void { |
| 2212 | 2664 | _ = unused_fmt_string; |
| 2213 | 2665 | _ = options; |
| 2214 | if (object.archive) |ar| { | |
| 2666 | if (object.in_archive) |ar| { | |
| 2215 | 2667 | try writer.writeAll(ar.path); |
| 2216 | 2668 | try writer.writeByte('('); |
| 2217 | 2669 | try writer.writeAll(object.path); |
| ... | ... | @@ -2240,32 +2692,71 @@ const StabFile = struct { |
| 2240 | 2692 | comp_dir: u32, |
| 2241 | 2693 | stabs: std.ArrayListUnmanaged(Stab) = .{}, |
| 2242 | 2694 | |
| 2243 | fn getCompDir(sf: StabFile, object: *const Object) [:0]const u8 { | |
| 2695 | fn getCompDir(sf: StabFile, object: Object) [:0]const u8 { | |
| 2244 | 2696 | const nlist = object.symtab.items(.nlist)[sf.comp_dir]; |
| 2245 | 2697 | return object.getString(nlist.n_strx); |
| 2246 | 2698 | } |
| 2247 | 2699 | |
| 2248 | fn getTuName(sf: StabFile, object: *const Object) [:0]const u8 { | |
| 2700 | fn getTuName(sf: StabFile, object: Object) [:0]const u8 { | |
| 2249 | 2701 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 1]; |
| 2250 | 2702 | return object.getString(nlist.n_strx); |
| 2251 | 2703 | } |
| 2252 | 2704 | |
| 2253 | fn getOsoPath(sf: StabFile, object: *const Object) [:0]const u8 { | |
| 2705 | fn getOsoPath(sf: StabFile, object: Object) [:0]const u8 { | |
| 2254 | 2706 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 2]; |
| 2255 | 2707 | return object.getString(nlist.n_strx); |
| 2256 | 2708 | } |
| 2257 | 2709 | |
| 2258 | fn getOsoModTime(sf: StabFile, object: *const Object) u64 { | |
| 2710 | fn getOsoModTime(sf: StabFile, object: Object) u64 { | |
| 2259 | 2711 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 2]; |
| 2260 | 2712 | return nlist.n_value; |
| 2261 | 2713 | } |
| 2262 | 2714 | |
| 2263 | 2715 | const Stab = struct { |
| 2264 | 2716 | is_func: bool = true, |
| 2265 | symbol: ?Symbol.Index = null, | |
| 2717 | index: ?Symbol.Index = null, | |
| 2718 | ||
| 2719 | fn getSymbol(stab: Stab, object: Object) ?Symbol { | |
| 2720 | const index = stab.index orelse return null; | |
| 2721 | return object.symbols.items[index]; | |
| 2722 | } | |
| 2723 | ||
| 2724 | pub fn format( | |
| 2725 | stab: Stab, | |
| 2726 | comptime unused_fmt_string: []const u8, | |
| 2727 | options: std.fmt.FormatOptions, | |
| 2728 | writer: anytype, | |
| 2729 | ) !void { | |
| 2730 | _ = stab; | |
| 2731 | _ = unused_fmt_string; | |
| 2732 | _ = options; | |
| 2733 | _ = writer; | |
| 2734 | @compileError("do not format stabs directly"); | |
| 2735 | } | |
| 2266 | 2736 | |
| 2267 | fn getSymbol(stab: Stab, macho_file: *MachO) ?*Symbol { | |
| 2268 | return if (stab.symbol) |s| macho_file.getSymbol(s) else null; | |
| 2737 | const StabFormatContext = struct { Stab, Object }; | |
| 2738 | ||
| 2739 | pub fn fmt(stab: Stab, object: Object) std.fmt.Formatter(format2) { | |
| 2740 | return .{ .data = .{ stab, object } }; | |
| 2741 | } | |
| 2742 | ||
| 2743 | fn format2( | |
| 2744 | ctx: StabFormatContext, | |
| 2745 | comptime unused_fmt_string: []const u8, | |
| 2746 | options: std.fmt.FormatOptions, | |
| 2747 | writer: anytype, | |
| 2748 | ) !void { | |
| 2749 | _ = unused_fmt_string; | |
| 2750 | _ = options; | |
| 2751 | const stab, const object = ctx; | |
| 2752 | const sym = stab.getSymbol(object).?; | |
| 2753 | if (stab.is_func) { | |
| 2754 | try writer.print("func({d})", .{stab.index.?}); | |
| 2755 | } else if (sym.visibility == .global) { | |
| 2756 | try writer.print("gsym({d})", .{stab.index.?}); | |
| 2757 | } else { | |
| 2758 | try writer.print("stsym({d})", .{stab.index.?}); | |
| 2759 | } | |
| 2269 | 2760 | } |
| 2270 | 2761 | }; |
| 2271 | 2762 | }; |
| ... | ... | @@ -2274,43 +2765,52 @@ const CompileUnit = struct { |
| 2274 | 2765 | comp_dir: u32, |
| 2275 | 2766 | tu_name: u32, |
| 2276 | 2767 | |
| 2277 | fn getCompDir(cu: CompileUnit, object: *const Object) [:0]const u8 { | |
| 2768 | fn getCompDir(cu: CompileUnit, object: Object) [:0]const u8 { | |
| 2278 | 2769 | return object.getString(cu.comp_dir); |
| 2279 | 2770 | } |
| 2280 | 2771 | |
| 2281 | fn getTuName(cu: CompileUnit, object: *const Object) [:0]const u8 { | |
| 2772 | fn getTuName(cu: CompileUnit, object: Object) [:0]const u8 { | |
| 2282 | 2773 | return object.getString(cu.tu_name); |
| 2283 | 2774 | } |
| 2284 | 2775 | }; |
| 2285 | 2776 | |
| 2286 | 2777 | const InArchive = struct { |
| 2287 | 2778 | path: []const u8, |
| 2288 | offset: u64, | |
| 2289 | 2779 | size: u32, |
| 2290 | 2780 | }; |
| 2291 | 2781 | |
| 2782 | const CompactUnwindCtx = struct { | |
| 2783 | rec_index: u32 = 0, | |
| 2784 | rec_count: u32 = 0, | |
| 2785 | reloc_index: u32 = 0, | |
| 2786 | reloc_count: u32 = 0, | |
| 2787 | }; | |
| 2788 | ||
| 2292 | 2789 | const x86_64 = struct { |
| 2293 | 2790 | fn parseRelocs( |
| 2294 | self: *const Object, | |
| 2295 | n_sect: u8, | |
| 2791 | self: *Object, | |
| 2296 | 2792 | sect: macho.section_64, |
| 2297 | 2793 | out: *std.ArrayListUnmanaged(Relocation), |
| 2794 | handle: File.Handle, | |
| 2298 | 2795 | macho_file: *MachO, |
| 2299 | 2796 | ) !void { |
| 2300 | 2797 | const gpa = macho_file.base.comp.gpa; |
| 2301 | 2798 | |
| 2302 | const handle = macho_file.getFileHandle(self.file_handle); | |
| 2303 | const offset = if (self.archive) |ar| ar.offset else 0; | |
| 2304 | 2799 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 2305 | 2800 | defer gpa.free(relocs_buffer); |
| 2306 | 2801 | { |
| 2307 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset); | |
| 2802 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset); | |
| 2308 | 2803 | if (amt != relocs_buffer.len) return error.InputOutput; |
| 2309 | 2804 | } |
| 2310 | 2805 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; |
| 2311 | 2806 | |
| 2312 | const code = try self.getSectionData(@intCast(n_sect), macho_file); | |
| 2807 | const sect_size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 2808 | const code = try gpa.alloc(u8, sect_size); | |
| 2313 | 2809 | defer gpa.free(code); |
| 2810 | { | |
| 2811 | const amt = try handle.preadAll(code, sect.offset + self.offset); | |
| 2812 | if (amt != code.len) return error.InputOutput; | |
| 2813 | } | |
| 2314 | 2814 | |
| 2315 | 2815 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); |
| 2316 | 2816 | |
| ... | ... | @@ -2332,8 +2832,9 @@ const x86_64 = struct { |
| 2332 | 2832 | .X86_64_RELOC_SIGNED_4 => 4, |
| 2333 | 2833 | else => 0, |
| 2334 | 2834 | }; |
| 2835 | var is_extern = rel.r_extern == 1; | |
| 2335 | 2836 | |
| 2336 | const target = if (rel.r_extern == 0) blk: { | |
| 2837 | const target = if (!is_extern) blk: { | |
| 2337 | 2838 | const nsect = rel.r_symbolnum - 1; |
| 2338 | 2839 | const taddr: i64 = if (rel.r_pcrel == 1) |
| 2339 | 2840 | @as(i64, @intCast(sect.addr)) + rel.r_address + addend + 4 |
| ... | ... | @@ -2345,9 +2846,15 @@ const x86_64 = struct { |
| 2345 | 2846 | }); |
| 2346 | 2847 | return error.MalformedObject; |
| 2347 | 2848 | }; |
| 2348 | addend = taddr - @as(i64, @intCast(macho_file.getAtom(target).?.getInputAddress(macho_file))); | |
| 2849 | const target_atom = self.getAtom(target).?; | |
| 2850 | addend = taddr - @as(i64, @intCast(target_atom.getInputAddress(macho_file))); | |
| 2851 | const isec = target_atom.getInputSection(macho_file); | |
| 2852 | if (isCstringLiteral(isec) or isFixedSizeLiteral(isec) or isPtrLiteral(isec)) { | |
| 2853 | is_extern = true; | |
| 2854 | break :blk target_atom.getExtra(macho_file).literal_symbol_index; | |
| 2855 | } | |
| 2349 | 2856 | break :blk target; |
| 2350 | } else self.symbols.items[rel.r_symbolnum]; | |
| 2857 | } else rel.r_symbolnum; | |
| 2351 | 2858 | |
| 2352 | 2859 | const has_subtractor = if (i > 0 and |
| 2353 | 2860 | @as(macho.reloc_type_x86_64, @enumFromInt(relocs[i - 1].r_type)) == .X86_64_RELOC_SUBTRACTOR) |
| ... | ... | @@ -2361,7 +2868,7 @@ const x86_64 = struct { |
| 2361 | 2868 | break :blk true; |
| 2362 | 2869 | } else false; |
| 2363 | 2870 | |
| 2364 | const @"type": Relocation.Type = validateRelocType(rel, rel_type) catch |err| { | |
| 2871 | const @"type": Relocation.Type = validateRelocType(rel, rel_type, is_extern) catch |err| { | |
| 2365 | 2872 | switch (err) { |
| 2366 | 2873 | error.Pcrel => try macho_file.reportParseError2( |
| 2367 | 2874 | self.index, |
| ... | ... | @@ -2388,7 +2895,7 @@ const x86_64 = struct { |
| 2388 | 2895 | }; |
| 2389 | 2896 | |
| 2390 | 2897 | out.appendAssumeCapacity(.{ |
| 2391 | .tag = if (rel.r_extern == 1) .@"extern" else .local, | |
| 2898 | .tag = if (is_extern) .@"extern" else .local, | |
| 2392 | 2899 | .offset = @as(u32, @intCast(rel.r_address)), |
| 2393 | 2900 | .target = target, |
| 2394 | 2901 | .addend = addend, |
| ... | ... | @@ -2403,7 +2910,7 @@ const x86_64 = struct { |
| 2403 | 2910 | } |
| 2404 | 2911 | } |
| 2405 | 2912 | |
| 2406 | fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_x86_64) !Relocation.Type { | |
| 2913 | fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_x86_64, is_extern: bool) !Relocation.Type { | |
| 2407 | 2914 | switch (rel_type) { |
| 2408 | 2915 | .X86_64_RELOC_UNSIGNED => { |
| 2409 | 2916 | if (rel.r_pcrel == 1) return error.Pcrel; |
| ... | ... | @@ -2423,7 +2930,7 @@ const x86_64 = struct { |
| 2423 | 2930 | => { |
| 2424 | 2931 | if (rel.r_pcrel == 0) return error.NonPcrel; |
| 2425 | 2932 | if (rel.r_length != 2) return error.InvalidLength; |
| 2426 | if (rel.r_extern == 0) return error.NonExtern; | |
| 2933 | if (!is_extern) return error.NonExtern; | |
| 2427 | 2934 | return switch (rel_type) { |
| 2428 | 2935 | .X86_64_RELOC_BRANCH => .branch, |
| 2429 | 2936 | .X86_64_RELOC_GOT_LOAD => .got_load, |
| ... | ... | @@ -2454,26 +2961,29 @@ const x86_64 = struct { |
| 2454 | 2961 | |
| 2455 | 2962 | const aarch64 = struct { |
| 2456 | 2963 | fn parseRelocs( |
| 2457 | self: *const Object, | |
| 2458 | n_sect: u8, | |
| 2964 | self: *Object, | |
| 2459 | 2965 | sect: macho.section_64, |
| 2460 | 2966 | out: *std.ArrayListUnmanaged(Relocation), |
| 2967 | handle: File.Handle, | |
| 2461 | 2968 | macho_file: *MachO, |
| 2462 | 2969 | ) !void { |
| 2463 | 2970 | const gpa = macho_file.base.comp.gpa; |
| 2464 | 2971 | |
| 2465 | const handle = macho_file.getFileHandle(self.file_handle); | |
| 2466 | const offset = if (self.archive) |ar| ar.offset else 0; | |
| 2467 | 2972 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 2468 | 2973 | defer gpa.free(relocs_buffer); |
| 2469 | 2974 | { |
| 2470 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset); | |
| 2975 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset); | |
| 2471 | 2976 | if (amt != relocs_buffer.len) return error.InputOutput; |
| 2472 | 2977 | } |
| 2473 | 2978 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; |
| 2474 | 2979 | |
| 2475 | const code = try self.getSectionData(@intCast(n_sect), macho_file); | |
| 2980 | const sect_size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 2981 | const code = try gpa.alloc(u8, sect_size); | |
| 2476 | 2982 | defer gpa.free(code); |
| 2983 | { | |
| 2984 | const amt = try handle.preadAll(code, sect.offset + self.offset); | |
| 2985 | if (amt != code.len) return error.InputOutput; | |
| 2986 | } | |
| 2477 | 2987 | |
| 2478 | 2988 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); |
| 2479 | 2989 | |
| ... | ... | @@ -2519,8 +3029,9 @@ const aarch64 = struct { |
| 2519 | 3029 | } |
| 2520 | 3030 | |
| 2521 | 3031 | const rel_type: macho.reloc_type_arm64 = @enumFromInt(rel.r_type); |
| 3032 | var is_extern = rel.r_extern == 1; | |
| 2522 | 3033 | |
| 2523 | const target = if (rel.r_extern == 0) blk: { | |
| 3034 | const target = if (!is_extern) blk: { | |
| 2524 | 3035 | const nsect = rel.r_symbolnum - 1; |
| 2525 | 3036 | const taddr: i64 = if (rel.r_pcrel == 1) |
| 2526 | 3037 | @as(i64, @intCast(sect.addr)) + rel.r_address + addend |
| ... | ... | @@ -2532,9 +3043,15 @@ const aarch64 = struct { |
| 2532 | 3043 | }); |
| 2533 | 3044 | return error.MalformedObject; |
| 2534 | 3045 | }; |
| 2535 | addend = taddr - @as(i64, @intCast(macho_file.getAtom(target).?.getInputAddress(macho_file))); | |
| 3046 | const target_atom = self.getAtom(target).?; | |
| 3047 | addend = taddr - @as(i64, @intCast(target_atom.getInputAddress(macho_file))); | |
| 3048 | const isec = target_atom.getInputSection(macho_file); | |
| 3049 | if (isCstringLiteral(isec) or isFixedSizeLiteral(isec) or isPtrLiteral(isec)) { | |
| 3050 | is_extern = true; | |
| 3051 | break :blk target_atom.getExtra(macho_file).literal_symbol_index; | |
| 3052 | } | |
| 2536 | 3053 | break :blk target; |
| 2537 | } else self.symbols.items[rel.r_symbolnum]; | |
| 3054 | } else rel.r_symbolnum; | |
| 2538 | 3055 | |
| 2539 | 3056 | const has_subtractor = if (i > 0 and |
| 2540 | 3057 | @as(macho.reloc_type_arm64, @enumFromInt(relocs[i - 1].r_type)) == .ARM64_RELOC_SUBTRACTOR) |
| ... | ... | @@ -2548,7 +3065,7 @@ const aarch64 = struct { |
| 2548 | 3065 | break :blk true; |
| 2549 | 3066 | } else false; |
| 2550 | 3067 | |
| 2551 | const @"type": Relocation.Type = validateRelocType(rel, rel_type) catch |err| { | |
| 3068 | const @"type": Relocation.Type = validateRelocType(rel, rel_type, is_extern) catch |err| { | |
| 2552 | 3069 | switch (err) { |
| 2553 | 3070 | error.Pcrel => try macho_file.reportParseError2( |
| 2554 | 3071 | self.index, |
| ... | ... | @@ -2575,7 +3092,7 @@ const aarch64 = struct { |
| 2575 | 3092 | }; |
| 2576 | 3093 | |
| 2577 | 3094 | out.appendAssumeCapacity(.{ |
| 2578 | .tag = if (rel.r_extern == 1) .@"extern" else .local, | |
| 3095 | .tag = if (is_extern) .@"extern" else .local, | |
| 2579 | 3096 | .offset = @as(u32, @intCast(rel.r_address)), |
| 2580 | 3097 | .target = target, |
| 2581 | 3098 | .addend = addend, |
| ... | ... | @@ -2590,7 +3107,7 @@ const aarch64 = struct { |
| 2590 | 3107 | } |
| 2591 | 3108 | } |
| 2592 | 3109 | |
| 2593 | fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_arm64) !Relocation.Type { | |
| 3110 | fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_arm64, is_extern: bool) !Relocation.Type { | |
| 2594 | 3111 | switch (rel_type) { |
| 2595 | 3112 | .ARM64_RELOC_UNSIGNED => { |
| 2596 | 3113 | if (rel.r_pcrel == 1) return error.Pcrel; |
| ... | ... | @@ -2611,7 +3128,7 @@ const aarch64 = struct { |
| 2611 | 3128 | => { |
| 2612 | 3129 | if (rel.r_pcrel == 0) return error.NonPcrel; |
| 2613 | 3130 | if (rel.r_length != 2) return error.InvalidLength; |
| 2614 | if (rel.r_extern == 0) return error.NonExtern; | |
| 3131 | if (!is_extern) return error.NonExtern; | |
| 2615 | 3132 | return switch (rel_type) { |
| 2616 | 3133 | .ARM64_RELOC_BRANCH26 => .branch, |
| 2617 | 3134 | .ARM64_RELOC_PAGE21 => .page, |
| ... | ... | @@ -2628,7 +3145,7 @@ const aarch64 = struct { |
| 2628 | 3145 | => { |
| 2629 | 3146 | if (rel.r_pcrel == 1) return error.Pcrel; |
| 2630 | 3147 | if (rel.r_length != 2) return error.InvalidLength; |
| 2631 | if (rel.r_extern == 0) return error.NonExtern; | |
| 3148 | if (!is_extern) return error.NonExtern; | |
| 2632 | 3149 | return switch (rel_type) { |
| 2633 | 3150 | .ARM64_RELOC_PAGEOFF12 => .pageoff, |
| 2634 | 3151 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => .got_load_pageoff, |
src/link/MachO/Relocation.zig+23-11| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | tag: enum { @"extern", local }, | |
| 1 | tag: Tag, | |
| 2 | 2 | offset: u32, |
| 3 | 3 | target: u32, |
| 4 | 4 | addend: i64, |
| ... | ... | @@ -10,34 +10,44 @@ meta: packed struct { |
| 10 | 10 | symbolnum: u24, |
| 11 | 11 | }, |
| 12 | 12 | |
| 13 | pub fn getTargetSymbol(rel: Relocation, macho_file: *MachO) *Symbol { | |
| 13 | pub fn getTargetSymbolRef(rel: Relocation, atom: Atom, macho_file: *MachO) MachO.Ref { | |
| 14 | 14 | assert(rel.tag == .@"extern"); |
| 15 | return macho_file.getSymbol(rel.target); | |
| 15 | return atom.getFile(macho_file).getSymbolRef(rel.target, macho_file); | |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | pub fn getTargetAtom(rel: Relocation, macho_file: *MachO) *Atom { | |
| 18 | pub fn getTargetSymbol(rel: Relocation, atom: Atom, macho_file: *MachO) *Symbol { | |
| 19 | assert(rel.tag == .@"extern"); | |
| 20 | const ref = atom.getFile(macho_file).getSymbolRef(rel.target, macho_file); | |
| 21 | return ref.getSymbol(macho_file).?; | |
| 22 | } | |
| 23 | ||
| 24 | pub fn getTargetAtom(rel: Relocation, atom: Atom, macho_file: *MachO) *Atom { | |
| 19 | 25 | assert(rel.tag == .local); |
| 20 | return macho_file.getAtom(rel.target).?; | |
| 26 | return atom.getFile(macho_file).getAtom(rel.target).?; | |
| 21 | 27 | } |
| 22 | 28 | |
| 23 | pub fn getTargetAddress(rel: Relocation, macho_file: *MachO) u64 { | |
| 29 | pub fn getTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 { | |
| 24 | 30 | return switch (rel.tag) { |
| 25 | .local => rel.getTargetAtom(macho_file).getAddress(macho_file), | |
| 26 | .@"extern" => rel.getTargetSymbol(macho_file).getAddress(.{}, macho_file), | |
| 31 | .local => rel.getTargetAtom(atom, macho_file).getAddress(macho_file), | |
| 32 | .@"extern" => rel.getTargetSymbol(atom, macho_file).getAddress(.{}, macho_file), | |
| 27 | 33 | }; |
| 28 | 34 | } |
| 29 | 35 | |
| 30 | pub fn getGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 { | |
| 36 | pub fn getGotTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 { | |
| 31 | 37 | return switch (rel.tag) { |
| 32 | 38 | .local => 0, |
| 33 | .@"extern" => rel.getTargetSymbol(macho_file).getGotAddress(macho_file), | |
| 39 | .@"extern" => rel.getTargetSymbol(atom, macho_file).getGotAddress(macho_file), | |
| 34 | 40 | }; |
| 35 | 41 | } |
| 36 | 42 | |
| 37 | 43 | pub fn getZigGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 { |
| 44 | const zo = macho_file.getZigObject() orelse return 0; | |
| 38 | 45 | return switch (rel.tag) { |
| 39 | 46 | .local => 0, |
| 40 | .@"extern" => rel.getTargetSymbol(macho_file).getZigGotAddress(macho_file), | |
| 47 | .@"extern" => { | |
| 48 | const ref = zo.getSymbolRef(rel.target, macho_file); | |
| 49 | return ref.getSymbol(macho_file).?.getZigGotAddress(macho_file); | |
| 50 | }, | |
| 41 | 51 | }; |
| 42 | 52 | } |
| 43 | 53 | |
| ... | ... | @@ -155,6 +165,8 @@ pub const Type = enum { |
| 155 | 165 | unsigned, |
| 156 | 166 | }; |
| 157 | 167 | |
| 168 | const Tag = enum { local, @"extern" }; | |
| 169 | ||
| 158 | 170 | const assert = std.debug.assert; |
| 159 | 171 | const macho = std.macho; |
| 160 | 172 | const math = std.math; |
src/link/MachO/Symbol.zig+52-37| ... | ... | @@ -9,17 +9,16 @@ name: u32 = 0, |
| 9 | 9 | /// File where this symbol is defined. |
| 10 | 10 | file: File.Index = 0, |
| 11 | 11 | |
| 12 | /// Atom containing this symbol if any. | |
| 13 | /// Index of 0 means there is no associated atom with this symbol. | |
| 12 | /// Reference to Atom containing this symbol if any. | |
| 14 | 13 | /// Use `getAtom` to get the pointer to the atom. |
| 15 | atom: Atom.Index = 0, | |
| 14 | atom_ref: MachO.Ref = .{ .index = 0, .file = 0 }, | |
| 16 | 15 | |
| 17 | 16 | /// Assigned output section index for this symbol. |
| 18 | 17 | out_n_sect: u8 = 0, |
| 19 | 18 | |
| 20 | 19 | /// Index of the source nlist this symbol references. |
| 21 | 20 | /// Use `getNlist` to pull the nlist from the relevant file. |
| 22 | nlist_idx: Index = 0, | |
| 21 | nlist_idx: u32 = 0, | |
| 23 | 22 | |
| 24 | 23 | /// Misc flags for the symbol packaged as packed struct for compression. |
| 25 | 24 | flags: Flags = .{}, |
| ... | ... | @@ -55,16 +54,19 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool { |
| 55 | 54 | } |
| 56 | 55 | |
| 57 | 56 | pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 { |
| 58 | if (symbol.flags.global) return macho_file.strings.getAssumeExists(symbol.name); | |
| 59 | 57 | return switch (symbol.getFile(macho_file).?) { |
| 60 | .dylib => unreachable, // There are no local symbols for dylibs | |
| 61 | 58 | .zig_object => |x| x.strtab.getAssumeExists(symbol.name), |
| 62 | 59 | inline else => |x| x.getString(symbol.name), |
| 63 | 60 | }; |
| 64 | 61 | } |
| 65 | 62 | |
| 66 | 63 | pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom { |
| 67 | return macho_file.getAtom(symbol.atom); | |
| 64 | return symbol.atom_ref.getAtom(macho_file); | |
| 65 | } | |
| 66 | ||
| 67 | pub fn getOutputSectionIndex(symbol: Symbol, macho_file: *MachO) u8 { | |
| 68 | if (symbol.getAtom(macho_file)) |atom| return atom.out_n_sect; | |
| 69 | return symbol.out_n_sect; | |
| 68 | 70 | } |
| 69 | 71 | |
| 70 | 72 | pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { |
| ... | ... | @@ -75,8 +77,10 @@ pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { |
| 75 | 77 | pub fn getNlist(symbol: Symbol, macho_file: *MachO) macho.nlist_64 { |
| 76 | 78 | const file = symbol.getFile(macho_file).?; |
| 77 | 79 | return switch (file) { |
| 80 | .dylib => unreachable, | |
| 81 | .zig_object => unreachable, | |
| 78 | 82 | .object => |x| x.symtab.items(.nlist)[symbol.nlist_idx], |
| 79 | else => unreachable, | |
| 83 | .internal => |x| x.symtab.items[symbol.nlist_idx], | |
| 80 | 84 | }; |
| 81 | 85 | } |
| 82 | 86 | |
| ... | ... | @@ -124,33 +128,35 @@ pub fn getAddress(symbol: Symbol, opts: struct { |
| 124 | 128 | |
| 125 | 129 | pub fn getGotAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 126 | 130 | if (!symbol.flags.has_got) return 0; |
| 127 | const extra = symbol.getExtra(macho_file).?; | |
| 131 | const extra = symbol.getExtra(macho_file); | |
| 128 | 132 | return macho_file.got.getAddress(extra.got, macho_file); |
| 129 | 133 | } |
| 130 | 134 | |
| 131 | 135 | pub fn getStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 132 | 136 | if (!symbol.flags.stubs) return 0; |
| 133 | const extra = symbol.getExtra(macho_file).?; | |
| 137 | const extra = symbol.getExtra(macho_file); | |
| 134 | 138 | return macho_file.stubs.getAddress(extra.stubs, macho_file); |
| 135 | 139 | } |
| 136 | 140 | |
| 137 | 141 | pub fn getObjcStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 138 | 142 | if (!symbol.flags.objc_stubs) return 0; |
| 139 | const extra = symbol.getExtra(macho_file).?; | |
| 143 | const extra = symbol.getExtra(macho_file); | |
| 140 | 144 | return macho_file.objc_stubs.getAddress(extra.objc_stubs, macho_file); |
| 141 | 145 | } |
| 142 | 146 | |
| 143 | 147 | pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 144 | 148 | if (!symbol.flags.objc_stubs) return 0; |
| 145 | const extra = symbol.getExtra(macho_file).?; | |
| 146 | const atom = macho_file.getAtom(extra.objc_selrefs).?; | |
| 147 | assert(atom.flags.alive); | |
| 148 | return atom.getAddress(macho_file); | |
| 149 | const extra = symbol.getExtra(macho_file); | |
| 150 | const file = symbol.getFile(macho_file).?; | |
| 151 | return switch (file) { | |
| 152 | .dylib, .zig_object => unreachable, | |
| 153 | inline else => |x| x.symbols.items[extra.objc_selrefs].getAddress(.{}, macho_file), | |
| 154 | }; | |
| 149 | 155 | } |
| 150 | 156 | |
| 151 | 157 | pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 152 | 158 | if (!symbol.flags.tlv_ptr) return 0; |
| 153 | const extra = symbol.getExtra(macho_file).?; | |
| 159 | const extra = symbol.getExtra(macho_file); | |
| 154 | 160 | return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file); |
| 155 | 161 | } |
| 156 | 162 | |
| ... | ... | @@ -162,14 +168,14 @@ const GetOrCreateZigGotEntryResult = struct { |
| 162 | 168 | pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult { |
| 163 | 169 | assert(!macho_file.base.isRelocatable()); |
| 164 | 170 | assert(symbol.flags.needs_zig_got); |
| 165 | if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).?.zig_got }; | |
| 171 | if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).zig_got }; | |
| 166 | 172 | const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file); |
| 167 | 173 | return .{ .found_existing = false, .index = index }; |
| 168 | 174 | } |
| 169 | 175 | |
| 170 | 176 | pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 171 | 177 | if (!symbol.flags.has_zig_got) return 0; |
| 172 | const extras = symbol.getExtra(macho_file).?; | |
| 178 | const extras = symbol.getExtra(macho_file); | |
| 173 | 179 | return macho_file.zig_got.entryAddress(extras.zig_got, macho_file); |
| 174 | 180 | } |
| 175 | 181 | |
| ... | ... | @@ -180,7 +186,7 @@ pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 { |
| 180 | 186 | const symtab_ctx = switch (file) { |
| 181 | 187 | inline else => |x| x.output_symtab_ctx, |
| 182 | 188 | }; |
| 183 | var idx = symbol.getExtra(macho_file).?.symtab; | |
| 189 | var idx = symbol.getExtra(macho_file).symtab; | |
| 184 | 190 | if (symbol.isLocal()) { |
| 185 | 191 | idx += symtab_ctx.ilocal; |
| 186 | 192 | } else if (symbol.flags.@"export") { |
| ... | ... | @@ -202,11 +208,8 @@ const AddExtraOpts = struct { |
| 202 | 208 | symtab: ?u32 = null, |
| 203 | 209 | }; |
| 204 | 210 | |
| 205 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void { | |
| 206 | if (symbol.getExtra(macho_file) == null) { | |
| 207 | symbol.extra = try macho_file.addSymbolExtra(.{}); | |
| 208 | } | |
| 209 | var extra = symbol.getExtra(macho_file).?; | |
| 211 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) void { | |
| 212 | var extra = symbol.getExtra(macho_file); | |
| 210 | 213 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { |
| 211 | 214 | if (@field(opts, field.name)) |x| { |
| 212 | 215 | @field(extra, field.name) = x; |
| ... | ... | @@ -215,18 +218,22 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void { |
| 215 | 218 | symbol.setExtra(extra, macho_file); |
| 216 | 219 | } |
| 217 | 220 | |
| 218 | pub inline fn getExtra(symbol: Symbol, macho_file: *MachO) ?Extra { | |
| 219 | return macho_file.getSymbolExtra(symbol.extra); | |
| 221 | pub inline fn getExtra(symbol: Symbol, macho_file: *MachO) Extra { | |
| 222 | return switch (symbol.getFile(macho_file).?) { | |
| 223 | inline else => |x| x.getSymbolExtra(symbol.extra), | |
| 224 | }; | |
| 220 | 225 | } |
| 221 | 226 | |
| 222 | 227 | pub inline fn setExtra(symbol: Symbol, extra: Extra, macho_file: *MachO) void { |
| 223 | macho_file.setSymbolExtra(symbol.extra, extra); | |
| 228 | return switch (symbol.getFile(macho_file).?) { | |
| 229 | inline else => |x| x.setSymbolExtra(symbol.extra, extra), | |
| 230 | }; | |
| 224 | 231 | } |
| 225 | 232 | |
| 226 | 233 | pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) void { |
| 227 | 234 | if (symbol.isLocal()) { |
| 228 | 235 | out.n_type = if (symbol.flags.abs) macho.N_ABS else macho.N_SECT; |
| 229 | out.n_sect = if (symbol.flags.abs) 0 else @intCast(symbol.out_n_sect + 1); | |
| 236 | out.n_sect = if (symbol.flags.abs) 0 else @intCast(symbol.getOutputSectionIndex(macho_file) + 1); | |
| 230 | 237 | out.n_desc = 0; |
| 231 | 238 | out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file); |
| 232 | 239 | |
| ... | ... | @@ -238,7 +245,7 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo |
| 238 | 245 | assert(symbol.visibility == .global); |
| 239 | 246 | out.n_type = macho.N_EXT; |
| 240 | 247 | out.n_type |= if (symbol.flags.abs) macho.N_ABS else macho.N_SECT; |
| 241 | out.n_sect = if (symbol.flags.abs) 0 else @intCast(symbol.out_n_sect + 1); | |
| 248 | out.n_sect = if (symbol.flags.abs) 0 else @intCast(symbol.getOutputSectionIndex(macho_file) + 1); | |
| 242 | 249 | out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file); |
| 243 | 250 | out.n_desc = 0; |
| 244 | 251 | |
| ... | ... | @@ -318,15 +325,20 @@ fn format2( |
| 318 | 325 | symbol.getAddress(.{}, ctx.macho_file), |
| 319 | 326 | }); |
| 320 | 327 | if (symbol.getFile(ctx.macho_file)) |file| { |
| 321 | if (symbol.out_n_sect != 0) { | |
| 322 | try writer.print(" : sect({d})", .{symbol.out_n_sect}); | |
| 328 | if (symbol.getOutputSectionIndex(ctx.macho_file) != 0) { | |
| 329 | try writer.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)}); | |
| 323 | 330 | } |
| 324 | 331 | if (symbol.getAtom(ctx.macho_file)) |atom| { |
| 325 | 332 | try writer.print(" : atom({d})", .{atom.atom_index}); |
| 326 | 333 | } |
| 327 | var buf: [2]u8 = .{'_'} ** 2; | |
| 334 | var buf: [3]u8 = .{'_'} ** 3; | |
| 328 | 335 | if (symbol.flags.@"export") buf[0] = 'E'; |
| 329 | 336 | if (symbol.flags.import) buf[1] = 'I'; |
| 337 | switch (symbol.visibility) { | |
| 338 | .local => buf[2] = 'L', | |
| 339 | .hidden => buf[2] = 'H', | |
| 340 | .global => buf[2] = 'G', | |
| 341 | } | |
| 330 | 342 | try writer.print(" : {s}", .{&buf}); |
| 331 | 343 | if (symbol.flags.weak) try writer.writeAll(" : weak"); |
| 332 | 344 | if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab"); |
| ... | ... | @@ -346,11 +358,6 @@ pub const Flags = packed struct { |
| 346 | 358 | /// Whether the symbol is exported at runtime. |
| 347 | 359 | @"export": bool = false, |
| 348 | 360 | |
| 349 | /// Whether the symbol is effectively an extern and takes part in global | |
| 350 | /// symbol resolution. Then, its name will be saved in global string interning | |
| 351 | /// table. | |
| 352 | global: bool = false, | |
| 353 | ||
| 354 | 361 | /// Whether this symbol is weak. |
| 355 | 362 | weak: bool = false, |
| 356 | 363 | |
| ... | ... | @@ -400,6 +407,14 @@ pub const Visibility = enum { |
| 400 | 407 | global, |
| 401 | 408 | hidden, |
| 402 | 409 | local, |
| 410 | ||
| 411 | pub fn rank(vis: Visibility) u2 { | |
| 412 | return switch (vis) { | |
| 413 | .local => 2, | |
| 414 | .hidden => 1, | |
| 415 | .global => 0, | |
| 416 | }; | |
| 417 | } | |
| 403 | 418 | }; |
| 404 | 419 | |
| 405 | 420 | pub const Extra = struct { |
src/link/MachO/UnwindInfo.zig+67-45| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | /// List of all unwind records gathered from all objects and sorted |
| 2 | 2 | /// by allocated relative function address within the section. |
| 3 | records: std.ArrayListUnmanaged(Record.Index) = .{}, | |
| 3 | records: std.ArrayListUnmanaged(Record.Ref) = .{}, | |
| 4 | 4 | |
| 5 | 5 | /// List of all personalities referenced by either unwind info entries |
| 6 | 6 | /// or __eh_frame entries. |
| 7 | personalities: [max_personalities]Symbol.Index = undefined, | |
| 7 | personalities: [max_personalities]MachO.Ref = undefined, | |
| 8 | 8 | personalities_count: u2 = 0, |
| 9 | 9 | |
| 10 | 10 | /// List of common encodings sorted in descending order with the most common first. |
| ... | ... | @@ -25,10 +25,10 @@ pub fn deinit(info: *UnwindInfo, allocator: Allocator) void { |
| 25 | 25 | info.lsdas_lookup.deinit(allocator); |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | fn canFold(macho_file: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) bool { | |
| 28 | fn canFold(macho_file: *MachO, lhs_ref: Record.Ref, rhs_ref: Record.Ref) bool { | |
| 29 | 29 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 30 | const lhs = macho_file.getUnwindRecord(lhs_index); | |
| 31 | const rhs = macho_file.getUnwindRecord(rhs_index); | |
| 30 | const lhs = lhs_ref.getUnwindRecord(macho_file); | |
| 31 | const rhs = rhs_ref.getUnwindRecord(macho_file); | |
| 32 | 32 | if (cpu_arch == .x86_64) { |
| 33 | 33 | if (lhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND) or |
| 34 | 34 | rhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND)) return false; |
| ... | ... | @@ -42,27 +42,31 @@ fn canFold(macho_file: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 45 | const tracy = trace(@src()); | |
| 46 | defer tracy.end(); | |
| 47 | ||
| 45 | 48 | const gpa = macho_file.base.comp.gpa; |
| 46 | 49 | |
| 47 | 50 | log.debug("generating unwind info", .{}); |
| 48 | 51 | |
| 49 | 52 | // Collect all unwind records |
| 50 | 53 | for (macho_file.sections.items(.atoms)) |atoms| { |
| 51 | for (atoms.items) |atom_index| { | |
| 52 | const atom = macho_file.getAtom(atom_index) orelse continue; | |
| 54 | for (atoms.items) |ref| { | |
| 55 | const atom = ref.getAtom(macho_file) orelse continue; | |
| 53 | 56 | if (!atom.flags.alive) continue; |
| 54 | 57 | const recs = atom.getUnwindRecords(macho_file); |
| 58 | const file = atom.getFile(macho_file); | |
| 55 | 59 | try info.records.ensureUnusedCapacity(gpa, recs.len); |
| 56 | 60 | for (recs) |rec| { |
| 57 | if (!macho_file.getUnwindRecord(rec).alive) continue; | |
| 58 | info.records.appendAssumeCapacity(rec); | |
| 61 | if (!file.object.getUnwindRecord(rec).alive) continue; | |
| 62 | info.records.appendAssumeCapacity(.{ .record = rec, .file = file.getIndex() }); | |
| 59 | 63 | } |
| 60 | 64 | } |
| 61 | 65 | } |
| 62 | 66 | |
| 63 | 67 | // Encode records |
| 64 | for (info.records.items) |index| { | |
| 65 | const rec = macho_file.getUnwindRecord(index); | |
| 68 | for (info.records.items) |ref| { | |
| 69 | const rec = ref.getUnwindRecord(macho_file); | |
| 66 | 70 | if (rec.getFde(macho_file)) |fde| { |
| 67 | 71 | rec.enc.setDwarfSectionOffset(@intCast(fde.out_offset)); |
| 68 | 72 | if (fde.getLsdaAtom(macho_file)) |lsda| { |
| ... | ... | @@ -72,27 +76,31 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 72 | 76 | } |
| 73 | 77 | const cie = fde.getCie(macho_file); |
| 74 | 78 | if (cie.getPersonality(macho_file)) |_| { |
| 75 | const personality_index = try info.getOrPutPersonalityFunction(cie.personality.?.index); // TODO handle error | |
| 79 | const object = cie.getObject(macho_file); | |
| 80 | const sym_ref = object.getSymbolRef(cie.personality.?.index, macho_file); | |
| 81 | const personality_index = try info.getOrPutPersonalityFunction(sym_ref); // TODO handle error | |
| 76 | 82 | rec.enc.setPersonalityIndex(personality_index + 1); |
| 77 | 83 | } |
| 78 | 84 | } else if (rec.getPersonality(macho_file)) |_| { |
| 79 | const personality_index = try info.getOrPutPersonalityFunction(rec.personality.?); // TODO handle error | |
| 85 | const object = rec.getObject(macho_file); | |
| 86 | const sym_ref = object.getSymbolRef(rec.personality.?, macho_file); | |
| 87 | const personality_index = try info.getOrPutPersonalityFunction(sym_ref); // TODO handle error | |
| 80 | 88 | rec.enc.setPersonalityIndex(personality_index + 1); |
| 81 | 89 | } |
| 82 | 90 | } |
| 83 | 91 | |
| 84 | 92 | // Sort by assigned relative address within each output section |
| 85 | 93 | const sortFn = struct { |
| 86 | fn sortFn(ctx: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) bool { | |
| 87 | const lhs = ctx.getUnwindRecord(lhs_index); | |
| 88 | const rhs = ctx.getUnwindRecord(rhs_index); | |
| 94 | fn sortFn(ctx: *MachO, lhs_ref: Record.Ref, rhs_ref: Record.Ref) bool { | |
| 95 | const lhs = lhs_ref.getUnwindRecord(ctx); | |
| 96 | const rhs = rhs_ref.getUnwindRecord(ctx); | |
| 89 | 97 | const lhsa = lhs.getAtom(ctx); |
| 90 | 98 | const rhsa = rhs.getAtom(ctx); |
| 91 | 99 | if (lhsa.out_n_sect == rhsa.out_n_sect) return lhs.getAtomAddress(ctx) < rhs.getAtomAddress(ctx); |
| 92 | 100 | return lhsa.out_n_sect < rhsa.out_n_sect; |
| 93 | 101 | } |
| 94 | 102 | }.sortFn; |
| 95 | mem.sort(Record.Index, info.records.items, macho_file, sortFn); | |
| 103 | mem.sort(Record.Ref, info.records.items, macho_file, sortFn); | |
| 96 | 104 | |
| 97 | 105 | // Fold the records |
| 98 | 106 | // Any adjacent two records that share encoding can be folded into one. |
| ... | ... | @@ -101,8 +109,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 101 | 109 | var j: usize = 1; |
| 102 | 110 | while (j < info.records.items.len) : (j += 1) { |
| 103 | 111 | if (canFold(macho_file, info.records.items[i], info.records.items[j])) { |
| 104 | const rec = macho_file.getUnwindRecord(info.records.items[i]); | |
| 105 | rec.length += macho_file.getUnwindRecord(info.records.items[j]).length + 1; | |
| 112 | const rec = info.records.items[i].getUnwindRecord(macho_file); | |
| 113 | rec.length += info.records.items[j].getUnwindRecord(macho_file).length + 1; | |
| 106 | 114 | } else { |
| 107 | 115 | i += 1; |
| 108 | 116 | info.records.items[i] = info.records.items[j]; |
| ... | ... | @@ -111,14 +119,15 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 111 | 119 | info.records.shrinkAndFree(gpa, i + 1); |
| 112 | 120 | } |
| 113 | 121 | |
| 114 | for (info.records.items) |rec_index| { | |
| 115 | const rec = macho_file.getUnwindRecord(rec_index); | |
| 122 | for (info.records.items) |ref| { | |
| 123 | const rec = ref.getUnwindRecord(macho_file); | |
| 116 | 124 | const atom = rec.getAtom(macho_file); |
| 117 | log.debug("@{x}-{x} : {s} : rec({d}) : {}", .{ | |
| 125 | log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {}", .{ | |
| 118 | 126 | rec.getAtomAddress(macho_file), |
| 119 | 127 | rec.getAtomAddress(macho_file) + rec.length, |
| 120 | 128 | atom.getName(macho_file), |
| 121 | rec_index, | |
| 129 | ref.record, | |
| 130 | ref.file, | |
| 122 | 131 | rec.enc, |
| 123 | 132 | }); |
| 124 | 133 | } |
| ... | ... | @@ -161,8 +170,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 161 | 170 | ).init(gpa); |
| 162 | 171 | defer common_encodings_counts.deinit(); |
| 163 | 172 | |
| 164 | for (info.records.items) |rec_index| { | |
| 165 | const rec = macho_file.getUnwindRecord(rec_index); | |
| 173 | for (info.records.items) |ref| { | |
| 174 | const rec = ref.getUnwindRecord(macho_file); | |
| 166 | 175 | if (rec.enc.isDwarf(macho_file)) continue; |
| 167 | 176 | const gop = try common_encodings_counts.getOrPut(rec.enc); |
| 168 | 177 | if (!gop.found_existing) { |
| ... | ... | @@ -190,7 +199,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 190 | 199 | { |
| 191 | 200 | var i: u32 = 0; |
| 192 | 201 | while (i < info.records.items.len) { |
| 193 | const rec = macho_file.getUnwindRecord(info.records.items[i]); | |
| 202 | const rec = info.records.items[i].getUnwindRecord(macho_file); | |
| 194 | 203 | const range_start_max: u64 = rec.getAtomAddress(macho_file) + compressed_entry_func_offset_mask; |
| 195 | 204 | var encoding_count: u9 = info.common_encodings_count; |
| 196 | 205 | var space_left: u32 = second_level_page_words - |
| ... | ... | @@ -202,7 +211,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 202 | 211 | }; |
| 203 | 212 | |
| 204 | 213 | while (space_left >= 1 and i < info.records.items.len) { |
| 205 | const next = macho_file.getUnwindRecord(info.records.items[i]); | |
| 214 | const next = info.records.items[i].getUnwindRecord(macho_file); | |
| 206 | 215 | const is_dwarf = next.enc.isDwarf(macho_file); |
| 207 | 216 | |
| 208 | 217 | if (next.getAtomAddress(macho_file) >= range_start_max) { |
| ... | ... | @@ -244,8 +253,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 244 | 253 | // Save records having an LSDA pointer |
| 245 | 254 | log.debug("LSDA pointers:", .{}); |
| 246 | 255 | try info.lsdas_lookup.ensureTotalCapacityPrecise(gpa, info.records.items.len); |
| 247 | for (info.records.items, 0..) |index, i| { | |
| 248 | const rec = macho_file.getUnwindRecord(index); | |
| 256 | for (info.records.items, 0..) |ref, i| { | |
| 257 | const rec = ref.getUnwindRecord(macho_file); | |
| 249 | 258 | info.lsdas_lookup.appendAssumeCapacity(@intCast(info.lsdas.items.len)); |
| 250 | 259 | if (rec.getLsdaAtom(macho_file)) |lsda| { |
| 251 | 260 | log.debug(" @{x} => lsda({d})", .{ rec.getAtomAddress(macho_file), lsda.atom_index }); |
| ... | ... | @@ -255,6 +264,9 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 255 | 264 | } |
| 256 | 265 | |
| 257 | 266 | pub fn calcSize(info: UnwindInfo) usize { |
| 267 | const tracy = trace(@src()); | |
| 268 | defer tracy.end(); | |
| 269 | ||
| 258 | 270 | var total_size: usize = 0; |
| 259 | 271 | total_size += @sizeOf(macho.unwind_info_section_header); |
| 260 | 272 | total_size += |
| ... | ... | @@ -291,8 +303,8 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 291 | 303 | |
| 292 | 304 | try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count])); |
| 293 | 305 | |
| 294 | for (info.personalities[0..info.personalities_count]) |sym_index| { | |
| 295 | const sym = macho_file.getSymbol(sym_index); | |
| 306 | for (info.personalities[0..info.personalities_count]) |ref| { | |
| 307 | const sym = ref.getSymbol(macho_file).?; | |
| 296 | 308 | try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little); |
| 297 | 309 | } |
| 298 | 310 | |
| ... | ... | @@ -301,7 +313,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 301 | 313 | (info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry)))); |
| 302 | 314 | for (info.pages.items, 0..) |page, i| { |
| 303 | 315 | assert(page.count > 0); |
| 304 | const rec = macho_file.getUnwindRecord(info.records.items[page.start]); | |
| 316 | const rec = info.records.items[page.start].getUnwindRecord(macho_file); | |
| 305 | 317 | try writer.writeStruct(macho.unwind_info_section_header_index_entry{ |
| 306 | 318 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), |
| 307 | 319 | .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)), |
| ... | ... | @@ -310,7 +322,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 310 | 322 | }); |
| 311 | 323 | } |
| 312 | 324 | |
| 313 | const last_rec = macho_file.getUnwindRecord(info.records.items[info.records.items.len - 1]); | |
| 325 | const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file); | |
| 314 | 326 | const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr)); |
| 315 | 327 | try writer.writeStruct(macho.unwind_info_section_header_index_entry{ |
| 316 | 328 | .functionOffset = sentinel_address, |
| ... | ... | @@ -320,7 +332,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 320 | 332 | }); |
| 321 | 333 | |
| 322 | 334 | for (info.lsdas.items) |index| { |
| 323 | const rec = macho_file.getUnwindRecord(info.records.items[index]); | |
| 335 | const rec = info.records.items[index].getUnwindRecord(macho_file); | |
| 324 | 336 | try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{ |
| 325 | 337 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), |
| 326 | 338 | .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)), |
| ... | ... | @@ -340,13 +352,13 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 340 | 352 | @memset(buffer[stream.pos..], 0); |
| 341 | 353 | } |
| 342 | 354 | |
| 343 | fn getOrPutPersonalityFunction(info: *UnwindInfo, sym_index: Symbol.Index) error{TooManyPersonalities}!u2 { | |
| 355 | fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 { | |
| 344 | 356 | comptime var index: u2 = 0; |
| 345 | 357 | inline while (index < max_personalities) : (index += 1) { |
| 346 | if (info.personalities[index] == sym_index) { | |
| 358 | if (info.personalities[index].eql(ref)) { | |
| 347 | 359 | return index; |
| 348 | 360 | } else if (index == info.personalities_count) { |
| 349 | info.personalities[index] = sym_index; | |
| 361 | info.personalities[index] = ref; | |
| 350 | 362 | info.personalities_count += 1; |
| 351 | 363 | return index; |
| 352 | 364 | } |
| ... | ... | @@ -461,16 +473,17 @@ pub const Record = struct { |
| 461 | 473 | } |
| 462 | 474 | |
| 463 | 475 | pub fn getAtom(rec: Record, macho_file: *MachO) *Atom { |
| 464 | return macho_file.getAtom(rec.atom).?; | |
| 476 | return rec.getObject(macho_file).getAtom(rec.atom).?; | |
| 465 | 477 | } |
| 466 | 478 | |
| 467 | 479 | pub fn getLsdaAtom(rec: Record, macho_file: *MachO) ?*Atom { |
| 468 | return macho_file.getAtom(rec.lsda); | |
| 480 | return rec.getObject(macho_file).getAtom(rec.lsda); | |
| 469 | 481 | } |
| 470 | 482 | |
| 471 | 483 | pub fn getPersonality(rec: Record, macho_file: *MachO) ?*Symbol { |
| 472 | 484 | const personality = rec.personality orelse return null; |
| 473 | return macho_file.getSymbol(personality); | |
| 485 | const object = rec.getObject(macho_file); | |
| 486 | return object.getSymbolRef(personality, macho_file).getSymbol(macho_file); | |
| 474 | 487 | } |
| 475 | 488 | |
| 476 | 489 | pub fn getFde(rec: Record, macho_file: *MachO) ?Fde { |
| ... | ... | @@ -537,6 +550,15 @@ pub const Record = struct { |
| 537 | 550 | } |
| 538 | 551 | |
| 539 | 552 | pub const Index = u32; |
| 553 | ||
| 554 | const Ref = struct { | |
| 555 | record: Index, | |
| 556 | file: File.Index, | |
| 557 | ||
| 558 | pub fn getUnwindRecord(ref: Ref, macho_file: *MachO) *Record { | |
| 559 | return macho_file.getFile(ref.file).?.object.getUnwindRecord(ref.record); | |
| 560 | } | |
| 561 | }; | |
| 540 | 562 | }; |
| 541 | 563 | |
| 542 | 564 | const max_personalities = 3; |
| ... | ... | @@ -635,8 +657,8 @@ const Page = struct { |
| 635 | 657 | .entryCount = page.count, |
| 636 | 658 | }); |
| 637 | 659 | |
| 638 | for (info.records.items[page.start..][0..page.count]) |index| { | |
| 639 | const rec = macho_file.getUnwindRecord(index); | |
| 660 | for (info.records.items[page.start..][0..page.count]) |ref| { | |
| 661 | const rec = ref.getUnwindRecord(macho_file); | |
| 640 | 662 | try writer.writeStruct(macho.unwind_info_regular_second_level_entry{ |
| 641 | 663 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), |
| 642 | 664 | .encoding = rec.enc.enc, |
| ... | ... | @@ -658,9 +680,9 @@ const Page = struct { |
| 658 | 680 | } |
| 659 | 681 | |
| 660 | 682 | assert(page.count > 0); |
| 661 | const first_rec = macho_file.getUnwindRecord(info.records.items[page.start]); | |
| 662 | for (info.records.items[page.start..][0..page.count]) |index| { | |
| 663 | const rec = macho_file.getUnwindRecord(index); | |
| 683 | const first_rec = info.records.items[page.start].getUnwindRecord(macho_file); | |
| 684 | for (info.records.items[page.start..][0..page.count]) |ref| { | |
| 685 | const rec = ref.getUnwindRecord(macho_file); | |
| 664 | 686 | const enc_index = blk: { |
| 665 | 687 | if (info.getCommonEncoding(rec.enc)) |id| break :blk id; |
| 666 | 688 | const ncommon = info.common_encodings_count; |
src/link/MachO/ZigObject.zig+522-230| ... | ... | @@ -6,9 +6,15 @@ index: File.Index, |
| 6 | 6 | symtab: std.MultiArrayList(Nlist) = .{}, |
| 7 | 7 | strtab: StringTable = .{}, |
| 8 | 8 | |
| 9 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 10 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 11 | globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{}, | |
| 9 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | |
| 10 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 11 | globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{}, | |
| 12 | /// Maps string index (so name) into nlist index for the global symbol defined within this | |
| 13 | /// module. | |
| 14 | globals_lookup: std.AutoHashMapUnmanaged(u32, u32) = .{}, | |
| 15 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | |
| 16 | atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{}, | |
| 17 | atoms_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 12 | 18 | |
| 13 | 19 | /// Table of tracked LazySymbols. |
| 14 | 20 | lazy_syms: LazySymbolTable = .{}, |
| ... | ... | @@ -48,7 +54,6 @@ relocs: RelocationTable = .{}, |
| 48 | 54 | |
| 49 | 55 | dwarf: ?Dwarf = null, |
| 50 | 56 | |
| 51 | dynamic_relocs: MachO.DynamicRelocs = .{}, | |
| 52 | 57 | output_symtab_ctx: MachO.SymtabCtx = .{}, |
| 53 | 58 | output_ar_state: Archive.ArState = .{}, |
| 54 | 59 | |
| ... | ... | @@ -59,10 +64,13 @@ debug_info_header_dirty: bool = false, |
| 59 | 64 | debug_line_header_dirty: bool = false, |
| 60 | 65 | |
| 61 | 66 | pub fn init(self: *ZigObject, macho_file: *MachO) !void { |
| 67 | const tracy = trace(@src()); | |
| 68 | defer tracy.end(); | |
| 69 | ||
| 62 | 70 | const comp = macho_file.base.comp; |
| 63 | 71 | const gpa = comp.gpa; |
| 64 | 72 | |
| 65 | try self.atoms.append(gpa, 0); // null input section | |
| 73 | try self.atoms.append(gpa, .{ .extra = try self.addAtomExtra(gpa, .{}) }); // null input section | |
| 66 | 74 | try self.strtab.buffer.append(gpa, 0); |
| 67 | 75 | |
| 68 | 76 | switch (comp.config.debug_format) { |
| ... | ... | @@ -85,8 +93,12 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 85 | 93 | self.symtab.deinit(allocator); |
| 86 | 94 | self.strtab.deinit(allocator); |
| 87 | 95 | self.symbols.deinit(allocator); |
| 88 | self.atoms.deinit(allocator); | |
| 96 | self.symbols_extra.deinit(allocator); | |
| 97 | self.globals.deinit(allocator); | |
| 89 | 98 | self.globals_lookup.deinit(allocator); |
| 99 | self.atoms.deinit(allocator); | |
| 100 | self.atoms_indexes.deinit(allocator); | |
| 101 | self.atoms_extra.deinit(allocator); | |
| 90 | 102 | |
| 91 | 103 | { |
| 92 | 104 | var it = self.decls.iterator(); |
| ... | ... | @@ -129,53 +141,73 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 129 | 141 | } |
| 130 | 142 | } |
| 131 | 143 | |
| 132 | fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index { | |
| 144 | fn newSymbol(self: *ZigObject, allocator: Allocator, name: u32, args: struct { | |
| 145 | type: u8 = macho.N_UNDF | macho.N_EXT, | |
| 146 | desc: u16 = 0, | |
| 147 | }) !Symbol.Index { | |
| 133 | 148 | try self.symtab.ensureUnusedCapacity(allocator, 1); |
| 134 | const index = @as(Symbol.Index, @intCast(self.symtab.addOneAssumeCapacity())); | |
| 135 | self.symtab.set(index, .{ | |
| 136 | .nlist = MachO.null_sym, | |
| 149 | try self.symbols.ensureUnusedCapacity(allocator, 1); | |
| 150 | try self.symbols_extra.ensureUnusedCapacity(allocator, @sizeOf(Symbol.Extra)); | |
| 151 | try self.globals.ensureUnusedCapacity(allocator, 1); | |
| 152 | ||
| 153 | const index = self.addSymbolAssumeCapacity(); | |
| 154 | const symbol = &self.symbols.items[index]; | |
| 155 | symbol.name = name; | |
| 156 | symbol.extra = self.addSymbolExtraAssumeCapacity(.{}); | |
| 157 | ||
| 158 | const nlist_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity()); | |
| 159 | self.symtab.set(nlist_idx, .{ | |
| 160 | .nlist = .{ | |
| 161 | .n_strx = name, | |
| 162 | .n_type = args.type, | |
| 163 | .n_sect = 0, | |
| 164 | .n_desc = args.desc, | |
| 165 | .n_value = 0, | |
| 166 | }, | |
| 137 | 167 | .size = 0, |
| 138 | 168 | .atom = 0, |
| 139 | 169 | }); |
| 140 | return index; | |
| 141 | } | |
| 142 | ||
| 143 | pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index { | |
| 144 | const gpa = macho_file.base.comp.gpa; | |
| 145 | const atom_index = try macho_file.addAtom(); | |
| 146 | const symbol_index = try macho_file.addSymbol(); | |
| 147 | const nlist_index = try self.addNlist(gpa); | |
| 170 | symbol.nlist_idx = nlist_idx; | |
| 148 | 171 | |
| 149 | try self.atoms.append(gpa, atom_index); | |
| 150 | try self.symbols.append(gpa, symbol_index); | |
| 172 | self.globals.appendAssumeCapacity(0); | |
| 151 | 173 | |
| 152 | const atom = macho_file.getAtom(atom_index).?; | |
| 153 | atom.file = self.index; | |
| 154 | atom.atom_index = atom_index; | |
| 174 | return index; | |
| 175 | } | |
| 155 | 176 | |
| 156 | const symbol = macho_file.getSymbol(symbol_index); | |
| 157 | symbol.file = self.index; | |
| 158 | symbol.atom = atom_index; | |
| 177 | fn newAtom(self: *ZigObject, allocator: Allocator, name: u32, macho_file: *MachO) !Atom.Index { | |
| 178 | try self.atoms.ensureUnusedCapacity(allocator, 1); | |
| 179 | try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra)); | |
| 180 | try self.atoms_indexes.ensureUnusedCapacity(allocator, 1); | |
| 181 | try self.relocs.ensureUnusedCapacity(allocator, 1); | |
| 159 | 182 | |
| 160 | self.symtab.items(.atom)[nlist_index] = atom_index; | |
| 161 | symbol.nlist_idx = nlist_index; | |
| 183 | const index = self.addAtomAssumeCapacity(); | |
| 184 | self.atoms_indexes.appendAssumeCapacity(index); | |
| 185 | const atom = self.getAtom(index).?; | |
| 186 | atom.name = name; | |
| 162 | 187 | |
| 163 | 188 | const relocs_index = @as(u32, @intCast(self.relocs.items.len)); |
| 164 | const relocs = try self.relocs.addOne(gpa); | |
| 165 | relocs.* = .{}; | |
| 166 | try atom.addExtra(.{ .rel_index = relocs_index, .rel_count = 0 }, macho_file); | |
| 167 | atom.flags.relocs = true; | |
| 189 | self.relocs.addOneAssumeCapacity().* = .{}; | |
| 190 | atom.addExtra(.{ .rel_index = relocs_index, .rel_count = 0 }, macho_file); | |
| 168 | 191 | |
| 169 | return symbol_index; | |
| 192 | return index; | |
| 193 | } | |
| 194 | ||
| 195 | fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name: u32, macho_file: *MachO) !Symbol.Index { | |
| 196 | const atom_index = try self.newAtom(allocator, name, macho_file); | |
| 197 | const sym_index = try self.newSymbol(allocator, name, .{ .type = macho.N_SECT }); | |
| 198 | const sym = &self.symbols.items[sym_index]; | |
| 199 | sym.atom_ref = .{ .index = atom_index, .file = self.index }; | |
| 200 | self.symtab.items(.atom)[sym.nlist_idx] = atom_index; | |
| 201 | return sym_index; | |
| 170 | 202 | } |
| 171 | 203 | |
| 172 | 204 | pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8) !void { |
| 173 | 205 | assert(atom.file == self.index); |
| 174 | 206 | assert(atom.size == buffer.len); |
| 175 | const sect = macho_file.sections.items(.header)[atom.out_n_sect]; | |
| 176 | assert(!sect.isZerofill()); | |
| 207 | const isec = atom.getInputSection(macho_file); | |
| 208 | assert(!isec.isZerofill()); | |
| 177 | 209 | |
| 178 | switch (sect.type()) { | |
| 210 | switch (isec.type()) { | |
| 179 | 211 | macho.S_THREAD_LOCAL_REGULAR => { |
| 180 | 212 | const tlv = self.tlv_initializers.get(atom.atom_index).?; |
| 181 | 213 | @memcpy(buffer, tlv.data); |
| ... | ... | @@ -184,6 +216,7 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 184 | 216 | @memset(buffer, 0); |
| 185 | 217 | }, |
| 186 | 218 | else => { |
| 219 | const sect = macho_file.sections.items(.header)[atom.out_n_sect]; | |
| 187 | 220 | const file_offset = sect.offset + atom.value; |
| 188 | 221 | const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); |
| 189 | 222 | if (amt != buffer.len) return error.InputOutput; |
| ... | ... | @@ -192,102 +225,65 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 192 | 225 | } |
| 193 | 226 | |
| 194 | 227 | pub fn getAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) []const Relocation { |
| 195 | if (!atom.flags.relocs) return &[0]Relocation{}; | |
| 196 | const extra = atom.getExtra(macho_file).?; | |
| 228 | const extra = atom.getExtra(macho_file); | |
| 197 | 229 | const relocs = self.relocs.items[extra.rel_index]; |
| 198 | 230 | return relocs.items[0..extra.rel_count]; |
| 199 | 231 | } |
| 200 | 232 | |
| 201 | 233 | pub fn freeAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) void { |
| 202 | if (atom.flags.relocs) { | |
| 203 | const extra = atom.getExtra(macho_file).?; | |
| 204 | self.relocs.items[extra.rel_index].clearRetainingCapacity(); | |
| 205 | } | |
| 234 | const extra = atom.getExtra(macho_file); | |
| 235 | self.relocs.items[extra.rel_index].clearRetainingCapacity(); | |
| 206 | 236 | } |
| 207 | 237 | |
| 208 | pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void { | |
| 238 | pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) !void { | |
| 209 | 239 | const tracy = trace(@src()); |
| 210 | 240 | defer tracy.end(); |
| 211 | 241 | |
| 212 | for (self.symbols.items, 0..) |index, i| { | |
| 213 | const nlist_idx = @as(Symbol.Index, @intCast(i)); | |
| 214 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | |
| 215 | const atom_index = self.symtab.items(.atom)[nlist_idx]; | |
| 242 | const gpa = macho_file.base.comp.gpa; | |
| 216 | 243 | |
| 244 | for (self.symtab.items(.nlist), self.symtab.items(.atom), self.globals.items, 0..) |nlist, atom_index, *global, i| { | |
| 217 | 245 | if (!nlist.ext()) continue; |
| 218 | if (nlist.undf() and !nlist.tentative()) continue; | |
| 219 | 246 | if (nlist.sect()) { |
| 220 | const atom = macho_file.getAtom(atom_index).?; | |
| 247 | const atom = self.getAtom(atom_index).?; | |
| 221 | 248 | if (!atom.flags.alive) continue; |
| 222 | 249 | } |
| 223 | 250 | |
| 224 | const symbol = macho_file.getSymbol(index); | |
| 251 | const gop = try macho_file.resolver.getOrPut(gpa, .{ | |
| 252 | .index = @intCast(i), | |
| 253 | .file = self.index, | |
| 254 | }, macho_file); | |
| 255 | if (!gop.found_existing) { | |
| 256 | gop.ref.* = .{ .index = 0, .file = 0 }; | |
| 257 | } | |
| 258 | global.* = gop.index; | |
| 259 | ||
| 260 | if (nlist.undf() and !nlist.tentative()) continue; | |
| 261 | if (gop.ref.getFile(macho_file) == null) { | |
| 262 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; | |
| 263 | continue; | |
| 264 | } | |
| 265 | ||
| 225 | 266 | if (self.asFile().getSymbolRank(.{ |
| 226 | 267 | .archive = false, |
| 227 | 268 | .weak = nlist.weakDef(), |
| 228 | 269 | .tentative = nlist.tentative(), |
| 229 | }) < symbol.getSymbolRank(macho_file)) { | |
| 230 | const value = if (nlist.sect()) blk: { | |
| 231 | const atom = macho_file.getAtom(atom_index).?; | |
| 232 | break :blk nlist.n_value - atom.getInputAddress(macho_file); | |
| 233 | } else nlist.n_value; | |
| 234 | const out_n_sect = if (nlist.sect()) macho_file.getAtom(atom_index).?.out_n_sect else 0; | |
| 235 | symbol.value = value; | |
| 236 | symbol.atom = atom_index; | |
| 237 | symbol.out_n_sect = out_n_sect; | |
| 238 | symbol.nlist_idx = nlist_idx; | |
| 239 | symbol.file = self.index; | |
| 240 | symbol.flags.weak = nlist.weakDef(); | |
| 241 | symbol.flags.abs = nlist.abs(); | |
| 242 | symbol.flags.tentative = nlist.tentative(); | |
| 243 | symbol.flags.weak_ref = false; | |
| 244 | symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0; | |
| 245 | symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip(); | |
| 246 | // TODO: symbol.flags.interposable = macho_file.base.isDynLib() and macho_file.options.namespace == .flat and !nlist.pext(); | |
| 247 | symbol.flags.interposable = false; | |
| 248 | ||
| 249 | if (nlist.sect() and | |
| 250 | macho_file.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES) | |
| 251 | { | |
| 252 | symbol.flags.tlv = true; | |
| 253 | } | |
| 254 | } | |
| 255 | ||
| 256 | // Regardless of who the winner is, we still merge symbol visibility here. | |
| 257 | if (nlist.pext() or (nlist.weakDef() and nlist.weakRef())) { | |
| 258 | if (symbol.visibility != .global) { | |
| 259 | symbol.visibility = .hidden; | |
| 260 | } | |
| 261 | } else { | |
| 262 | symbol.visibility = .global; | |
| 270 | }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) { | |
| 271 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; | |
| 263 | 272 | } |
| 264 | 273 | } |
| 265 | 274 | } |
| 266 | 275 | |
| 267 | pub fn resetGlobals(self: *ZigObject, macho_file: *MachO) void { | |
| 268 | for (self.symbols.items, 0..) |sym_index, nlist_idx| { | |
| 269 | if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue; | |
| 270 | const sym = macho_file.getSymbol(sym_index); | |
| 271 | const name = sym.name; | |
| 272 | const global = sym.flags.global; | |
| 273 | const weak_ref = sym.flags.weak_ref; | |
| 274 | sym.* = .{}; | |
| 275 | sym.name = name; | |
| 276 | sym.flags.global = global; | |
| 277 | sym.flags.weak_ref = weak_ref; | |
| 278 | } | |
| 279 | } | |
| 280 | ||
| 281 | 276 | pub fn markLive(self: *ZigObject, macho_file: *MachO) void { |
| 282 | 277 | const tracy = trace(@src()); |
| 283 | 278 | defer tracy.end(); |
| 284 | 279 | |
| 285 | for (self.symbols.items, 0..) |index, nlist_idx| { | |
| 286 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | |
| 280 | for (0..self.symbols.items.len) |i| { | |
| 281 | const nlist = self.symtab.items(.nlist)[i]; | |
| 287 | 282 | if (!nlist.ext()) continue; |
| 288 | 283 | |
| 289 | const sym = macho_file.getSymbol(index); | |
| 290 | const file = sym.getFile(macho_file) orelse continue; | |
| 284 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 285 | const file = ref.getFile(macho_file) orelse continue; | |
| 286 | const sym = ref.getSymbol(macho_file).?; | |
| 291 | 287 | const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative); |
| 292 | 288 | if (should_keep and file == .object and !file.object.alive) { |
| 293 | 289 | file.object.alive = true; |
| ... | ... | @@ -296,20 +292,18 @@ pub fn markLive(self: *ZigObject, macho_file: *MachO) void { |
| 296 | 292 | } |
| 297 | 293 | } |
| 298 | 294 | |
| 299 | pub fn checkDuplicates(self: *ZigObject, dupes: anytype, macho_file: *MachO) !void { | |
| 300 | for (self.symbols.items, 0..) |index, nlist_idx| { | |
| 301 | const sym = macho_file.getSymbol(index); | |
| 302 | if (sym.visibility != .global) continue; | |
| 303 | const file = sym.getFile(macho_file) orelse continue; | |
| 304 | if (file.getIndex() == self.index) continue; | |
| 295 | pub fn mergeSymbolVisibility(self: *ZigObject, macho_file: *MachO) void { | |
| 296 | const tracy = trace(@src()); | |
| 297 | defer tracy.end(); | |
| 305 | 298 | |
| 306 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | |
| 307 | if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) { | |
| 308 | const gop = try dupes.getOrPut(index); | |
| 309 | if (!gop.found_existing) { | |
| 310 | gop.value_ptr.* = .{}; | |
| 311 | } | |
| 312 | try gop.value_ptr.append(macho_file.base.comp.gpa, self.index); | |
| 299 | for (self.symbols.items, 0..) |sym, i| { | |
| 300 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 301 | const global = ref.getSymbol(macho_file) orelse continue; | |
| 302 | if (sym.visibility.rank() < global.visibility.rank()) { | |
| 303 | global.visibility = sym.visibility; | |
| 304 | } | |
| 305 | if (sym.flags.weak_ref) { | |
| 306 | global.flags.weak_ref = true; | |
| 313 | 307 | } |
| 314 | 308 | } |
| 315 | 309 | } |
| ... | ... | @@ -331,7 +325,9 @@ pub fn dedupLiterals(self: *ZigObject, lp: MachO.LiteralPool, macho_file: *MachO |
| 331 | 325 | /// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer. |
| 332 | 326 | /// We need this so that we can write to an archive. |
| 333 | 327 | /// TODO implement writing ZigObject data directly to a buffer instead. |
| 334 | pub fn readFileContents(self: *ZigObject, size: usize, macho_file: *MachO) !void { | |
| 328 | pub fn readFileContents(self: *ZigObject, macho_file: *MachO) !void { | |
| 329 | // Size of the output object file is always the offset + size of the strtab | |
| 330 | const size = macho_file.symtab_cmd.stroff + macho_file.symtab_cmd.strsize; | |
| 335 | 331 | const gpa = macho_file.base.comp.gpa; |
| 336 | 332 | try self.data.resize(gpa, size); |
| 337 | 333 | const amt = try macho_file.base.file.?.preadAll(self.data.items, 0); |
| ... | ... | @@ -340,9 +336,9 @@ pub fn readFileContents(self: *ZigObject, size: usize, macho_file: *MachO) !void |
| 340 | 336 | |
| 341 | 337 | pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, macho_file: *MachO) error{OutOfMemory}!void { |
| 342 | 338 | const gpa = macho_file.base.comp.gpa; |
| 343 | for (self.symbols.items) |sym_index| { | |
| 344 | const sym = macho_file.getSymbol(sym_index); | |
| 345 | const file = sym.getFile(macho_file).?; | |
| 339 | for (self.symbols.items, 0..) |sym, i| { | |
| 340 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 341 | const file = ref.getFile(macho_file).?; | |
| 346 | 342 | assert(file.getIndex() == self.index); |
| 347 | 343 | if (!sym.flags.@"export") continue; |
| 348 | 344 | const off = try ar_symtab.strtab.insert(gpa, sym.getName(macho_file)); |
| ... | ... | @@ -362,9 +358,39 @@ pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !voi |
| 362 | 358 | try writer.writeAll(self.data.items); |
| 363 | 359 | } |
| 364 | 360 | |
| 361 | pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void { | |
| 362 | const tracy = trace(@src()); | |
| 363 | defer tracy.end(); | |
| 364 | ||
| 365 | for (self.symbols.items, 0..) |*sym, i| { | |
| 366 | const nlist = self.symtab.items(.nlist)[i]; | |
| 367 | if (!nlist.ext()) continue; | |
| 368 | if (!nlist.undf()) continue; | |
| 369 | ||
| 370 | if (self.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue; | |
| 371 | ||
| 372 | const is_import = switch (macho_file.undefined_treatment) { | |
| 373 | .@"error" => false, | |
| 374 | .warn, .suppress => nlist.weakRef(), | |
| 375 | .dynamic_lookup => true, | |
| 376 | }; | |
| 377 | if (is_import) { | |
| 378 | sym.value = 0; | |
| 379 | sym.atom_ref = .{ .index = 0, .file = 0 }; | |
| 380 | sym.flags.weak = false; | |
| 381 | sym.flags.weak_ref = nlist.weakRef(); | |
| 382 | sym.flags.import = is_import; | |
| 383 | sym.visibility = .global; | |
| 384 | ||
| 385 | const idx = self.globals.items[i]; | |
| 386 | macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = self.index }; | |
| 387 | } | |
| 388 | } | |
| 389 | } | |
| 390 | ||
| 365 | 391 | pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void { |
| 366 | for (self.atoms.items) |atom_index| { | |
| 367 | const atom = macho_file.getAtom(atom_index) orelse continue; | |
| 392 | for (self.getAtoms()) |atom_index| { | |
| 393 | const atom = self.getAtom(atom_index) orelse continue; | |
| 368 | 394 | if (!atom.flags.alive) continue; |
| 369 | 395 | const sect = atom.getInputSection(macho_file); |
| 370 | 396 | if (sect.isZerofill()) continue; |
| ... | ... | @@ -372,25 +398,168 @@ pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void { |
| 372 | 398 | } |
| 373 | 399 | } |
| 374 | 400 | |
| 375 | pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) !void { | |
| 401 | pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void { | |
| 402 | const gpa = macho_file.base.comp.gpa; | |
| 403 | var has_error = false; | |
| 404 | for (self.getAtoms()) |atom_index| { | |
| 405 | const atom = self.getAtom(atom_index) orelse continue; | |
| 406 | if (!atom.flags.alive) continue; | |
| 407 | const sect = &macho_file.sections.items(.header)[atom.out_n_sect]; | |
| 408 | if (sect.isZerofill()) continue; | |
| 409 | if (!macho_file.isZigSection(atom.out_n_sect)) continue; // Non-Zig sections are handled separately | |
| 410 | if (atom.getRelocs(macho_file).len == 0) continue; | |
| 411 | // TODO: we will resolve and write ZigObject's TLS data twice: | |
| 412 | // once here, and once in writeAtoms | |
| 413 | const atom_size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 414 | const code = try gpa.alloc(u8, atom_size); | |
| 415 | defer gpa.free(code); | |
| 416 | self.getAtomData(macho_file, atom.*, code) catch |err| { | |
| 417 | switch (err) { | |
| 418 | error.InputOutput => { | |
| 419 | try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{ | |
| 420 | atom.getName(macho_file), | |
| 421 | }); | |
| 422 | }, | |
| 423 | else => |e| { | |
| 424 | try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{ | |
| 425 | atom.getName(macho_file), | |
| 426 | @errorName(e), | |
| 427 | }); | |
| 428 | }, | |
| 429 | } | |
| 430 | has_error = true; | |
| 431 | continue; | |
| 432 | }; | |
| 433 | const file_offset = sect.offset + atom.value; | |
| 434 | atom.resolveRelocs(macho_file, code) catch |err| { | |
| 435 | switch (err) { | |
| 436 | error.ResolveFailed => {}, | |
| 437 | else => |e| { | |
| 438 | try macho_file.reportUnexpectedError("unexpected error while resolving relocations: {s}", .{@errorName(e)}); | |
| 439 | }, | |
| 440 | } | |
| 441 | has_error = true; | |
| 442 | continue; | |
| 443 | }; | |
| 444 | try macho_file.base.file.?.pwriteAll(code, file_offset); | |
| 445 | } | |
| 446 | ||
| 447 | if (has_error) return error.ResolveFailed; | |
| 448 | } | |
| 449 | ||
| 450 | pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void { | |
| 451 | for (self.getAtoms()) |atom_index| { | |
| 452 | const atom = self.getAtom(atom_index) orelse continue; | |
| 453 | if (!atom.flags.alive) continue; | |
| 454 | const header = &macho_file.sections.items(.header)[atom.out_n_sect]; | |
| 455 | if (header.isZerofill()) continue; | |
| 456 | if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; | |
| 457 | const nreloc = atom.calcNumRelocs(macho_file); | |
| 458 | atom.addExtra(.{ .rel_out_index = header.nreloc, .rel_out_count = nreloc }, macho_file); | |
| 459 | header.nreloc += nreloc; | |
| 460 | } | |
| 461 | } | |
| 462 | ||
| 463 | pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void { | |
| 464 | const gpa = macho_file.base.comp.gpa; | |
| 465 | ||
| 466 | for (self.getAtoms()) |atom_index| { | |
| 467 | const atom = self.getAtom(atom_index) orelse continue; | |
| 468 | if (!atom.flags.alive) continue; | |
| 469 | const header = macho_file.sections.items(.header)[atom.out_n_sect]; | |
| 470 | const relocs = macho_file.sections.items(.relocs)[atom.out_n_sect].items; | |
| 471 | if (header.isZerofill()) continue; | |
| 472 | if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; | |
| 473 | if (atom.getRelocs(macho_file).len == 0) continue; | |
| 474 | const extra = atom.getExtra(macho_file); | |
| 475 | const atom_size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 476 | const code = try gpa.alloc(u8, atom_size); | |
| 477 | defer gpa.free(code); | |
| 478 | self.getAtomData(macho_file, atom.*, code) catch |err| switch (err) { | |
| 479 | error.InputOutput => { | |
| 480 | try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{ | |
| 481 | atom.getName(macho_file), | |
| 482 | }); | |
| 483 | return error.FlushFailure; | |
| 484 | }, | |
| 485 | else => |e| { | |
| 486 | try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{ | |
| 487 | atom.getName(macho_file), | |
| 488 | @errorName(e), | |
| 489 | }); | |
| 490 | return error.FlushFailure; | |
| 491 | }, | |
| 492 | }; | |
| 493 | const file_offset = header.offset + atom.value; | |
| 494 | try atom.writeRelocs(macho_file, code, relocs[extra.rel_out_index..][0..extra.rel_out_count]); | |
| 495 | try macho_file.base.file.?.pwriteAll(code, file_offset); | |
| 496 | } | |
| 497 | } | |
| 498 | ||
| 499 | // TODO we need this because not everything gets written out incrementally. | |
| 500 | // For example, TLS data gets written out via traditional route. | |
| 501 | // Is there any better way of handling this? | |
| 502 | pub fn writeAtomsRelocatable(self: *ZigObject, macho_file: *MachO) !void { | |
| 503 | const tracy = trace(@src()); | |
| 504 | defer tracy.end(); | |
| 505 | ||
| 506 | for (self.getAtoms()) |atom_index| { | |
| 507 | const atom = self.getAtom(atom_index) orelse continue; | |
| 508 | if (!atom.flags.alive) continue; | |
| 509 | const sect = atom.getInputSection(macho_file); | |
| 510 | if (sect.isZerofill()) continue; | |
| 511 | if (macho_file.isZigSection(atom.out_n_sect)) continue; | |
| 512 | if (atom.getRelocs(macho_file).len == 0) continue; | |
| 513 | const off = std.math.cast(usize, atom.value) orelse return error.Overflow; | |
| 514 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 515 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items; | |
| 516 | try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]); | |
| 517 | const relocs = macho_file.sections.items(.relocs)[atom.out_n_sect].items; | |
| 518 | const extra = atom.getExtra(macho_file); | |
| 519 | try atom.writeRelocs(macho_file, buffer[off..][0..size], relocs[extra.rel_out_index..][0..extra.rel_out_count]); | |
| 520 | } | |
| 521 | } | |
| 522 | ||
| 523 | // TODO we need this because not everything gets written out incrementally. | |
| 524 | // For example, TLS data gets written out via traditional route. | |
| 525 | // Is there any better way of handling this? | |
| 526 | pub fn writeAtoms(self: *ZigObject, macho_file: *MachO) !void { | |
| 527 | const tracy = trace(@src()); | |
| 528 | defer tracy.end(); | |
| 529 | ||
| 530 | for (self.getAtoms()) |atom_index| { | |
| 531 | const atom = self.getAtom(atom_index) orelse continue; | |
| 532 | if (!atom.flags.alive) continue; | |
| 533 | const sect = atom.getInputSection(macho_file); | |
| 534 | if (sect.isZerofill()) continue; | |
| 535 | if (macho_file.isZigSection(atom.out_n_sect)) continue; | |
| 536 | const off = std.math.cast(usize, atom.value) orelse return error.Overflow; | |
| 537 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 538 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items; | |
| 539 | try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]); | |
| 540 | try atom.resolveRelocs(macho_file, buffer[off..][0..size]); | |
| 541 | } | |
| 542 | } | |
| 543 | ||
| 544 | pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) void { | |
| 376 | 545 | const tracy = trace(@src()); |
| 377 | 546 | defer tracy.end(); |
| 378 | 547 | |
| 379 | for (self.symbols.items) |sym_index| { | |
| 380 | const sym = macho_file.getSymbol(sym_index); | |
| 381 | const file = sym.getFile(macho_file) orelse continue; | |
| 548 | for (self.symbols.items, 0..) |*sym, i| { | |
| 549 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 550 | const file = ref.getFile(macho_file) orelse continue; | |
| 382 | 551 | if (file.getIndex() != self.index) continue; |
| 383 | 552 | if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; |
| 384 | 553 | sym.flags.output_symtab = true; |
| 385 | 554 | if (sym.isLocal()) { |
| 386 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); | |
| 555 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); | |
| 387 | 556 | self.output_symtab_ctx.nlocals += 1; |
| 388 | 557 | } else if (sym.flags.@"export") { |
| 389 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file); | |
| 558 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file); | |
| 390 | 559 | self.output_symtab_ctx.nexports += 1; |
| 391 | 560 | } else { |
| 392 | 561 | assert(sym.flags.import); |
| 393 | try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | |
| 562 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | |
| 394 | 563 | self.output_symtab_ctx.nimports += 1; |
| 395 | 564 | } |
| 396 | 565 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1)); |
| ... | ... | @@ -401,17 +570,20 @@ pub fn writeSymtab(self: ZigObject, macho_file: *MachO, ctx: anytype) void { |
| 401 | 570 | const tracy = trace(@src()); |
| 402 | 571 | defer tracy.end(); |
| 403 | 572 | |
| 404 | for (self.symbols.items) |sym_index| { | |
| 405 | const sym = macho_file.getSymbol(sym_index); | |
| 406 | const file = sym.getFile(macho_file) orelse continue; | |
| 573 | var n_strx = self.output_symtab_ctx.stroff; | |
| 574 | for (self.symbols.items, 0..) |sym, i| { | |
| 575 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 576 | const file = ref.getFile(macho_file) orelse continue; | |
| 407 | 577 | if (file.getIndex() != self.index) continue; |
| 408 | 578 | const idx = sym.getOutputSymtabIndex(macho_file) orelse continue; |
| 409 | const n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | |
| 410 | ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file)); | |
| 411 | ctx.strtab.appendAssumeCapacity(0); | |
| 412 | 579 | const out_sym = &ctx.symtab.items[idx]; |
| 413 | 580 | out_sym.n_strx = n_strx; |
| 414 | 581 | sym.setOutputSym(macho_file, out_sym); |
| 582 | const name = sym.getName(macho_file); | |
| 583 | @memcpy(ctx.strtab.items[n_strx..][0..name.len], name); | |
| 584 | n_strx += @intCast(name.len); | |
| 585 | ctx.strtab.items[n_strx] = 0; | |
| 586 | n_strx += 1; | |
| 415 | 587 | } |
| 416 | 588 | } |
| 417 | 589 | |
| ... | ... | @@ -524,9 +696,9 @@ pub fn getDeclVAddr( |
| 524 | 696 | reloc_info: link.File.RelocInfo, |
| 525 | 697 | ) !u64 { |
| 526 | 698 | const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index); |
| 527 | const sym = macho_file.getSymbol(sym_index); | |
| 699 | const sym = self.symbols.items[sym_index]; | |
| 528 | 700 | const vaddr = sym.getAddress(.{}, macho_file); |
| 529 | const parent_atom = macho_file.getSymbol(reloc_info.parent_atom_index).getAtom(macho_file).?; | |
| 701 | const parent_atom = self.symbols.items[reloc_info.parent_atom_index].getAtom(macho_file).?; | |
| 530 | 702 | try parent_atom.addReloc(macho_file, .{ |
| 531 | 703 | .tag = .@"extern", |
| 532 | 704 | .offset = @intCast(reloc_info.offset), |
| ... | ... | @@ -550,9 +722,9 @@ pub fn getAnonDeclVAddr( |
| 550 | 722 | reloc_info: link.File.RelocInfo, |
| 551 | 723 | ) !u64 { |
| 552 | 724 | const sym_index = self.anon_decls.get(decl_val).?.symbol_index; |
| 553 | const sym = macho_file.getSymbol(sym_index); | |
| 725 | const sym = self.symbols.items[sym_index]; | |
| 554 | 726 | const vaddr = sym.getAddress(.{}, macho_file); |
| 555 | const parent_atom = macho_file.getSymbol(reloc_info.parent_atom_index).getAtom(macho_file).?; | |
| 727 | const parent_atom = self.symbols.items[reloc_info.parent_atom_index].getAtom(macho_file).?; | |
| 556 | 728 | try parent_atom.addReloc(macho_file, .{ |
| 557 | 729 | .tag = .@"extern", |
| 558 | 730 | .offset = @intCast(reloc_info.offset), |
| ... | ... | @@ -585,7 +757,7 @@ pub fn lowerAnonDecl( |
| 585 | 757 | else => explicit_alignment, |
| 586 | 758 | }; |
| 587 | 759 | if (self.anon_decls.get(decl_val)) |metadata| { |
| 588 | const existing_alignment = macho_file.getSymbol(metadata.symbol_index).getAtom(macho_file).?.alignment; | |
| 760 | const existing_alignment = self.symbols.items[metadata.symbol_index].getAtom(macho_file).?.alignment; | |
| 589 | 761 | if (decl_alignment.order(existing_alignment).compare(.lte)) |
| 590 | 762 | return .ok; |
| 591 | 763 | } |
| ... | ... | @@ -629,13 +801,10 @@ fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPoo |
| 629 | 801 | } |
| 630 | 802 | |
| 631 | 803 | fn freeDeclMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Index) void { |
| 632 | _ = self; | |
| 633 | const gpa = macho_file.base.comp.gpa; | |
| 634 | const sym = macho_file.getSymbol(sym_index); | |
| 804 | const sym = self.symbols.items[sym_index]; | |
| 635 | 805 | sym.getAtom(macho_file).?.free(macho_file); |
| 636 | 806 | log.debug("adding %{d} to local symbols free list", .{sym_index}); |
| 637 | macho_file.symbols_free_list.append(gpa, sym_index) catch {}; | |
| 638 | macho_file.symbols.items[sym_index] = .{}; | |
| 807 | // TODO redo this | |
| 639 | 808 | // TODO free GOT entry here |
| 640 | 809 | } |
| 641 | 810 | |
| ... | ... | @@ -676,7 +845,7 @@ pub fn updateFunc( |
| 676 | 845 | |
| 677 | 846 | const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index); |
| 678 | 847 | self.freeUnnamedConsts(macho_file, decl_index); |
| 679 | macho_file.getSymbol(sym_index).getAtom(macho_file).?.freeRelocs(macho_file); | |
| 848 | self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); | |
| 680 | 849 | |
| 681 | 850 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 682 | 851 | defer code_buffer.deinit(); |
| ... | ... | @@ -709,7 +878,7 @@ pub fn updateFunc( |
| 709 | 878 | try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code); |
| 710 | 879 | |
| 711 | 880 | if (decl_state) |*ds| { |
| 712 | const sym = macho_file.getSymbol(sym_index); | |
| 881 | const sym = self.symbols.items[sym_index]; | |
| 713 | 882 | try self.dwarf.?.commitDeclState( |
| 714 | 883 | pt, |
| 715 | 884 | decl_index, |
| ... | ... | @@ -744,13 +913,13 @@ pub fn updateDecl( |
| 744 | 913 | const name = decl.name.toSlice(&mod.intern_pool); |
| 745 | 914 | const lib_name = variable.lib_name.toSlice(&mod.intern_pool); |
| 746 | 915 | const index = try self.getGlobalSymbol(macho_file, name, lib_name); |
| 747 | const actual_index = self.symbols.items[index]; | |
| 748 | macho_file.getSymbol(actual_index).flags.needs_got = true; | |
| 916 | const sym = &self.symbols.items[index]; | |
| 917 | sym.flags.needs_got = true; | |
| 749 | 918 | return; |
| 750 | 919 | } |
| 751 | 920 | |
| 752 | 921 | const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index); |
| 753 | macho_file.getSymbol(sym_index).getAtom(macho_file).?.freeRelocs(macho_file); | |
| 922 | self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); | |
| 754 | 923 | |
| 755 | 924 | const gpa = macho_file.base.comp.gpa; |
| 756 | 925 | var code_buffer = std.ArrayList(u8).init(gpa); |
| ... | ... | @@ -773,19 +942,16 @@ pub fn updateDecl( |
| 773 | 942 | return; |
| 774 | 943 | }, |
| 775 | 944 | }; |
| 776 | const sect_index = try self.getDeclOutputSection(macho_file, decl, code); | |
| 777 | const is_threadlocal = switch (macho_file.sections.items(.header)[sect_index].type()) { | |
| 778 | macho.S_THREAD_LOCAL_ZEROFILL, macho.S_THREAD_LOCAL_REGULAR => true, | |
| 779 | else => false, | |
| 780 | }; | |
| 781 | if (is_threadlocal) { | |
| 945 | if (isThreadlocal(macho_file, decl_index)) { | |
| 946 | const sect_index = try self.getDeclOutputSection(macho_file, decl, code); | |
| 782 | 947 | try self.updateTlv(macho_file, pt, decl_index, sym_index, sect_index, code); |
| 783 | 948 | } else { |
| 949 | const sect_index = try self.getDeclOutputSection(macho_file, decl, code); | |
| 784 | 950 | try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code); |
| 785 | 951 | } |
| 786 | 952 | |
| 787 | 953 | if (decl_state) |*ds| { |
| 788 | const sym = macho_file.getSymbol(sym_index); | |
| 954 | const sym = self.symbols.items[sym_index]; | |
| 789 | 955 | try self.dwarf.?.commitDeclState( |
| 790 | 956 | pt, |
| 791 | 957 | decl_index, |
| ... | ... | @@ -817,14 +983,16 @@ fn updateDeclCode( |
| 817 | 983 | const required_alignment = decl.getAlignment(pt); |
| 818 | 984 | |
| 819 | 985 | const sect = &macho_file.sections.items(.header)[sect_index]; |
| 820 | const sym = macho_file.getSymbol(sym_index); | |
| 986 | const sym = &self.symbols.items[sym_index]; | |
| 821 | 987 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 822 | 988 | const atom = sym.getAtom(macho_file).?; |
| 823 | 989 | |
| 824 | 990 | sym.out_n_sect = sect_index; |
| 825 | 991 | atom.out_n_sect = sect_index; |
| 826 | 992 | |
| 827 | sym.name = try self.strtab.insert(gpa, decl.fqn.toSlice(ip)); | |
| 993 | const sym_name = try std.fmt.allocPrintZ(gpa, "_{s}", .{decl.fqn.toSlice(ip)}); | |
| 994 | defer gpa.free(sym_name); | |
| 995 | sym.name = try self.strtab.insert(gpa, sym_name); | |
| 828 | 996 | atom.flags.alive = true; |
| 829 | 997 | atom.name = sym.name; |
| 830 | 998 | nlist.n_strx = sym.name; |
| ... | ... | @@ -851,13 +1019,13 @@ fn updateDeclCode( |
| 851 | 1019 | if (!macho_file.base.isRelocatable()) { |
| 852 | 1020 | log.debug(" (updating offset table entry)", .{}); |
| 853 | 1021 | assert(sym.flags.has_zig_got); |
| 854 | const extra = sym.getExtra(macho_file).?; | |
| 1022 | const extra = sym.getExtra(macho_file); | |
| 855 | 1023 | try macho_file.zig_got.writeOne(macho_file, extra.zig_got); |
| 856 | 1024 | } |
| 857 | 1025 | } |
| 858 | 1026 | } else if (code.len < old_size) { |
| 859 | 1027 | atom.shrink(macho_file); |
| 860 | } else if (macho_file.getAtom(atom.next_index) == null) { | |
| 1028 | } else if (self.getAtom(atom.next_index) == null) { | |
| 861 | 1029 | const needed_size = atom.value + code.len; |
| 862 | 1030 | sect.size = needed_size; |
| 863 | 1031 | } |
| ... | ... | @@ -922,31 +1090,22 @@ fn createTlvInitializer( |
| 922 | 1090 | const gpa = macho_file.base.comp.gpa; |
| 923 | 1091 | const sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{name}); |
| 924 | 1092 | defer gpa.free(sym_name); |
| 1093 | const off = try self.strtab.insert(gpa, sym_name); | |
| 925 | 1094 | |
| 926 | const sym_index = try self.addAtom(macho_file); | |
| 927 | const sym = macho_file.getSymbol(sym_index); | |
| 1095 | const sym_index = try self.newSymbolWithAtom(gpa, off, macho_file); | |
| 1096 | const sym = &self.symbols.items[sym_index]; | |
| 928 | 1097 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 929 | 1098 | const atom = sym.getAtom(macho_file).?; |
| 930 | ||
| 931 | 1099 | sym.out_n_sect = sect_index; |
| 932 | 1100 | atom.out_n_sect = sect_index; |
| 933 | ||
| 934 | sym.value = 0; | |
| 935 | sym.name = try self.strtab.insert(gpa, sym_name); | |
| 936 | 1101 | atom.flags.alive = true; |
| 937 | atom.name = sym.name; | |
| 938 | nlist.n_strx = sym.name; | |
| 939 | nlist.n_sect = sect_index + 1; | |
| 940 | nlist.n_type = macho.N_SECT; | |
| 941 | nlist.n_value = 0; | |
| 942 | self.symtab.items(.size)[sym.nlist_idx] = code.len; | |
| 943 | ||
| 944 | 1102 | atom.alignment = alignment; |
| 945 | 1103 | atom.size = code.len; |
| 1104 | nlist.n_sect = sect_index + 1; | |
| 1105 | self.symtab.items(.size)[sym.nlist_idx] = code.len; | |
| 946 | 1106 | |
| 947 | 1107 | const slice = macho_file.sections.slice(); |
| 948 | 1108 | const header = slice.items(.header)[sect_index]; |
| 949 | const atoms = &slice.items(.atoms)[sect_index]; | |
| 950 | 1109 | |
| 951 | 1110 | const gop = try self.tlv_initializers.getOrPut(gpa, atom.atom_index); |
| 952 | 1111 | assert(!gop.found_existing); // TODO incremental updates |
| ... | ... | @@ -957,8 +1116,6 @@ fn createTlvInitializer( |
| 957 | 1116 | gop.value_ptr.data = try gpa.dupe(u8, code); |
| 958 | 1117 | } |
| 959 | 1118 | |
| 960 | try atoms.append(gpa, atom.atom_index); | |
| 961 | ||
| 962 | 1119 | return sym_index; |
| 963 | 1120 | } |
| 964 | 1121 | |
| ... | ... | @@ -971,7 +1128,7 @@ fn createTlvDescriptor( |
| 971 | 1128 | ) !void { |
| 972 | 1129 | const gpa = macho_file.base.comp.gpa; |
| 973 | 1130 | |
| 974 | const sym = macho_file.getSymbol(sym_index); | |
| 1131 | const sym = &self.symbols.items[sym_index]; | |
| 975 | 1132 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 976 | 1133 | const atom = sym.getAtom(macho_file).?; |
| 977 | 1134 | const alignment = Atom.Alignment.fromNonzeroByteUnits(@alignOf(u64)); |
| ... | ... | @@ -1001,7 +1158,7 @@ fn createTlvDescriptor( |
| 1001 | 1158 | try atom.addReloc(macho_file, .{ |
| 1002 | 1159 | .tag = .@"extern", |
| 1003 | 1160 | .offset = 0, |
| 1004 | .target = self.symbols.items[tlv_bootstrap_index], | |
| 1161 | .target = tlv_bootstrap_index, | |
| 1005 | 1162 | .addend = 0, |
| 1006 | 1163 | .type = .unsigned, |
| 1007 | 1164 | .meta = .{ |
| ... | ... | @@ -1021,11 +1178,9 @@ fn createTlvDescriptor( |
| 1021 | 1178 | .pcrel = false, |
| 1022 | 1179 | .has_subtractor = false, |
| 1023 | 1180 | .length = 3, |
| 1024 | .symbolnum = @intCast(macho_file.getSymbol(init_sym_index).nlist_idx), | |
| 1181 | .symbolnum = @intCast(init_sym_index), | |
| 1025 | 1182 | }, |
| 1026 | 1183 | }); |
| 1027 | ||
| 1028 | try macho_file.sections.items(.atoms)[sect_index].append(gpa, atom.atom_index); | |
| 1029 | 1184 | } |
| 1030 | 1185 | |
| 1031 | 1186 | fn getDeclOutputSection( |
| ... | ... | @@ -1116,8 +1271,8 @@ pub fn lowerUnnamedConst( |
| 1116 | 1271 | return error.CodegenFail; |
| 1117 | 1272 | }, |
| 1118 | 1273 | }; |
| 1119 | const sym = macho_file.getSymbol(sym_index); | |
| 1120 | try unnamed_consts.append(gpa, sym.atom); | |
| 1274 | const sym = self.symbols.items[sym_index]; | |
| 1275 | try unnamed_consts.append(gpa, sym.atom_ref.index); | |
| 1121 | 1276 | return sym_index; |
| 1122 | 1277 | } |
| 1123 | 1278 | |
| ... | ... | @@ -1141,7 +1296,8 @@ fn lowerConst( |
| 1141 | 1296 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1142 | 1297 | defer code_buffer.deinit(); |
| 1143 | 1298 | |
| 1144 | const sym_index = try self.addAtom(macho_file); | |
| 1299 | const name_str_index = try self.strtab.insert(gpa, name); | |
| 1300 | const sym_index = try self.newSymbolWithAtom(gpa, name_str_index, macho_file); | |
| 1145 | 1301 | |
| 1146 | 1302 | const res = try codegen.generateSymbol(&macho_file.base, pt, src_loc, val, &code_buffer, .{ |
| 1147 | 1303 | .none = {}, |
| ... | ... | @@ -1153,20 +1309,15 @@ fn lowerConst( |
| 1153 | 1309 | .fail => |em| return .{ .fail = em }, |
| 1154 | 1310 | }; |
| 1155 | 1311 | |
| 1156 | const sym = macho_file.getSymbol(sym_index); | |
| 1157 | const name_str_index = try self.strtab.insert(gpa, name); | |
| 1158 | sym.name = name_str_index; | |
| 1312 | const sym = &self.symbols.items[sym_index]; | |
| 1159 | 1313 | sym.out_n_sect = output_section_index; |
| 1160 | 1314 | |
| 1161 | 1315 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 1162 | nlist.n_strx = name_str_index; | |
| 1163 | nlist.n_type = macho.N_SECT; | |
| 1164 | 1316 | nlist.n_sect = output_section_index + 1; |
| 1165 | 1317 | self.symtab.items(.size)[sym.nlist_idx] = code.len; |
| 1166 | 1318 | |
| 1167 | 1319 | const atom = sym.getAtom(macho_file).?; |
| 1168 | 1320 | atom.flags.alive = true; |
| 1169 | atom.name = name_str_index; | |
| 1170 | 1321 | atom.alignment = required_alignment; |
| 1171 | 1322 | atom.size = code.len; |
| 1172 | 1323 | atom.out_n_sect = output_section_index; |
| ... | ... | @@ -1175,9 +1326,6 @@ fn lowerConst( |
| 1175 | 1326 | // TODO rename and re-audit this method |
| 1176 | 1327 | errdefer self.freeDeclMetadata(macho_file, sym_index); |
| 1177 | 1328 | |
| 1178 | sym.value = 0; | |
| 1179 | nlist.n_value = 0; | |
| 1180 | ||
| 1181 | 1329 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 1182 | 1330 | const file_offset = sect.offset + atom.value; |
| 1183 | 1331 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| ... | ... | @@ -1219,7 +1367,7 @@ pub fn updateExports( |
| 1219 | 1367 | }, |
| 1220 | 1368 | }; |
| 1221 | 1369 | const sym_index = metadata.symbol_index; |
| 1222 | const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx; | |
| 1370 | const nlist_idx = self.symbols.items[sym_index].nlist_idx; | |
| 1223 | 1371 | const nlist = self.symtab.items(.nlist)[nlist_idx]; |
| 1224 | 1372 | |
| 1225 | 1373 | for (export_indices) |export_idx| { |
| ... | ... | @@ -1255,22 +1403,30 @@ pub fn updateExports( |
| 1255 | 1403 | break :blk global_nlist_index; |
| 1256 | 1404 | }; |
| 1257 | 1405 | const global_nlist = &self.symtab.items(.nlist)[global_nlist_index]; |
| 1406 | const atom_index = self.symtab.items(.atom)[nlist_idx]; | |
| 1407 | const global_sym = &self.symbols.items[global_nlist_index]; | |
| 1258 | 1408 | global_nlist.n_value = nlist.n_value; |
| 1259 | 1409 | global_nlist.n_sect = nlist.n_sect; |
| 1260 | 1410 | global_nlist.n_type = macho.N_EXT | macho.N_SECT; |
| 1261 | 1411 | self.symtab.items(.size)[global_nlist_index] = self.symtab.items(.size)[nlist_idx]; |
| 1262 | self.symtab.items(.atom)[global_nlist_index] = self.symtab.items(.atom)[nlist_idx]; | |
| 1412 | self.symtab.items(.atom)[global_nlist_index] = atom_index; | |
| 1413 | global_sym.atom_ref = .{ .index = atom_index, .file = self.index }; | |
| 1263 | 1414 | |
| 1264 | 1415 | switch (exp.opts.linkage) { |
| 1265 | 1416 | .internal => { |
| 1266 | 1417 | // Symbol should be hidden, or in MachO lingo, private extern. |
| 1267 | 1418 | global_nlist.n_type |= macho.N_PEXT; |
| 1419 | global_sym.visibility = .hidden; | |
| 1420 | }, | |
| 1421 | .strong => { | |
| 1422 | global_sym.visibility = .global; | |
| 1268 | 1423 | }, |
| 1269 | .strong => {}, | |
| 1270 | 1424 | .weak => { |
| 1271 | 1425 | // Weak linkage is specified as part of n_desc field. |
| 1272 | 1426 | // Symbol's n_type is like for a symbol with strong linkage. |
| 1273 | 1427 | global_nlist.n_desc |= macho.N_WEAK_DEF; |
| 1428 | global_sym.visibility = .global; | |
| 1429 | global_sym.flags.weak = true; | |
| 1274 | 1430 | }, |
| 1275 | 1431 | else => unreachable, |
| 1276 | 1432 | } |
| ... | ... | @@ -1323,7 +1479,7 @@ fn updateLazySymbol( |
| 1323 | 1479 | .code => macho_file.zig_text_sect_index.?, |
| 1324 | 1480 | .const_data => macho_file.zig_const_sect_index.?, |
| 1325 | 1481 | }; |
| 1326 | const sym = macho_file.getSymbol(symbol_index); | |
| 1482 | const sym = &self.symbols.items[symbol_index]; | |
| 1327 | 1483 | sym.name = name_str_index; |
| 1328 | 1484 | sym.out_n_sect = output_section_index; |
| 1329 | 1485 | |
| ... | ... | @@ -1383,12 +1539,12 @@ pub fn deleteExport( |
| 1383 | 1539 | const nlist = &self.symtab.items(.nlist)[nlist_index.*]; |
| 1384 | 1540 | self.symtab.items(.size)[nlist_index.*] = 0; |
| 1385 | 1541 | _ = self.globals_lookup.remove(nlist.n_strx); |
| 1386 | const sym_index = macho_file.globals.get(nlist.n_strx).?; | |
| 1387 | const sym = macho_file.getSymbol(sym_index); | |
| 1388 | if (sym.file == self.index) { | |
| 1389 | _ = macho_file.globals.swapRemove(nlist.n_strx); | |
| 1390 | sym.* = .{}; | |
| 1391 | } | |
| 1542 | // TODO actually remove the export | |
| 1543 | // const sym_index = macho_file.globals.get(nlist.n_strx).?; | |
| 1544 | // const sym = &self.symbols.items[sym_index]; | |
| 1545 | // if (sym.file == self.index) { | |
| 1546 | // sym.* = .{}; | |
| 1547 | // } | |
| 1392 | 1548 | nlist.* = MachO.null_sym; |
| 1393 | 1549 | } |
| 1394 | 1550 | |
| ... | ... | @@ -1400,14 +1556,9 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l |
| 1400 | 1556 | const off = try self.strtab.insert(gpa, sym_name); |
| 1401 | 1557 | const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); |
| 1402 | 1558 | if (!lookup_gop.found_existing) { |
| 1403 | const nlist_index = try self.addNlist(gpa); | |
| 1404 | const nlist = &self.symtab.items(.nlist)[nlist_index]; | |
| 1405 | nlist.n_strx = off; | |
| 1406 | nlist.n_type = macho.N_EXT; | |
| 1407 | lookup_gop.value_ptr.* = nlist_index; | |
| 1408 | const global_name_off = try macho_file.strings.insert(gpa, sym_name); | |
| 1409 | const gop = try macho_file.getOrCreateGlobal(global_name_off); | |
| 1410 | try self.symbols.append(gpa, gop.index); | |
| 1559 | const sym_index = try self.newSymbol(gpa, off, .{}); | |
| 1560 | const sym = &self.symbols.items[sym_index]; | |
| 1561 | lookup_gop.value_ptr.* = sym.nlist_idx; | |
| 1411 | 1562 | } |
| 1412 | 1563 | return lookup_gop.value_ptr.*; |
| 1413 | 1564 | } |
| ... | ... | @@ -1420,17 +1571,11 @@ pub fn getOrCreateMetadataForDecl( |
| 1420 | 1571 | const gpa = macho_file.base.comp.gpa; |
| 1421 | 1572 | const gop = try self.decls.getOrPut(gpa, decl_index); |
| 1422 | 1573 | if (!gop.found_existing) { |
| 1423 | const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded; | |
| 1424 | const sym_index = try self.addAtom(macho_file); | |
| 1425 | const mod = macho_file.base.comp.module.?; | |
| 1426 | const decl = mod.declPtr(decl_index); | |
| 1427 | const sym = macho_file.getSymbol(sym_index); | |
| 1428 | if (decl.getOwnedVariable(mod)) |variable| { | |
| 1429 | if (variable.is_threadlocal and any_non_single_threaded) { | |
| 1430 | sym.flags.tlv = true; | |
| 1431 | } | |
| 1432 | } | |
| 1433 | if (!sym.flags.tlv) { | |
| 1574 | const sym_index = try self.newSymbolWithAtom(gpa, 0, macho_file); | |
| 1575 | const sym = &self.symbols.items[sym_index]; | |
| 1576 | if (isThreadlocal(macho_file, decl_index)) { | |
| 1577 | sym.flags.tlv = true; | |
| 1578 | } else { | |
| 1434 | 1579 | sym.flags.needs_zig_got = true; |
| 1435 | 1580 | } |
| 1436 | 1581 | gop.value_ptr.* = .{ .symbol_index = sym_index }; |
| ... | ... | @@ -1464,8 +1609,8 @@ pub fn getOrCreateMetadataForLazySymbol( |
| 1464 | 1609 | }; |
| 1465 | 1610 | switch (metadata.state.*) { |
| 1466 | 1611 | .unused => { |
| 1467 | const symbol_index = try self.addAtom(macho_file); | |
| 1468 | const sym = macho_file.getSymbol(symbol_index); | |
| 1612 | const symbol_index = try self.newSymbolWithAtom(gpa, 0, macho_file); | |
| 1613 | const sym = &self.symbols.items[symbol_index]; | |
| 1469 | 1614 | sym.flags.needs_zig_got = true; |
| 1470 | 1615 | metadata.symbol_index.* = symbol_index; |
| 1471 | 1616 | }, |
| ... | ... | @@ -1479,6 +1624,144 @@ pub fn getOrCreateMetadataForLazySymbol( |
| 1479 | 1624 | return symbol_index; |
| 1480 | 1625 | } |
| 1481 | 1626 | |
| 1627 | fn isThreadlocal(macho_file: *MachO, decl_index: InternPool.DeclIndex) bool { | |
| 1628 | const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded; | |
| 1629 | const zcu = macho_file.base.comp.module.?; | |
| 1630 | const decl = zcu.declPtr(decl_index); | |
| 1631 | const variable = decl.getOwnedVariable(zcu) orelse return false; | |
| 1632 | return variable.is_threadlocal and any_non_single_threaded; | |
| 1633 | } | |
| 1634 | ||
| 1635 | fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index { | |
| 1636 | try self.atoms.ensureUnusedCapacity(allocator, 1); | |
| 1637 | try self.atoms_extra.ensureUnusedCapacity(allocator, 1); | |
| 1638 | return self.addAtomAssumeCapacity(); | |
| 1639 | } | |
| 1640 | ||
| 1641 | fn addAtomAssumeCapacity(self: *ZigObject) Atom.Index { | |
| 1642 | const atom_index: Atom.Index = @intCast(self.atoms.items.len); | |
| 1643 | const atom = self.atoms.addOneAssumeCapacity(); | |
| 1644 | atom.* = .{ | |
| 1645 | .file = self.index, | |
| 1646 | .atom_index = atom_index, | |
| 1647 | .extra = self.addAtomExtraAssumeCapacity(.{}), | |
| 1648 | }; | |
| 1649 | return atom_index; | |
| 1650 | } | |
| 1651 | ||
| 1652 | pub fn getAtom(self: *ZigObject, atom_index: Atom.Index) ?*Atom { | |
| 1653 | if (atom_index == 0) return null; | |
| 1654 | assert(atom_index < self.atoms.items.len); | |
| 1655 | return &self.atoms.items[atom_index]; | |
| 1656 | } | |
| 1657 | ||
| 1658 | pub fn getAtoms(self: *ZigObject) []const Atom.Index { | |
| 1659 | return self.atoms_indexes.items; | |
| 1660 | } | |
| 1661 | ||
| 1662 | fn addAtomExtra(self: *ZigObject, allocator: Allocator, extra: Atom.Extra) !u32 { | |
| 1663 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 1664 | try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len); | |
| 1665 | return self.addAtomExtraAssumeCapacity(extra); | |
| 1666 | } | |
| 1667 | ||
| 1668 | fn addAtomExtraAssumeCapacity(self: *ZigObject, extra: Atom.Extra) u32 { | |
| 1669 | const index = @as(u32, @intCast(self.atoms_extra.items.len)); | |
| 1670 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 1671 | inline for (fields) |field| { | |
| 1672 | self.atoms_extra.appendAssumeCapacity(switch (field.type) { | |
| 1673 | u32 => @field(extra, field.name), | |
| 1674 | else => @compileError("bad field type"), | |
| 1675 | }); | |
| 1676 | } | |
| 1677 | return index; | |
| 1678 | } | |
| 1679 | ||
| 1680 | pub fn getAtomExtra(self: ZigObject, index: u32) Atom.Extra { | |
| 1681 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 1682 | var i: usize = index; | |
| 1683 | var result: Atom.Extra = undefined; | |
| 1684 | inline for (fields) |field| { | |
| 1685 | @field(result, field.name) = switch (field.type) { | |
| 1686 | u32 => self.atoms_extra.items[i], | |
| 1687 | else => @compileError("bad field type"), | |
| 1688 | }; | |
| 1689 | i += 1; | |
| 1690 | } | |
| 1691 | return result; | |
| 1692 | } | |
| 1693 | ||
| 1694 | pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void { | |
| 1695 | assert(index > 0); | |
| 1696 | const fields = @typeInfo(Atom.Extra).Struct.fields; | |
| 1697 | inline for (fields, 0..) |field, i| { | |
| 1698 | self.atoms_extra.items[index + i] = switch (field.type) { | |
| 1699 | u32 => @field(extra, field.name), | |
| 1700 | else => @compileError("bad field type"), | |
| 1701 | }; | |
| 1702 | } | |
| 1703 | } | |
| 1704 | ||
| 1705 | fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index { | |
| 1706 | try self.symbols.ensureUnusedCapacity(allocator, 1); | |
| 1707 | return self.addSymbolAssumeCapacity(); | |
| 1708 | } | |
| 1709 | ||
| 1710 | fn addSymbolAssumeCapacity(self: *ZigObject) Symbol.Index { | |
| 1711 | const index: Symbol.Index = @intCast(self.symbols.items.len); | |
| 1712 | const symbol = self.symbols.addOneAssumeCapacity(); | |
| 1713 | symbol.* = .{ .file = self.index }; | |
| 1714 | return index; | |
| 1715 | } | |
| 1716 | ||
| 1717 | pub fn getSymbolRef(self: ZigObject, index: Symbol.Index, macho_file: *MachO) MachO.Ref { | |
| 1718 | const global_index = self.globals.items[index]; | |
| 1719 | if (macho_file.resolver.get(global_index)) |ref| return ref; | |
| 1720 | return .{ .index = index, .file = self.index }; | |
| 1721 | } | |
| 1722 | ||
| 1723 | pub fn addSymbolExtra(self: *ZigObject, allocator: Allocator, extra: Symbol.Extra) !u32 { | |
| 1724 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 1725 | try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); | |
| 1726 | return self.addSymbolExtraAssumeCapacity(extra); | |
| 1727 | } | |
| 1728 | ||
| 1729 | fn addSymbolExtraAssumeCapacity(self: *ZigObject, extra: Symbol.Extra) u32 { | |
| 1730 | const index = @as(u32, @intCast(self.symbols_extra.items.len)); | |
| 1731 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 1732 | inline for (fields) |field| { | |
| 1733 | self.symbols_extra.appendAssumeCapacity(switch (field.type) { | |
| 1734 | u32 => @field(extra, field.name), | |
| 1735 | else => @compileError("bad field type"), | |
| 1736 | }); | |
| 1737 | } | |
| 1738 | return index; | |
| 1739 | } | |
| 1740 | ||
| 1741 | pub fn getSymbolExtra(self: ZigObject, index: u32) Symbol.Extra { | |
| 1742 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 1743 | var i: usize = index; | |
| 1744 | var result: Symbol.Extra = undefined; | |
| 1745 | inline for (fields) |field| { | |
| 1746 | @field(result, field.name) = switch (field.type) { | |
| 1747 | u32 => self.symbols_extra.items[i], | |
| 1748 | else => @compileError("bad field type"), | |
| 1749 | }; | |
| 1750 | i += 1; | |
| 1751 | } | |
| 1752 | return result; | |
| 1753 | } | |
| 1754 | ||
| 1755 | pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void { | |
| 1756 | const fields = @typeInfo(Symbol.Extra).Struct.fields; | |
| 1757 | inline for (fields, 0..) |field, i| { | |
| 1758 | self.symbols_extra.items[index + i] = switch (field.type) { | |
| 1759 | u32 => @field(extra, field.name), | |
| 1760 | else => @compileError("bad field type"), | |
| 1761 | }; | |
| 1762 | } | |
| 1763 | } | |
| 1764 | ||
| 1482 | 1765 | pub fn asFile(self: *ZigObject) File { |
| 1483 | 1766 | return .{ .zig_object = self }; |
| 1484 | 1767 | } |
| ... | ... | @@ -1504,9 +1787,16 @@ fn formatSymtab( |
| 1504 | 1787 | _ = unused_fmt_string; |
| 1505 | 1788 | _ = options; |
| 1506 | 1789 | try writer.writeAll(" symbols\n"); |
| 1507 | for (ctx.self.symbols.items) |index| { | |
| 1508 | const sym = ctx.macho_file.getSymbol(index); | |
| 1509 | try writer.print(" {}\n", .{sym.fmt(ctx.macho_file)}); | |
| 1790 | const self = ctx.self; | |
| 1791 | const macho_file = ctx.macho_file; | |
| 1792 | for (self.symbols.items, 0..) |sym, i| { | |
| 1793 | const ref = self.getSymbolRef(@intCast(i), macho_file); | |
| 1794 | if (ref.getFile(macho_file) == null) { | |
| 1795 | // TODO any better way of handling this? | |
| 1796 | try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); | |
| 1797 | } else { | |
| 1798 | try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); | |
| 1799 | } | |
| 1510 | 1800 | } |
| 1511 | 1801 | } |
| 1512 | 1802 | |
| ... | ... | @@ -1525,10 +1815,12 @@ fn formatAtoms( |
| 1525 | 1815 | ) !void { |
| 1526 | 1816 | _ = unused_fmt_string; |
| 1527 | 1817 | _ = options; |
| 1818 | const self = ctx.self; | |
| 1819 | const macho_file = ctx.macho_file; | |
| 1528 | 1820 | try writer.writeAll(" atoms\n"); |
| 1529 | for (ctx.self.atoms.items) |atom_index| { | |
| 1530 | const atom = ctx.macho_file.getAtom(atom_index) orelse continue; | |
| 1531 | try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)}); | |
| 1821 | for (self.getAtoms()) |atom_index| { | |
| 1822 | const atom = self.getAtom(atom_index) orelse continue; | |
| 1823 | try writer.print(" {}\n", .{atom.fmt(macho_file)}); | |
| 1532 | 1824 | } |
| 1533 | 1825 | } |
| 1534 | 1826 |
src/link/MachO/dead_strip.zig+45-27| ... | ... | @@ -17,16 +17,16 @@ pub fn gcAtoms(macho_file: *MachO) !void { |
| 17 | 17 | fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho_file: *MachO) !void { |
| 18 | 18 | for (objects) |index| { |
| 19 | 19 | const object = macho_file.getFile(index).?; |
| 20 | for (object.getSymbols()) |sym_index| { | |
| 21 | const sym = macho_file.getSymbol(sym_index); | |
| 22 | const file = sym.getFile(macho_file) orelse continue; | |
| 20 | for (object.getSymbols(), 0..) |*sym, i| { | |
| 21 | const ref = object.getSymbolRef(@intCast(i), macho_file); | |
| 22 | const file = ref.getFile(macho_file) orelse continue; | |
| 23 | 23 | if (file.getIndex() != index) continue; |
| 24 | 24 | if (sym.flags.no_dead_strip or (macho_file.base.isDynLib() and sym.visibility == .global)) |
| 25 | 25 | try markSymbol(sym, roots, macho_file); |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | for (object.getAtoms()) |atom_index| { |
| 29 | const atom = macho_file.getAtom(atom_index).?; | |
| 29 | const atom = object.getAtom(atom_index) orelse continue; | |
| 30 | 30 | const isec = atom.getInputSection(macho_file); |
| 31 | 31 | switch (isec.type()) { |
| 32 | 32 | macho.S_MOD_INIT_FUNC_POINTERS, |
| ... | ... | @@ -41,8 +41,9 @@ fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | for (macho_file.objects.items) |index| { |
| 44 | for (macho_file.getFile(index).?.object.unwind_records.items) |cu_index| { | |
| 45 | const cu = macho_file.getUnwindRecord(cu_index); | |
| 44 | const object = macho_file.getFile(index).?.object; | |
| 45 | for (object.unwind_records_indexes.items) |cu_index| { | |
| 46 | const cu = object.getUnwindRecord(cu_index); | |
| 46 | 47 | if (!cu.alive) continue; |
| 47 | 48 | if (cu.getFde(macho_file)) |fde| { |
| 48 | 49 | if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| try markSymbol(sym, roots, macho_file); |
| ... | ... | @@ -50,19 +51,27 @@ fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho |
| 50 | 51 | } |
| 51 | 52 | } |
| 52 | 53 | |
| 53 | for (macho_file.undefined_symbols.items) |sym_index| { | |
| 54 | const sym = macho_file.getSymbol(sym_index); | |
| 55 | try markSymbol(sym, roots, macho_file); | |
| 56 | } | |
| 54 | if (macho_file.getInternalObject()) |obj| { | |
| 55 | for (obj.force_undefined.items) |sym_index| { | |
| 56 | const ref = obj.getSymbolRef(sym_index, macho_file); | |
| 57 | if (ref.getFile(macho_file) != null) { | |
| 58 | const sym = ref.getSymbol(macho_file).?; | |
| 59 | try markSymbol(sym, roots, macho_file); | |
| 60 | } | |
| 61 | } | |
| 57 | 62 | |
| 58 | for (&[_]?Symbol.Index{ | |
| 59 | macho_file.entry_index, | |
| 60 | macho_file.dyld_stub_binder_index, | |
| 61 | macho_file.objc_msg_send_index, | |
| 62 | }) |index| { | |
| 63 | if (index) |idx| { | |
| 64 | const sym = macho_file.getSymbol(idx); | |
| 65 | try markSymbol(sym, roots, macho_file); | |
| 63 | for (&[_]?Symbol.Index{ | |
| 64 | obj.entry_index, | |
| 65 | obj.dyld_stub_binder_index, | |
| 66 | obj.objc_msg_send_index, | |
| 67 | }) |index| { | |
| 68 | if (index) |idx| { | |
| 69 | const ref = obj.getSymbolRef(idx, macho_file); | |
| 70 | if (ref.getFile(macho_file) != null) { | |
| 71 | const sym = ref.getSymbol(macho_file).?; | |
| 72 | try markSymbol(sym, roots, macho_file); | |
| 73 | } | |
| 74 | } | |
| 66 | 75 | } |
| 67 | 76 | } |
| 68 | 77 | } |
| ... | ... | @@ -88,8 +97,9 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void { |
| 88 | 97 | loop = false; |
| 89 | 98 | |
| 90 | 99 | for (objects) |index| { |
| 91 | for (macho_file.getFile(index).?.getAtoms()) |atom_index| { | |
| 92 | const atom = macho_file.getAtom(atom_index).?; | |
| 100 | const file = macho_file.getFile(index).?; | |
| 101 | for (file.getAtoms()) |atom_index| { | |
| 102 | const atom = file.getAtom(atom_index) orelse continue; | |
| 93 | 103 | const isec = atom.getInputSection(macho_file); |
| 94 | 104 | if (isec.isDontDeadStripIfReferencesLive() and |
| 95 | 105 | !(mem.eql(u8, isec.sectName(), "__eh_frame") or |
| ... | ... | @@ -119,16 +129,20 @@ fn markLive(atom: *Atom, macho_file: *MachO) void { |
| 119 | 129 | |
| 120 | 130 | for (atom.getRelocs(macho_file)) |rel| { |
| 121 | 131 | const target_atom = switch (rel.tag) { |
| 122 | .local => rel.getTargetAtom(macho_file), | |
| 123 | .@"extern" => rel.getTargetSymbol(macho_file).getAtom(macho_file), | |
| 132 | .local => rel.getTargetAtom(atom.*, macho_file), | |
| 133 | .@"extern" => blk: { | |
| 134 | const ref = rel.getTargetSymbolRef(atom.*, macho_file); | |
| 135 | break :blk if (ref.getSymbol(macho_file)) |sym| sym.getAtom(macho_file) else null; | |
| 136 | }, | |
| 124 | 137 | }; |
| 125 | 138 | if (target_atom) |ta| { |
| 126 | 139 | if (markAtom(ta)) markLive(ta, macho_file); |
| 127 | 140 | } |
| 128 | 141 | } |
| 129 | 142 | |
| 143 | const file = atom.getFile(macho_file); | |
| 130 | 144 | for (atom.getUnwindRecords(macho_file)) |cu_index| { |
| 131 | const cu = macho_file.getUnwindRecord(cu_index); | |
| 145 | const cu = file.object.getUnwindRecord(cu_index); | |
| 132 | 146 | const cu_atom = cu.getAtom(macho_file); |
| 133 | 147 | if (markAtom(cu_atom)) markLive(cu_atom, macho_file); |
| 134 | 148 | |
| ... | ... | @@ -149,8 +163,11 @@ fn markLive(atom: *Atom, macho_file: *MachO) void { |
| 149 | 163 | fn refersLive(atom: *Atom, macho_file: *MachO) bool { |
| 150 | 164 | for (atom.getRelocs(macho_file)) |rel| { |
| 151 | 165 | const target_atom = switch (rel.tag) { |
| 152 | .local => rel.getTargetAtom(macho_file), | |
| 153 | .@"extern" => rel.getTargetSymbol(macho_file).getAtom(macho_file), | |
| 166 | .local => rel.getTargetAtom(atom.*, macho_file), | |
| 167 | .@"extern" => blk: { | |
| 168 | const ref = rel.getTargetSymbolRef(atom.*, macho_file); | |
| 169 | break :blk if (ref.getSymbol(macho_file)) |sym| sym.getAtom(macho_file) else null; | |
| 170 | }, | |
| 154 | 171 | }; |
| 155 | 172 | if (target_atom) |ta| { |
| 156 | 173 | if (ta.flags.alive) return true; |
| ... | ... | @@ -161,8 +178,9 @@ fn refersLive(atom: *Atom, macho_file: *MachO) bool { |
| 161 | 178 | |
| 162 | 179 | fn prune(objects: []const File.Index, macho_file: *MachO) void { |
| 163 | 180 | for (objects) |index| { |
| 164 | for (macho_file.getFile(index).?.getAtoms()) |atom_index| { | |
| 165 | const atom = macho_file.getAtom(atom_index).?; | |
| 181 | const file = macho_file.getFile(index).?; | |
| 182 | for (file.getAtoms()) |atom_index| { | |
| 183 | const atom = file.getAtom(atom_index) orelse continue; | |
| 166 | 184 | if (atom.flags.alive and !atom.flags.visited) { |
| 167 | 185 | atom.flags.alive = false; |
| 168 | 186 | atom.markUnwindRecordsDead(macho_file); |
src/link/MachO/dyld_info/Rebase.zig+113-15| ... | ... | @@ -1,14 +1,3 @@ |
| 1 | const Rebase = @This(); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const assert = std.debug.assert; | |
| 5 | const leb = std.leb; | |
| 6 | const log = std.log.scoped(.link_dyld_info); | |
| 7 | const macho = std.macho; | |
| 8 | const testing = std.testing; | |
| 9 | ||
| 10 | const Allocator = std.mem.Allocator; | |
| 11 | ||
| 12 | 1 | entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 13 | 2 | buffer: std.ArrayListUnmanaged(u8) = .{}, |
| 14 | 3 | |
| ... | ... | @@ -30,11 +19,107 @@ pub fn deinit(rebase: *Rebase, gpa: Allocator) void { |
| 30 | 19 | rebase.buffer.deinit(gpa); |
| 31 | 20 | } |
| 32 | 21 | |
| 33 | pub fn size(rebase: Rebase) u64 { | |
| 34 | return @as(u64, @intCast(rebase.buffer.items.len)); | |
| 22 | pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void { | |
| 23 | const tracy = trace(@src()); | |
| 24 | defer tracy.end(); | |
| 25 | ||
| 26 | const gpa = macho_file.base.comp.gpa; | |
| 27 | ||
| 28 | var objects = try std.ArrayList(File.Index).initCapacity(gpa, macho_file.objects.items.len + 2); | |
| 29 | defer objects.deinit(); | |
| 30 | objects.appendSliceAssumeCapacity(macho_file.objects.items); | |
| 31 | if (macho_file.getZigObject()) |obj| objects.appendAssumeCapacity(obj.index); | |
| 32 | if (macho_file.getInternalObject()) |obj| objects.appendAssumeCapacity(obj.index); | |
| 33 | ||
| 34 | for (objects.items) |index| { | |
| 35 | const file = macho_file.getFile(index).?; | |
| 36 | for (file.getAtoms()) |atom_index| { | |
| 37 | const atom = file.getAtom(atom_index) orelse continue; | |
| 38 | if (!atom.flags.alive) continue; | |
| 39 | if (atom.getInputSection(macho_file).isZerofill()) continue; | |
| 40 | const atom_addr = atom.getAddress(macho_file); | |
| 41 | const seg_id = macho_file.sections.items(.segment_id)[atom.out_n_sect]; | |
| 42 | const seg = macho_file.segments.items[seg_id]; | |
| 43 | for (atom.getRelocs(macho_file)) |rel| { | |
| 44 | if (rel.type != .unsigned or rel.meta.length != 3) continue; | |
| 45 | if (rel.tag == .@"extern") { | |
| 46 | const sym = rel.getTargetSymbol(atom.*, macho_file); | |
| 47 | if (sym.isTlvInit(macho_file)) continue; | |
| 48 | if (sym.flags.import) continue; | |
| 49 | } | |
| 50 | const rel_offset = rel.offset - atom.off; | |
| 51 | try rebase.entries.append(gpa, .{ | |
| 52 | .offset = atom_addr + rel_offset - seg.vmaddr, | |
| 53 | .segment_id = seg_id, | |
| 54 | }); | |
| 55 | } | |
| 56 | } | |
| 57 | } | |
| 58 | ||
| 59 | if (macho_file.zig_got_sect_index) |sid| { | |
| 60 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 61 | const seg = macho_file.segments.items[seg_id]; | |
| 62 | for (0..macho_file.zig_got.entries.items.len) |idx| { | |
| 63 | const addr = macho_file.zig_got.entryAddress(@intCast(idx), macho_file); | |
| 64 | try rebase.entries.append(gpa, .{ | |
| 65 | .offset = addr - seg.vmaddr, | |
| 66 | .segment_id = seg_id, | |
| 67 | }); | |
| 68 | } | |
| 69 | } | |
| 70 | ||
| 71 | if (macho_file.got_sect_index) |sid| { | |
| 72 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 73 | const seg = macho_file.segments.items[seg_id]; | |
| 74 | for (macho_file.got.symbols.items, 0..) |ref, idx| { | |
| 75 | const sym = ref.getSymbol(macho_file).?; | |
| 76 | const addr = macho_file.got.getAddress(@intCast(idx), macho_file); | |
| 77 | if (!sym.flags.import) { | |
| 78 | try rebase.entries.append(gpa, .{ | |
| 79 | .offset = addr - seg.vmaddr, | |
| 80 | .segment_id = seg_id, | |
| 81 | }); | |
| 82 | } | |
| 83 | } | |
| 84 | } | |
| 85 | ||
| 86 | if (macho_file.la_symbol_ptr_sect_index) |sid| { | |
| 87 | const sect = macho_file.sections.items(.header)[sid]; | |
| 88 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 89 | const seg = macho_file.segments.items[seg_id]; | |
| 90 | for (macho_file.stubs.symbols.items, 0..) |ref, idx| { | |
| 91 | const sym = ref.getSymbol(macho_file).?; | |
| 92 | const addr = sect.addr + idx * @sizeOf(u64); | |
| 93 | const rebase_entry = Rebase.Entry{ | |
| 94 | .offset = addr - seg.vmaddr, | |
| 95 | .segment_id = seg_id, | |
| 96 | }; | |
| 97 | if ((sym.flags.import and !sym.flags.weak) or !sym.flags.import) { | |
| 98 | try rebase.entries.append(gpa, rebase_entry); | |
| 99 | } | |
| 100 | } | |
| 101 | } | |
| 102 | ||
| 103 | if (macho_file.tlv_ptr_sect_index) |sid| { | |
| 104 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 105 | const seg = macho_file.segments.items[seg_id]; | |
| 106 | for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| { | |
| 107 | const sym = ref.getSymbol(macho_file).?; | |
| 108 | const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file); | |
| 109 | if (!sym.flags.import) { | |
| 110 | try rebase.entries.append(gpa, .{ | |
| 111 | .offset = addr - seg.vmaddr, | |
| 112 | .segment_id = seg_id, | |
| 113 | }); | |
| 114 | } | |
| 115 | } | |
| 116 | } | |
| 117 | ||
| 118 | try rebase.finalize(gpa); | |
| 119 | macho_file.dyld_info_cmd.rebase_size = mem.alignForward(u32, @intCast(rebase.buffer.items.len), @alignOf(u64)); | |
| 35 | 120 | } |
| 36 | 121 | |
| 37 | pub fn finalize(rebase: *Rebase, gpa: Allocator) !void { | |
| 122 | fn finalize(rebase: *Rebase, gpa: Allocator) !void { | |
| 38 | 123 | if (rebase.entries.items.len == 0) return; |
| 39 | 124 | |
| 40 | 125 | const writer = rebase.buffer.writer(gpa); |
| ... | ... | @@ -198,7 +283,6 @@ fn done(writer: anytype) !void { |
| 198 | 283 | } |
| 199 | 284 | |
| 200 | 285 | pub fn write(rebase: Rebase, writer: anytype) !void { |
| 201 | if (rebase.size() == 0) return; | |
| 202 | 286 | try writer.writeAll(rebase.buffer.items); |
| 203 | 287 | } |
| 204 | 288 | |
| ... | ... | @@ -574,3 +658,17 @@ test "rebase - composite" { |
| 574 | 658 | macho.REBASE_OPCODE_DONE, |
| 575 | 659 | }, rebase.buffer.items); |
| 576 | 660 | } |
| 661 | ||
| 662 | const std = @import("std"); | |
| 663 | const assert = std.debug.assert; | |
| 664 | const leb = std.leb; | |
| 665 | const log = std.log.scoped(.link_dyld_info); | |
| 666 | const macho = std.macho; | |
| 667 | const mem = std.mem; | |
| 668 | const testing = std.testing; | |
| 669 | const trace = @import("../../../tracy.zig").trace; | |
| 670 | ||
| 671 | const Allocator = mem.Allocator; | |
| 672 | const File = @import("../file.zig").File; | |
| 673 | const MachO = @import("../../MachO.zig"); | |
| 674 | const Rebase = @This(); |
src/link/MachO/dyld_info/Trie.zig+262-453| ... | ... | @@ -28,463 +28,310 @@ |
| 28 | 28 | //! After the optional exported symbol information is a byte of how many edges (0-255) that |
| 29 | 29 | //! this node has leaving it, followed by each edge. Each edge is a zero terminated UTF8 of |
| 30 | 30 | //! the addition chars in the symbol, followed by a uleb128 offset for the node that edge points to. |
| 31 | const Trie = @This(); | |
| 32 | ||
| 33 | const std = @import("std"); | |
| 34 | const mem = std.mem; | |
| 35 | const leb = std.leb; | |
| 36 | const log = std.log.scoped(.macho); | |
| 37 | const macho = std.macho; | |
| 38 | const testing = std.testing; | |
| 39 | const assert = std.debug.assert; | |
| 40 | const Allocator = mem.Allocator; | |
| 41 | ||
| 42 | pub const Node = struct { | |
| 43 | base: *Trie, | |
| 44 | ||
| 45 | /// Terminal info associated with this node. | |
| 46 | /// If this node is not a terminal node, info is null. | |
| 47 | terminal_info: ?struct { | |
| 48 | /// Export flags associated with this exported symbol. | |
| 49 | export_flags: u64, | |
| 50 | /// VM address offset wrt to the section this symbol is defined against. | |
| 51 | vmaddr_offset: u64, | |
| 52 | } = null, | |
| 53 | ||
| 54 | /// Offset of this node in the trie output byte stream. | |
| 55 | trie_offset: ?u64 = null, | |
| 56 | ||
| 57 | /// List of all edges originating from this node. | |
| 58 | edges: std.ArrayListUnmanaged(Edge) = .{}, | |
| 59 | ||
| 60 | node_dirty: bool = true, | |
| 61 | ||
| 62 | /// Edge connecting to nodes in the trie. | |
| 63 | pub const Edge = struct { | |
| 64 | from: *Node, | |
| 65 | to: *Node, | |
| 66 | label: []u8, | |
| 67 | ||
| 68 | fn deinit(self: *Edge, allocator: Allocator) void { | |
| 69 | self.to.deinit(allocator); | |
| 70 | allocator.destroy(self.to); | |
| 71 | allocator.free(self.label); | |
| 72 | self.from = undefined; | |
| 73 | self.to = undefined; | |
| 74 | self.label = undefined; | |
| 75 | } | |
| 76 | }; | |
| 77 | ||
| 78 | fn deinit(self: *Node, allocator: Allocator) void { | |
| 79 | for (self.edges.items) |*edge| { | |
| 80 | edge.deinit(allocator); | |
| 81 | } | |
| 82 | self.edges.deinit(allocator); | |
| 83 | } | |
| 84 | ||
| 85 | /// Inserts a new node starting from `self`. | |
| 86 | fn put(self: *Node, allocator: Allocator, label: []const u8) !*Node { | |
| 87 | // Check for match with edges from this node. | |
| 88 | for (self.edges.items) |*edge| { | |
| 89 | const match = mem.indexOfDiff(u8, edge.label, label) orelse return edge.to; | |
| 90 | if (match == 0) continue; | |
| 91 | if (match == edge.label.len) return edge.to.put(allocator, label[match..]); | |
| 92 | ||
| 93 | // Found a match, need to splice up nodes. | |
| 94 | // From: A -> B | |
| 95 | // To: A -> C -> B | |
| 96 | const mid = try allocator.create(Node); | |
| 97 | mid.* = .{ .base = self.base }; | |
| 98 | const to_label = try allocator.dupe(u8, edge.label[match..]); | |
| 99 | allocator.free(edge.label); | |
| 100 | const to_node = edge.to; | |
| 101 | edge.to = mid; | |
| 102 | edge.label = try allocator.dupe(u8, label[0..match]); | |
| 103 | self.base.node_count += 1; | |
| 104 | ||
| 105 | try mid.edges.append(allocator, .{ | |
| 106 | .from = mid, | |
| 107 | .to = to_node, | |
| 108 | .label = to_label, | |
| 109 | }); | |
| 110 | ||
| 111 | return if (match == label.len) mid else mid.put(allocator, label[match..]); | |
| 112 | } | |
| 113 | ||
| 114 | // Add a new node. | |
| 115 | const node = try allocator.create(Node); | |
| 116 | node.* = .{ .base = self.base }; | |
| 117 | self.base.node_count += 1; | |
| 118 | 31 | |
| 119 | try self.edges.append(allocator, .{ | |
| 120 | .from = self, | |
| 121 | .to = node, | |
| 122 | .label = try allocator.dupe(u8, label), | |
| 123 | }); | |
| 124 | ||
| 125 | return node; | |
| 126 | } | |
| 127 | ||
| 128 | /// Recursively parses the node from the input byte stream. | |
| 129 | fn read(self: *Node, allocator: Allocator, reader: anytype) Trie.ReadError!usize { | |
| 130 | self.node_dirty = true; | |
| 131 | const trie_offset = try reader.context.getPos(); | |
| 132 | self.trie_offset = trie_offset; | |
| 133 | ||
| 134 | var nread: usize = 0; | |
| 135 | ||
| 136 | const node_size = try leb.readUleb128(u64, reader); | |
| 137 | if (node_size > 0) { | |
| 138 | const export_flags = try leb.readUleb128(u64, reader); | |
| 139 | // TODO Parse special flags. | |
| 140 | assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and | |
| 141 | export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0); | |
| 142 | ||
| 143 | const vmaddr_offset = try leb.readUleb128(u64, reader); | |
| 144 | ||
| 145 | self.terminal_info = .{ | |
| 146 | .export_flags = export_flags, | |
| 147 | .vmaddr_offset = vmaddr_offset, | |
| 148 | }; | |
| 149 | } | |
| 150 | ||
| 151 | const nedges = try reader.readByte(); | |
| 152 | self.base.node_count += nedges; | |
| 153 | ||
| 154 | nread += (try reader.context.getPos()) - trie_offset; | |
| 155 | ||
| 156 | var i: usize = 0; | |
| 157 | while (i < nedges) : (i += 1) { | |
| 158 | const edge_start_pos = try reader.context.getPos(); | |
| 159 | ||
| 160 | const label = blk: { | |
| 161 | var label_buf = std.ArrayList(u8).init(allocator); | |
| 162 | while (true) { | |
| 163 | const next = try reader.readByte(); | |
| 164 | if (next == @as(u8, 0)) | |
| 165 | break; | |
| 166 | try label_buf.append(next); | |
| 167 | } | |
| 168 | break :blk try label_buf.toOwnedSlice(); | |
| 169 | }; | |
| 170 | ||
| 171 | const seek_to = try leb.readUleb128(u64, reader); | |
| 172 | const return_pos = try reader.context.getPos(); | |
| 173 | ||
| 174 | nread += return_pos - edge_start_pos; | |
| 175 | try reader.context.seekTo(seek_to); | |
| 176 | ||
| 177 | const node = try allocator.create(Node); | |
| 178 | node.* = .{ .base = self.base }; | |
| 179 | ||
| 180 | nread += try node.read(allocator, reader); | |
| 181 | try self.edges.append(allocator, .{ | |
| 182 | .from = self, | |
| 183 | .to = node, | |
| 184 | .label = label, | |
| 185 | }); | |
| 186 | try reader.context.seekTo(return_pos); | |
| 187 | } | |
| 32 | /// The root node of the trie. | |
| 33 | root: ?Node.Index = null, | |
| 34 | buffer: std.ArrayListUnmanaged(u8) = .{}, | |
| 35 | nodes: std.MultiArrayList(Node) = .{}, | |
| 36 | edges: std.ArrayListUnmanaged(Edge) = .{}, | |
| 188 | 37 | |
| 189 | return nread; | |
| 190 | } | |
| 38 | /// Insert a symbol into the trie, updating the prefixes in the process. | |
| 39 | /// This operation may change the layout of the trie by splicing edges in | |
| 40 | /// certain circumstances. | |
| 41 | fn put(self: *Trie, allocator: Allocator, symbol: ExportSymbol) !void { | |
| 42 | // const tracy = trace(@src()); | |
| 43 | // defer tracy.end(); | |
| 44 | ||
| 45 | const node_index = try self.putNode(self.root.?, allocator, symbol.name); | |
| 46 | const slice = self.nodes.slice(); | |
| 47 | slice.items(.is_terminal)[node_index] = true; | |
| 48 | slice.items(.vmaddr_offset)[node_index] = symbol.vmaddr_offset; | |
| 49 | slice.items(.export_flags)[node_index] = symbol.export_flags; | |
| 50 | } | |
| 191 | 51 | |
| 192 | /// Writes this node to a byte stream. | |
| 193 | /// The children of this node *are* not written to the byte stream | |
| 194 | /// recursively. To write all nodes to a byte stream in sequence, | |
| 195 | /// iterate over `Trie.ordered_nodes` and call this method on each node. | |
| 196 | /// This is one of the requirements of the MachO. | |
| 197 | /// Panics if `finalize` was not called before calling this method. | |
| 198 | fn write(self: Node, writer: anytype) !void { | |
| 199 | assert(!self.node_dirty); | |
| 200 | if (self.terminal_info) |info| { | |
| 201 | // Terminal node info: encode export flags and vmaddr offset of this symbol. | |
| 202 | var info_buf: [@sizeOf(u64) * 2]u8 = undefined; | |
| 203 | var info_stream = std.io.fixedBufferStream(&info_buf); | |
| 204 | // TODO Implement for special flags. | |
| 205 | assert(info.export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and | |
| 206 | info.export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0); | |
| 207 | try leb.writeUleb128(info_stream.writer(), info.export_flags); | |
| 208 | try leb.writeUleb128(info_stream.writer(), info.vmaddr_offset); | |
| 209 | ||
| 210 | // Encode the size of the terminal node info. | |
| 211 | var size_buf: [@sizeOf(u64)]u8 = undefined; | |
| 212 | var size_stream = std.io.fixedBufferStream(&size_buf); | |
| 213 | try leb.writeUleb128(size_stream.writer(), info_stream.pos); | |
| 214 | ||
| 215 | // Now, write them to the output stream. | |
| 216 | try writer.writeAll(size_buf[0..size_stream.pos]); | |
| 217 | try writer.writeAll(info_buf[0..info_stream.pos]); | |
| 218 | } else { | |
| 219 | // Non-terminal node is delimited by 0 byte. | |
| 220 | try writer.writeByte(0); | |
| 221 | } | |
| 222 | // Write number of edges (max legal number of edges is 256). | |
| 223 | try writer.writeByte(@as(u8, @intCast(self.edges.items.len))); | |
| 224 | ||
| 225 | for (self.edges.items) |edge| { | |
| 226 | // Write edge label and offset to next node in trie. | |
| 227 | try writer.writeAll(edge.label); | |
| 228 | try writer.writeByte(0); | |
| 229 | try leb.writeUleb128(writer, edge.to.trie_offset.?); | |
| 230 | } | |
| 52 | /// Inserts a new node starting at `node_index`. | |
| 53 | fn putNode(self: *Trie, node_index: Node.Index, allocator: Allocator, label: []const u8) !Node.Index { | |
| 54 | // Check for match with edges from this node. | |
| 55 | for (self.nodes.items(.edges)[node_index].items) |edge_index| { | |
| 56 | const edge = &self.edges.items[edge_index]; | |
| 57 | const match = mem.indexOfDiff(u8, edge.label, label) orelse return edge.node; | |
| 58 | if (match == 0) continue; | |
| 59 | if (match == edge.label.len) return self.putNode(edge.node, allocator, label[match..]); | |
| 60 | ||
| 61 | // Found a match, need to splice up nodes. | |
| 62 | // From: A -> B | |
| 63 | // To: A -> C -> B | |
| 64 | const mid_index = try self.addNode(allocator); | |
| 65 | const to_label = edge.label[match..]; | |
| 66 | const to_node = edge.node; | |
| 67 | edge.node = mid_index; | |
| 68 | edge.label = label[0..match]; | |
| 69 | ||
| 70 | const new_edge_index = try self.addEdge(allocator); | |
| 71 | const new_edge = &self.edges.items[new_edge_index]; | |
| 72 | new_edge.node = to_node; | |
| 73 | new_edge.label = to_label; | |
| 74 | try self.nodes.items(.edges)[mid_index].append(allocator, new_edge_index); | |
| 75 | ||
| 76 | return if (match == label.len) mid_index else self.putNode(mid_index, allocator, label[match..]); | |
| 231 | 77 | } |
| 232 | 78 | |
| 233 | const FinalizeResult = struct { | |
| 234 | /// Current size of this node in bytes. | |
| 235 | node_size: u64, | |
| 236 | ||
| 237 | /// True if the trie offset of this node in the output byte stream | |
| 238 | /// would need updating; false otherwise. | |
| 239 | updated: bool, | |
| 240 | }; | |
| 79 | // Add a new node. | |
| 80 | const new_node_index = try self.addNode(allocator); | |
| 81 | const new_edge_index = try self.addEdge(allocator); | |
| 82 | const new_edge = &self.edges.items[new_edge_index]; | |
| 83 | new_edge.node = new_node_index; | |
| 84 | new_edge.label = label; | |
| 85 | try self.nodes.items(.edges)[node_index].append(allocator, new_edge_index); | |
| 241 | 86 | |
| 242 | /// Updates offset of this node in the output byte stream. | |
| 243 | fn finalize(self: *Node, offset_in_trie: u64) !FinalizeResult { | |
| 244 | var stream = std.io.countingWriter(std.io.null_writer); | |
| 245 | const writer = stream.writer(); | |
| 246 | ||
| 247 | var node_size: u64 = 0; | |
| 248 | if (self.terminal_info) |info| { | |
| 249 | try leb.writeUleb128(writer, info.export_flags); | |
| 250 | try leb.writeUleb128(writer, info.vmaddr_offset); | |
| 251 | try leb.writeUleb128(writer, stream.bytes_written); | |
| 252 | } else { | |
| 253 | node_size += 1; // 0x0 for non-terminal nodes | |
| 254 | } | |
| 255 | node_size += 1; // 1 byte for edge count | |
| 87 | return new_node_index; | |
| 88 | } | |
| 256 | 89 | |
| 257 | for (self.edges.items) |edge| { | |
| 258 | const next_node_offset = edge.to.trie_offset orelse 0; | |
| 259 | node_size += edge.label.len + 1; | |
| 260 | try leb.writeUleb128(writer, next_node_offset); | |
| 90 | pub fn updateSize(self: *Trie, macho_file: *MachO) !void { | |
| 91 | const tracy = trace(@src()); | |
| 92 | defer tracy.end(); | |
| 93 | ||
| 94 | const gpa = macho_file.base.comp.gpa; | |
| 95 | ||
| 96 | try self.init(gpa); | |
| 97 | try self.nodes.ensureUnusedCapacity(gpa, macho_file.resolver.values.items.len * 2); | |
| 98 | try self.edges.ensureUnusedCapacity(gpa, macho_file.resolver.values.items.len * 2); | |
| 99 | ||
| 100 | const seg = macho_file.getTextSegment(); | |
| 101 | for (macho_file.resolver.values.items) |ref| { | |
| 102 | if (ref.getFile(macho_file) == null) continue; | |
| 103 | const sym = ref.getSymbol(macho_file).?; | |
| 104 | if (!sym.flags.@"export") continue; | |
| 105 | if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; | |
| 106 | var flags: u64 = if (sym.flags.abs) | |
| 107 | macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE | |
| 108 | else if (sym.flags.tlv) | |
| 109 | macho.EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL | |
| 110 | else | |
| 111 | macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR; | |
| 112 | if (sym.flags.weak) { | |
| 113 | flags |= macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; | |
| 114 | macho_file.weak_defines = true; | |
| 115 | macho_file.binds_to_weak = true; | |
| 261 | 116 | } |
| 262 | ||
| 263 | const trie_offset = self.trie_offset orelse 0; | |
| 264 | const updated = offset_in_trie != trie_offset; | |
| 265 | self.trie_offset = offset_in_trie; | |
| 266 | self.node_dirty = false; | |
| 267 | node_size += stream.bytes_written; | |
| 268 | ||
| 269 | return FinalizeResult{ .node_size = node_size, .updated = updated }; | |
| 117 | try self.put(gpa, .{ | |
| 118 | .name = sym.getName(macho_file), | |
| 119 | .vmaddr_offset = sym.getAddress(.{ .stubs = false }, macho_file) - seg.vmaddr, | |
| 120 | .export_flags = flags, | |
| 121 | }); | |
| 270 | 122 | } |
| 271 | }; | |
| 272 | ||
| 273 | /// The root node of the trie. | |
| 274 | root: ?*Node = null, | |
| 275 | 123 | |
| 276 | /// If you want to access nodes ordered in DFS fashion, | |
| 277 | /// you should call `finalize` first since the nodes | |
| 278 | /// in this container are not guaranteed to not be stale | |
| 279 | /// if more insertions took place after the last `finalize` | |
| 280 | /// call. | |
| 281 | ordered_nodes: std.ArrayListUnmanaged(*Node) = .{}, | |
| 124 | try self.finalize(gpa); | |
| 282 | 125 | |
| 283 | /// The size of the trie in bytes. | |
| 284 | /// This value may be outdated if there were additional | |
| 285 | /// insertions performed after `finalize` was called. | |
| 286 | /// Call `finalize` before accessing this value to ensure | |
| 287 | /// it is up-to-date. | |
| 288 | size: u64 = 0, | |
| 289 | ||
| 290 | /// Number of nodes currently in the trie. | |
| 291 | node_count: usize = 0, | |
| 292 | ||
| 293 | trie_dirty: bool = true, | |
| 294 | ||
| 295 | /// Export symbol that is to be placed in the trie. | |
| 296 | pub const ExportSymbol = struct { | |
| 297 | /// Name of the symbol. | |
| 298 | name: []const u8, | |
| 299 | ||
| 300 | /// Offset of this symbol's virtual memory address from the beginning | |
| 301 | /// of the __TEXT segment. | |
| 302 | vmaddr_offset: u64, | |
| 303 | ||
| 304 | /// Export flags of this exported symbol. | |
| 305 | export_flags: u64, | |
| 306 | }; | |
| 307 | ||
| 308 | /// Insert a symbol into the trie, updating the prefixes in the process. | |
| 309 | /// This operation may change the layout of the trie by splicing edges in | |
| 310 | /// certain circumstances. | |
| 311 | pub fn put(self: *Trie, allocator: Allocator, symbol: ExportSymbol) !void { | |
| 312 | const node = try self.root.?.put(allocator, symbol.name); | |
| 313 | node.terminal_info = .{ | |
| 314 | .vmaddr_offset = symbol.vmaddr_offset, | |
| 315 | .export_flags = symbol.export_flags, | |
| 316 | }; | |
| 317 | self.trie_dirty = true; | |
| 126 | macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); | |
| 318 | 127 | } |
| 319 | 128 | |
| 320 | 129 | /// Finalizes this trie for writing to a byte stream. |
| 321 | 130 | /// This step performs multiple passes through the trie ensuring |
| 322 | 131 | /// there are no gaps after every `Node` is ULEB128 encoded. |
| 323 | 132 | /// Call this method before trying to `write` the trie to a byte stream. |
| 324 | pub fn finalize(self: *Trie, allocator: Allocator) !void { | |
| 325 | if (!self.trie_dirty) return; | |
| 133 | fn finalize(self: *Trie, allocator: Allocator) !void { | |
| 134 | const tracy = trace(@src()); | |
| 135 | defer tracy.end(); | |
| 326 | 136 | |
| 327 | self.ordered_nodes.shrinkRetainingCapacity(0); | |
| 328 | try self.ordered_nodes.ensureTotalCapacity(allocator, self.node_count); | |
| 137 | var ordered_nodes = std.ArrayList(Node.Index).init(allocator); | |
| 138 | defer ordered_nodes.deinit(); | |
| 139 | try ordered_nodes.ensureTotalCapacityPrecise(self.nodes.items(.is_terminal).len); | |
| 329 | 140 | |
| 330 | var fifo = std.fifo.LinearFifo(*Node, .Dynamic).init(allocator); | |
| 141 | var fifo = std.fifo.LinearFifo(Node.Index, .Dynamic).init(allocator); | |
| 331 | 142 | defer fifo.deinit(); |
| 332 | 143 | |
| 333 | 144 | try fifo.writeItem(self.root.?); |
| 334 | 145 | |
| 335 | while (fifo.readItem()) |next| { | |
| 336 | for (next.edges.items) |*edge| { | |
| 337 | try fifo.writeItem(edge.to); | |
| 146 | while (fifo.readItem()) |next_index| { | |
| 147 | const edges = &self.nodes.items(.edges)[next_index]; | |
| 148 | for (edges.items) |edge_index| { | |
| 149 | const edge = self.edges.items[edge_index]; | |
| 150 | try fifo.writeItem(edge.node); | |
| 338 | 151 | } |
| 339 | self.ordered_nodes.appendAssumeCapacity(next); | |
| 152 | ordered_nodes.appendAssumeCapacity(next_index); | |
| 340 | 153 | } |
| 341 | 154 | |
| 342 | 155 | var more: bool = true; |
| 156 | var size: u32 = 0; | |
| 343 | 157 | while (more) { |
| 344 | self.size = 0; | |
| 158 | size = 0; | |
| 345 | 159 | more = false; |
| 346 | for (self.ordered_nodes.items) |node| { | |
| 347 | const res = try node.finalize(self.size); | |
| 348 | self.size += res.node_size; | |
| 160 | for (ordered_nodes.items) |node_index| { | |
| 161 | const res = try self.finalizeNode(node_index, size); | |
| 162 | size += res.node_size; | |
| 349 | 163 | if (res.updated) more = true; |
| 350 | 164 | } |
| 351 | 165 | } |
| 352 | 166 | |
| 353 | self.trie_dirty = false; | |
| 167 | try self.buffer.ensureTotalCapacityPrecise(allocator, size); | |
| 168 | for (ordered_nodes.items) |node_index| { | |
| 169 | try self.writeNode(node_index, self.buffer.writer(allocator)); | |
| 170 | } | |
| 354 | 171 | } |
| 355 | 172 | |
| 356 | const ReadError = error{ | |
| 357 | OutOfMemory, | |
| 358 | EndOfStream, | |
| 359 | Overflow, | |
| 173 | const FinalizeNodeResult = struct { | |
| 174 | /// Current size of this node in bytes. | |
| 175 | node_size: u32, | |
| 176 | ||
| 177 | /// True if the trie offset of this node in the output byte stream | |
| 178 | /// would need updating; false otherwise. | |
| 179 | updated: bool, | |
| 360 | 180 | }; |
| 361 | 181 | |
| 362 | /// Parse the trie from a byte stream. | |
| 363 | pub fn read(self: *Trie, allocator: Allocator, reader: anytype) ReadError!usize { | |
| 364 | return self.root.?.read(allocator, reader); | |
| 365 | } | |
| 182 | /// Updates offset of this node in the output byte stream. | |
| 183 | fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult { | |
| 184 | var stream = std.io.countingWriter(std.io.null_writer); | |
| 185 | const writer = stream.writer(); | |
| 186 | const slice = self.nodes.slice(); | |
| 187 | ||
| 188 | var node_size: u32 = 0; | |
| 189 | if (slice.items(.is_terminal)[node_index]) { | |
| 190 | const export_flags = slice.items(.export_flags)[node_index]; | |
| 191 | const vmaddr_offset = slice.items(.vmaddr_offset)[node_index]; | |
| 192 | try leb.writeULEB128(writer, export_flags); | |
| 193 | try leb.writeULEB128(writer, vmaddr_offset); | |
| 194 | try leb.writeULEB128(writer, stream.bytes_written); | |
| 195 | } else { | |
| 196 | node_size += 1; // 0x0 for non-terminal nodes | |
| 197 | } | |
| 198 | node_size += 1; // 1 byte for edge count | |
| 366 | 199 | |
| 367 | /// Write the trie to a byte stream. | |
| 368 | /// Panics if the trie was not finalized using `finalize` before calling this method. | |
| 369 | pub fn write(self: Trie, writer: anytype) !void { | |
| 370 | assert(!self.trie_dirty); | |
| 371 | for (self.ordered_nodes.items) |node| { | |
| 372 | try node.write(writer); | |
| 200 | for (slice.items(.edges)[node_index].items) |edge_index| { | |
| 201 | const edge = &self.edges.items[edge_index]; | |
| 202 | const next_node_offset = slice.items(.trie_offset)[edge.node]; | |
| 203 | node_size += @intCast(edge.label.len + 1); | |
| 204 | try leb.writeULEB128(writer, next_node_offset); | |
| 373 | 205 | } |
| 206 | ||
| 207 | const trie_offset = slice.items(.trie_offset)[node_index]; | |
| 208 | const updated = offset_in_trie != trie_offset; | |
| 209 | slice.items(.trie_offset)[node_index] = offset_in_trie; | |
| 210 | node_size += @intCast(stream.bytes_written); | |
| 211 | ||
| 212 | return .{ .node_size = node_size, .updated = updated }; | |
| 374 | 213 | } |
| 375 | 214 | |
| 376 | pub fn init(self: *Trie, allocator: Allocator) !void { | |
| 215 | fn init(self: *Trie, allocator: Allocator) !void { | |
| 377 | 216 | assert(self.root == null); |
| 378 | const root = try allocator.create(Node); | |
| 379 | root.* = .{ .base = self }; | |
| 380 | self.root = root; | |
| 381 | self.node_count += 1; | |
| 217 | self.root = try self.addNode(allocator); | |
| 382 | 218 | } |
| 383 | 219 | |
| 384 | 220 | pub fn deinit(self: *Trie, allocator: Allocator) void { |
| 385 | if (self.root) |root| { | |
| 386 | root.deinit(allocator); | |
| 387 | allocator.destroy(root); | |
| 221 | for (self.nodes.items(.edges)) |*edges| { | |
| 222 | edges.deinit(allocator); | |
| 388 | 223 | } |
| 389 | self.ordered_nodes.deinit(allocator); | |
| 224 | self.nodes.deinit(allocator); | |
| 225 | self.edges.deinit(allocator); | |
| 226 | self.buffer.deinit(allocator); | |
| 390 | 227 | } |
| 391 | 228 | |
| 392 | test "Trie node count" { | |
| 393 | const gpa = testing.allocator; | |
| 394 | var trie: Trie = .{}; | |
| 395 | defer trie.deinit(gpa); | |
| 396 | try trie.init(gpa); | |
| 229 | pub fn write(self: Trie, writer: anytype) !void { | |
| 230 | if (self.buffer.items.len == 0) return; | |
| 231 | try writer.writeAll(self.buffer.items); | |
| 232 | } | |
| 397 | 233 | |
| 398 | try testing.expectEqual(@as(usize, 1), trie.node_count); | |
| 399 | try testing.expect(trie.root != null); | |
| 234 | /// Writes this node to a byte stream. | |
| 235 | /// The children of this node *are* not written to the byte stream | |
| 236 | /// recursively. To write all nodes to a byte stream in sequence, | |
| 237 | /// iterate over `Trie.ordered_nodes` and call this method on each node. | |
| 238 | /// This is one of the requirements of the MachO. | |
| 239 | /// Panics if `finalize` was not called before calling this method. | |
| 240 | fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void { | |
| 241 | const slice = self.nodes.slice(); | |
| 242 | const edges = slice.items(.edges)[node_index]; | |
| 243 | const is_terminal = slice.items(.is_terminal)[node_index]; | |
| 244 | const export_flags = slice.items(.export_flags)[node_index]; | |
| 245 | const vmaddr_offset = slice.items(.vmaddr_offset)[node_index]; | |
| 246 | ||
| 247 | if (is_terminal) { | |
| 248 | // Terminal node info: encode export flags and vmaddr offset of this symbol. | |
| 249 | var info_buf: [@sizeOf(u64) * 2]u8 = undefined; | |
| 250 | var info_stream = std.io.fixedBufferStream(&info_buf); | |
| 251 | // TODO Implement for special flags. | |
| 252 | assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and | |
| 253 | export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0); | |
| 254 | try leb.writeULEB128(info_stream.writer(), export_flags); | |
| 255 | try leb.writeULEB128(info_stream.writer(), vmaddr_offset); | |
| 256 | ||
| 257 | // Encode the size of the terminal node info. | |
| 258 | var size_buf: [@sizeOf(u64)]u8 = undefined; | |
| 259 | var size_stream = std.io.fixedBufferStream(&size_buf); | |
| 260 | try leb.writeULEB128(size_stream.writer(), info_stream.pos); | |
| 261 | ||
| 262 | // Now, write them to the output stream. | |
| 263 | try writer.writeAll(size_buf[0..size_stream.pos]); | |
| 264 | try writer.writeAll(info_buf[0..info_stream.pos]); | |
| 265 | } else { | |
| 266 | // Non-terminal node is delimited by 0 byte. | |
| 267 | try writer.writeByte(0); | |
| 268 | } | |
| 269 | // Write number of edges (max legal number of edges is 256). | |
| 270 | try writer.writeByte(@as(u8, @intCast(edges.items.len))); | |
| 271 | ||
| 272 | for (edges.items) |edge_index| { | |
| 273 | const edge = self.edges.items[edge_index]; | |
| 274 | // Write edge label and offset to next node in trie. | |
| 275 | try writer.writeAll(edge.label); | |
| 276 | try writer.writeByte(0); | |
| 277 | try leb.writeULEB128(writer, slice.items(.trie_offset)[edge.node]); | |
| 278 | } | |
| 279 | } | |
| 400 | 280 | |
| 401 | try trie.put(gpa, .{ | |
| 402 | .name = "_main", | |
| 403 | .vmaddr_offset = 0, | |
| 404 | .export_flags = 0, | |
| 405 | }); | |
| 406 | try testing.expectEqual(@as(usize, 2), trie.node_count); | |
| 281 | fn addNode(self: *Trie, allocator: Allocator) !Node.Index { | |
| 282 | const index: Node.Index = @intCast(try self.nodes.addOne(allocator)); | |
| 283 | self.nodes.set(index, .{}); | |
| 284 | return index; | |
| 285 | } | |
| 407 | 286 | |
| 408 | // Inserting the same node shouldn't update the trie. | |
| 409 | try trie.put(gpa, .{ | |
| 410 | .name = "_main", | |
| 411 | .vmaddr_offset = 0, | |
| 412 | .export_flags = 0, | |
| 413 | }); | |
| 414 | try testing.expectEqual(@as(usize, 2), trie.node_count); | |
| 287 | fn addEdge(self: *Trie, allocator: Allocator) !Edge.Index { | |
| 288 | const index: Edge.Index = @intCast(self.edges.items.len); | |
| 289 | const edge = try self.edges.addOne(allocator); | |
| 290 | edge.* = .{}; | |
| 291 | return index; | |
| 292 | } | |
| 415 | 293 | |
| 416 | try trie.put(gpa, .{ | |
| 417 | .name = "__mh_execute_header", | |
| 418 | .vmaddr_offset = 0x1000, | |
| 419 | .export_flags = 0, | |
| 420 | }); | |
| 421 | try testing.expectEqual(@as(usize, 4), trie.node_count); | |
| 294 | /// Export symbol that is to be placed in the trie. | |
| 295 | pub const ExportSymbol = struct { | |
| 296 | /// Name of the symbol. | |
| 297 | name: []const u8, | |
| 422 | 298 | |
| 423 | // Inserting the same node shouldn't update the trie. | |
| 424 | try trie.put(gpa, .{ | |
| 425 | .name = "__mh_execute_header", | |
| 426 | .vmaddr_offset = 0x1000, | |
| 427 | .export_flags = 0, | |
| 428 | }); | |
| 429 | try testing.expectEqual(@as(usize, 4), trie.node_count); | |
| 430 | try trie.put(gpa, .{ | |
| 431 | .name = "_main", | |
| 432 | .vmaddr_offset = 0, | |
| 433 | .export_flags = 0, | |
| 434 | }); | |
| 435 | try testing.expectEqual(@as(usize, 4), trie.node_count); | |
| 436 | } | |
| 299 | /// Offset of this symbol's virtual memory address from the beginning | |
| 300 | /// of the __TEXT segment. | |
| 301 | vmaddr_offset: u64, | |
| 437 | 302 | |
| 438 | test "Trie basic" { | |
| 439 | const gpa = testing.allocator; | |
| 440 | var trie: Trie = .{}; | |
| 441 | defer trie.deinit(gpa); | |
| 442 | try trie.init(gpa); | |
| 303 | /// Export flags of this exported symbol. | |
| 304 | export_flags: u64, | |
| 305 | }; | |
| 443 | 306 | |
| 444 | // root --- _st ---> node | |
| 445 | try trie.put(gpa, .{ | |
| 446 | .name = "_st", | |
| 447 | .vmaddr_offset = 0, | |
| 448 | .export_flags = 0, | |
| 449 | }); | |
| 450 | try testing.expect(trie.root.?.edges.items.len == 1); | |
| 451 | try testing.expect(mem.eql(u8, trie.root.?.edges.items[0].label, "_st")); | |
| 452 | ||
| 453 | { | |
| 454 | // root --- _st ---> node --- art ---> node | |
| 455 | try trie.put(gpa, .{ | |
| 456 | .name = "_start", | |
| 457 | .vmaddr_offset = 0, | |
| 458 | .export_flags = 0, | |
| 459 | }); | |
| 460 | try testing.expect(trie.root.?.edges.items.len == 1); | |
| 307 | const Node = struct { | |
| 308 | is_terminal: bool = false, | |
| 461 | 309 | |
| 462 | const nextEdge = &trie.root.?.edges.items[0]; | |
| 463 | try testing.expect(mem.eql(u8, nextEdge.label, "_st")); | |
| 464 | try testing.expect(nextEdge.to.edges.items.len == 1); | |
| 465 | try testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "art")); | |
| 466 | } | |
| 467 | { | |
| 468 | // root --- _ ---> node --- st ---> node --- art ---> node | |
| 469 | // | | |
| 470 | // | --- main ---> node | |
| 471 | try trie.put(gpa, .{ | |
| 472 | .name = "_main", | |
| 473 | .vmaddr_offset = 0, | |
| 474 | .export_flags = 0, | |
| 475 | }); | |
| 476 | try testing.expect(trie.root.?.edges.items.len == 1); | |
| 310 | /// Export flags associated with this exported symbol. | |
| 311 | export_flags: u64 = 0, | |
| 477 | 312 | |
| 478 | const nextEdge = &trie.root.?.edges.items[0]; | |
| 479 | try testing.expect(mem.eql(u8, nextEdge.label, "_")); | |
| 480 | try testing.expect(nextEdge.to.edges.items.len == 2); | |
| 481 | try testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "st")); | |
| 482 | try testing.expect(mem.eql(u8, nextEdge.to.edges.items[1].label, "main")); | |
| 313 | /// VM address offset wrt to the section this symbol is defined against. | |
| 314 | vmaddr_offset: u64 = 0, | |
| 483 | 315 | |
| 484 | const nextNextEdge = &nextEdge.to.edges.items[0]; | |
| 485 | try testing.expect(mem.eql(u8, nextNextEdge.to.edges.items[0].label, "art")); | |
| 486 | } | |
| 487 | } | |
| 316 | /// Offset of this node in the trie output byte stream. | |
| 317 | trie_offset: u32 = 0, | |
| 318 | ||
| 319 | /// List of all edges originating from this node. | |
| 320 | edges: std.ArrayListUnmanaged(Edge.Index) = .{}, | |
| 321 | ||
| 322 | const Index = u32; | |
| 323 | }; | |
| 324 | ||
| 325 | /// Edge connecting nodes in the trie. | |
| 326 | const Edge = struct { | |
| 327 | /// Target node in the trie. | |
| 328 | node: Node.Index = 0, | |
| 329 | ||
| 330 | /// Matching prefix. | |
| 331 | label: []const u8 = "", | |
| 332 | ||
| 333 | const Index = u32; | |
| 334 | }; | |
| 488 | 335 | |
| 489 | 336 | fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void { |
| 490 | 337 | assert(expected.len > 0); |
| ... | ... | @@ -502,7 +349,7 @@ fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void { |
| 502 | 349 | } |
| 503 | 350 | |
| 504 | 351 | test "write Trie to a byte stream" { |
| 505 | var gpa = testing.allocator; | |
| 352 | const gpa = testing.allocator; | |
| 506 | 353 | var trie: Trie = .{}; |
| 507 | 354 | defer trie.deinit(gpa); |
| 508 | 355 | try trie.init(gpa); |
| ... | ... | @@ -519,7 +366,6 @@ test "write Trie to a byte stream" { |
| 519 | 366 | }); |
| 520 | 367 | |
| 521 | 368 | try trie.finalize(gpa); |
| 522 | try trie.finalize(gpa); // Finalizing mulitple times is a nop subsequently unless we add new nodes. | |
| 523 | 369 | |
| 524 | 370 | const exp_buffer = [_]u8{ |
| 525 | 371 | 0x0, 0x1, // node root |
| ... | ... | @@ -531,51 +377,7 @@ test "write Trie to a byte stream" { |
| 531 | 377 | 0x2, 0x0, 0x0, 0x0, // terminal node |
| 532 | 378 | 0x3, 0x0, 0x80, 0x20, 0x0, // terminal node |
| 533 | 379 | }; |
| 534 | ||
| 535 | const buffer = try gpa.alloc(u8, trie.size); | |
| 536 | defer gpa.free(buffer); | |
| 537 | var stream = std.io.fixedBufferStream(buffer); | |
| 538 | { | |
| 539 | _ = try trie.write(stream.writer()); | |
| 540 | try expectEqualHexStrings(&exp_buffer, buffer); | |
| 541 | } | |
| 542 | { | |
| 543 | // Writing finalized trie again should yield the same result. | |
| 544 | try stream.seekTo(0); | |
| 545 | _ = try trie.write(stream.writer()); | |
| 546 | try expectEqualHexStrings(&exp_buffer, buffer); | |
| 547 | } | |
| 548 | } | |
| 549 | ||
| 550 | test "parse Trie from byte stream" { | |
| 551 | const gpa = testing.allocator; | |
| 552 | ||
| 553 | const in_buffer = [_]u8{ | |
| 554 | 0x0, 0x1, // node root | |
| 555 | 0x5f, 0x0, 0x5, // edge '_' | |
| 556 | 0x0, 0x2, // non-terminal node | |
| 557 | 0x5f, 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, // edge '_mh_execute_header' | |
| 558 | 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x0, 0x21, // edge '_mh_execute_header' | |
| 559 | 0x6d, 0x61, 0x69, 0x6e, 0x0, 0x25, // edge 'main' | |
| 560 | 0x2, 0x0, 0x0, 0x0, // terminal node | |
| 561 | 0x3, 0x0, 0x80, 0x20, 0x0, // terminal node | |
| 562 | }; | |
| 563 | ||
| 564 | var in_stream = std.io.fixedBufferStream(&in_buffer); | |
| 565 | var trie: Trie = .{}; | |
| 566 | defer trie.deinit(gpa); | |
| 567 | try trie.init(gpa); | |
| 568 | const nread = try trie.read(gpa, in_stream.reader()); | |
| 569 | ||
| 570 | try testing.expect(nread == in_buffer.len); | |
| 571 | ||
| 572 | try trie.finalize(gpa); | |
| 573 | ||
| 574 | const out_buffer = try gpa.alloc(u8, trie.size); | |
| 575 | defer gpa.free(out_buffer); | |
| 576 | var out_stream = std.io.fixedBufferStream(out_buffer); | |
| 577 | _ = try trie.write(out_stream.writer()); | |
| 578 | try expectEqualHexStrings(&in_buffer, out_buffer); | |
| 380 | try expectEqualHexStrings(&exp_buffer, trie.buffer.items); | |
| 579 | 381 | } |
| 580 | 382 | |
| 581 | 383 | test "ordering bug" { |
| ... | ... | @@ -602,11 +404,18 @@ test "ordering bug" { |
| 602 | 404 | 0x88, 0x80, 0x02, 0x01, 0x73, 0x53, 0x74, 0x72, |
| 603 | 405 | 0x00, 0x12, 0x03, 0x00, 0xD8, 0x0A, 0x00, |
| 604 | 406 | }; |
| 605 | ||
| 606 | const buffer = try gpa.alloc(u8, trie.size); | |
| 607 | defer gpa.free(buffer); | |
| 608 | var stream = std.io.fixedBufferStream(buffer); | |
| 609 | // Writing finalized trie again should yield the same result. | |
| 610 | _ = try trie.write(stream.writer()); | |
| 611 | try expectEqualHexStrings(&exp_buffer, buffer); | |
| 407 | try expectEqualHexStrings(&exp_buffer, trie.buffer.items); | |
| 612 | 408 | } |
| 409 | ||
| 410 | const assert = std.debug.assert; | |
| 411 | const leb = std.leb; | |
| 412 | const log = std.log.scoped(.macho); | |
| 413 | const macho = std.macho; | |
| 414 | const mem = std.mem; | |
| 415 | const std = @import("std"); | |
| 416 | const testing = std.testing; | |
| 417 | const trace = @import("../../../tracy.zig").trace; | |
| 418 | ||
| 419 | const Allocator = mem.Allocator; | |
| 420 | const MachO = @import("../../MachO.zig"); | |
| 421 | const Trie = @This(); |
src/link/MachO/dyld_info/bind.zig+259-34| ... | ... | @@ -1,28 +1,19 @@ |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | const leb = std.leb; | |
| 4 | const log = std.log.scoped(.link_dyld_info); | |
| 5 | const macho = std.macho; | |
| 6 | const testing = std.testing; | |
| 7 | ||
| 8 | const Allocator = std.mem.Allocator; | |
| 9 | const MachO = @import("../../MachO.zig"); | |
| 10 | const Symbol = @import("../Symbol.zig"); | |
| 11 | ||
| 12 | 1 | pub const Entry = struct { |
| 13 | target: Symbol.Index, | |
| 2 | target: MachO.Ref, | |
| 14 | 3 | offset: u64, |
| 15 | 4 | segment_id: u8, |
| 16 | 5 | addend: i64, |
| 17 | 6 | |
| 18 | 7 | pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool { |
| 8 | _ = ctx; | |
| 19 | 9 | if (entry.segment_id == other.segment_id) { |
| 20 | if (entry.target == other.target) { | |
| 10 | if (entry.target.eql(other.target)) { | |
| 21 | 11 | return entry.offset < other.offset; |
| 22 | 12 | } |
| 23 | const entry_name = ctx.getSymbol(entry.target).getName(ctx); | |
| 24 | const other_name = ctx.getSymbol(other.target).getName(ctx); | |
| 25 | return std.mem.lessThan(u8, entry_name, other_name); | |
| 13 | if (entry.target.file == other.target.file) { | |
| 14 | return entry.target.index < other.target.index; | |
| 15 | } | |
| 16 | return entry.target.file < other.target.file; | |
| 26 | 17 | } |
| 27 | 18 | return entry.segment_id < other.segment_id; |
| 28 | 19 | } |
| ... | ... | @@ -39,11 +30,109 @@ pub const Bind = struct { |
| 39 | 30 | self.buffer.deinit(gpa); |
| 40 | 31 | } |
| 41 | 32 | |
| 42 | pub fn size(self: Self) u64 { | |
| 43 | return @intCast(self.buffer.items.len); | |
| 33 | pub fn updateSize(self: *Self, macho_file: *MachO) !void { | |
| 34 | const tracy = trace(@src()); | |
| 35 | defer tracy.end(); | |
| 36 | ||
| 37 | const gpa = macho_file.base.comp.gpa; | |
| 38 | const cpu_arch = macho_file.getTarget().cpu.arch; | |
| 39 | ||
| 40 | var objects = try std.ArrayList(File.Index).initCapacity(gpa, macho_file.objects.items.len + 2); | |
| 41 | defer objects.deinit(); | |
| 42 | objects.appendSliceAssumeCapacity(macho_file.objects.items); | |
| 43 | if (macho_file.getZigObject()) |obj| objects.appendAssumeCapacity(obj.index); | |
| 44 | if (macho_file.getInternalObject()) |obj| objects.appendAssumeCapacity(obj.index); | |
| 45 | ||
| 46 | for (objects.items) |index| { | |
| 47 | const file = macho_file.getFile(index).?; | |
| 48 | for (file.getAtoms()) |atom_index| { | |
| 49 | const atom = file.getAtom(atom_index) orelse continue; | |
| 50 | if (!atom.flags.alive) continue; | |
| 51 | if (atom.getInputSection(macho_file).isZerofill()) continue; | |
| 52 | const atom_addr = atom.getAddress(macho_file); | |
| 53 | const relocs = atom.getRelocs(macho_file); | |
| 54 | const seg_id = macho_file.sections.items(.segment_id)[atom.out_n_sect]; | |
| 55 | const seg = macho_file.segments.items[seg_id]; | |
| 56 | for (relocs) |rel| { | |
| 57 | if (rel.type != .unsigned or rel.meta.length != 3 or rel.tag != .@"extern") continue; | |
| 58 | const rel_offset = rel.offset - atom.off; | |
| 59 | const addend = rel.addend + rel.getRelocAddend(cpu_arch); | |
| 60 | const sym = rel.getTargetSymbol(atom.*, macho_file); | |
| 61 | if (sym.isTlvInit(macho_file)) continue; | |
| 62 | const entry = Entry{ | |
| 63 | .target = rel.getTargetSymbolRef(atom.*, macho_file), | |
| 64 | .offset = atom_addr + rel_offset - seg.vmaddr, | |
| 65 | .segment_id = seg_id, | |
| 66 | .addend = addend, | |
| 67 | }; | |
| 68 | if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) { | |
| 69 | try self.entries.append(gpa, entry); | |
| 70 | } | |
| 71 | } | |
| 72 | } | |
| 73 | } | |
| 74 | ||
| 75 | if (macho_file.got_sect_index) |sid| { | |
| 76 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 77 | const seg = macho_file.segments.items[seg_id]; | |
| 78 | for (macho_file.got.symbols.items, 0..) |ref, idx| { | |
| 79 | const sym = ref.getSymbol(macho_file).?; | |
| 80 | const addr = macho_file.got.getAddress(@intCast(idx), macho_file); | |
| 81 | const entry = Entry{ | |
| 82 | .target = ref, | |
| 83 | .offset = addr - seg.vmaddr, | |
| 84 | .segment_id = seg_id, | |
| 85 | .addend = 0, | |
| 86 | }; | |
| 87 | if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) { | |
| 88 | try self.entries.append(gpa, entry); | |
| 89 | } | |
| 90 | } | |
| 91 | } | |
| 92 | ||
| 93 | if (macho_file.la_symbol_ptr_sect_index) |sid| { | |
| 94 | const sect = macho_file.sections.items(.header)[sid]; | |
| 95 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 96 | const seg = macho_file.segments.items[seg_id]; | |
| 97 | for (macho_file.stubs.symbols.items, 0..) |ref, idx| { | |
| 98 | const sym = ref.getSymbol(macho_file).?; | |
| 99 | const addr = sect.addr + idx * @sizeOf(u64); | |
| 100 | const bind_entry = Entry{ | |
| 101 | .target = ref, | |
| 102 | .offset = addr - seg.vmaddr, | |
| 103 | .segment_id = seg_id, | |
| 104 | .addend = 0, | |
| 105 | }; | |
| 106 | if (sym.flags.import and sym.flags.weak) { | |
| 107 | try self.entries.append(gpa, bind_entry); | |
| 108 | } | |
| 109 | } | |
| 110 | } | |
| 111 | ||
| 112 | if (macho_file.tlv_ptr_sect_index) |sid| { | |
| 113 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 114 | const seg = macho_file.segments.items[seg_id]; | |
| 115 | ||
| 116 | for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| { | |
| 117 | const sym = ref.getSymbol(macho_file).?; | |
| 118 | const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file); | |
| 119 | const entry = Entry{ | |
| 120 | .target = ref, | |
| 121 | .offset = addr - seg.vmaddr, | |
| 122 | .segment_id = seg_id, | |
| 123 | .addend = 0, | |
| 124 | }; | |
| 125 | if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) { | |
| 126 | try self.entries.append(gpa, entry); | |
| 127 | } | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | try self.finalize(gpa, macho_file); | |
| 132 | macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); | |
| 44 | 133 | } |
| 45 | 134 | |
| 46 | pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { | |
| 135 | fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { | |
| 47 | 136 | if (self.entries.items.len == 0) return; |
| 48 | 137 | |
| 49 | 138 | const writer = self.buffer.writer(gpa); |
| ... | ... | @@ -75,7 +164,7 @@ pub const Bind = struct { |
| 75 | 164 | var addend: i64 = 0; |
| 76 | 165 | var count: usize = 0; |
| 77 | 166 | var skip: u64 = 0; |
| 78 | var target: ?Symbol.Index = null; | |
| 167 | var target: ?MachO.Ref = null; | |
| 79 | 168 | |
| 80 | 169 | var state: enum { |
| 81 | 170 | start, |
| ... | ... | @@ -86,7 +175,7 @@ pub const Bind = struct { |
| 86 | 175 | var i: usize = 0; |
| 87 | 176 | while (i < entries.len) : (i += 1) { |
| 88 | 177 | const current = entries[i]; |
| 89 | if (target == null or target.? != current.target) { | |
| 178 | if (target == null or !target.?.eql(current.target)) { | |
| 90 | 179 | switch (state) { |
| 91 | 180 | .start => {}, |
| 92 | 181 | .bind_single => try doBind(writer), |
| ... | ... | @@ -95,7 +184,7 @@ pub const Bind = struct { |
| 95 | 184 | state = .start; |
| 96 | 185 | target = current.target; |
| 97 | 186 | |
| 98 | const sym = ctx.getSymbol(current.target); | |
| 187 | const sym = current.target.getSymbol(ctx).?; | |
| 99 | 188 | const name = sym.getName(ctx); |
| 100 | 189 | const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; |
| 101 | 190 | const ordinal: i16 = ord: { |
| ... | ... | @@ -178,7 +267,6 @@ pub const Bind = struct { |
| 178 | 267 | } |
| 179 | 268 | |
| 180 | 269 | pub fn write(self: Self, writer: anytype) !void { |
| 181 | if (self.size() == 0) return; | |
| 182 | 270 | try writer.writeAll(self.buffer.items); |
| 183 | 271 | } |
| 184 | 272 | }; |
| ... | ... | @@ -194,11 +282,110 @@ pub const WeakBind = struct { |
| 194 | 282 | self.buffer.deinit(gpa); |
| 195 | 283 | } |
| 196 | 284 | |
| 197 | pub fn size(self: Self) u64 { | |
| 198 | return @intCast(self.buffer.items.len); | |
| 285 | pub fn updateSize(self: *Self, macho_file: *MachO) !void { | |
| 286 | const tracy = trace(@src()); | |
| 287 | defer tracy.end(); | |
| 288 | ||
| 289 | const gpa = macho_file.base.comp.gpa; | |
| 290 | const cpu_arch = macho_file.getTarget().cpu.arch; | |
| 291 | ||
| 292 | var objects = try std.ArrayList(File.Index).initCapacity(gpa, macho_file.objects.items.len + 2); | |
| 293 | defer objects.deinit(); | |
| 294 | objects.appendSliceAssumeCapacity(macho_file.objects.items); | |
| 295 | if (macho_file.getZigObject()) |obj| objects.appendAssumeCapacity(obj.index); | |
| 296 | if (macho_file.getInternalObject()) |obj| objects.appendAssumeCapacity(obj.index); | |
| 297 | ||
| 298 | for (objects.items) |index| { | |
| 299 | const file = macho_file.getFile(index).?; | |
| 300 | for (file.getAtoms()) |atom_index| { | |
| 301 | const atom = file.getAtom(atom_index) orelse continue; | |
| 302 | if (!atom.flags.alive) continue; | |
| 303 | if (atom.getInputSection(macho_file).isZerofill()) continue; | |
| 304 | const atom_addr = atom.getAddress(macho_file); | |
| 305 | const relocs = atom.getRelocs(macho_file); | |
| 306 | const seg_id = macho_file.sections.items(.segment_id)[atom.out_n_sect]; | |
| 307 | const seg = macho_file.segments.items[seg_id]; | |
| 308 | for (relocs) |rel| { | |
| 309 | if (rel.type != .unsigned or rel.meta.length != 3 or rel.tag != .@"extern") continue; | |
| 310 | const rel_offset = rel.offset - atom.off; | |
| 311 | const addend = rel.addend + rel.getRelocAddend(cpu_arch); | |
| 312 | const sym = rel.getTargetSymbol(atom.*, macho_file); | |
| 313 | if (sym.isTlvInit(macho_file)) continue; | |
| 314 | const entry = Entry{ | |
| 315 | .target = rel.getTargetSymbolRef(atom.*, macho_file), | |
| 316 | .offset = atom_addr + rel_offset - seg.vmaddr, | |
| 317 | .segment_id = seg_id, | |
| 318 | .addend = addend, | |
| 319 | }; | |
| 320 | if (!sym.isLocal() and sym.flags.weak) { | |
| 321 | try self.entries.append(gpa, entry); | |
| 322 | } | |
| 323 | } | |
| 324 | } | |
| 325 | } | |
| 326 | ||
| 327 | if (macho_file.got_sect_index) |sid| { | |
| 328 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 329 | const seg = macho_file.segments.items[seg_id]; | |
| 330 | for (macho_file.got.symbols.items, 0..) |ref, idx| { | |
| 331 | const sym = ref.getSymbol(macho_file).?; | |
| 332 | const addr = macho_file.got.getAddress(@intCast(idx), macho_file); | |
| 333 | const entry = Entry{ | |
| 334 | .target = ref, | |
| 335 | .offset = addr - seg.vmaddr, | |
| 336 | .segment_id = seg_id, | |
| 337 | .addend = 0, | |
| 338 | }; | |
| 339 | if (sym.flags.weak) { | |
| 340 | try self.entries.append(gpa, entry); | |
| 341 | } | |
| 342 | } | |
| 343 | } | |
| 344 | ||
| 345 | if (macho_file.la_symbol_ptr_sect_index) |sid| { | |
| 346 | const sect = macho_file.sections.items(.header)[sid]; | |
| 347 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 348 | const seg = macho_file.segments.items[seg_id]; | |
| 349 | ||
| 350 | for (macho_file.stubs.symbols.items, 0..) |ref, idx| { | |
| 351 | const sym = ref.getSymbol(macho_file).?; | |
| 352 | const addr = sect.addr + idx * @sizeOf(u64); | |
| 353 | const bind_entry = Entry{ | |
| 354 | .target = ref, | |
| 355 | .offset = addr - seg.vmaddr, | |
| 356 | .segment_id = seg_id, | |
| 357 | .addend = 0, | |
| 358 | }; | |
| 359 | if (sym.flags.weak) { | |
| 360 | try self.entries.append(gpa, bind_entry); | |
| 361 | } | |
| 362 | } | |
| 363 | } | |
| 364 | ||
| 365 | if (macho_file.tlv_ptr_sect_index) |sid| { | |
| 366 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 367 | const seg = macho_file.segments.items[seg_id]; | |
| 368 | ||
| 369 | for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| { | |
| 370 | const sym = ref.getSymbol(macho_file).?; | |
| 371 | const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file); | |
| 372 | const entry = Entry{ | |
| 373 | .target = ref, | |
| 374 | .offset = addr - seg.vmaddr, | |
| 375 | .segment_id = seg_id, | |
| 376 | .addend = 0, | |
| 377 | }; | |
| 378 | if (sym.flags.weak) { | |
| 379 | try self.entries.append(gpa, entry); | |
| 380 | } | |
| 381 | } | |
| 382 | } | |
| 383 | ||
| 384 | try self.finalize(gpa, macho_file); | |
| 385 | macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); | |
| 199 | 386 | } |
| 200 | 387 | |
| 201 | pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { | |
| 388 | fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { | |
| 202 | 389 | if (self.entries.items.len == 0) return; |
| 203 | 390 | |
| 204 | 391 | const writer = self.buffer.writer(gpa); |
| ... | ... | @@ -230,7 +417,7 @@ pub const WeakBind = struct { |
| 230 | 417 | var addend: i64 = 0; |
| 231 | 418 | var count: usize = 0; |
| 232 | 419 | var skip: u64 = 0; |
| 233 | var target: ?Symbol.Index = null; | |
| 420 | var target: ?MachO.Ref = null; | |
| 234 | 421 | |
| 235 | 422 | var state: enum { |
| 236 | 423 | start, |
| ... | ... | @@ -241,7 +428,7 @@ pub const WeakBind = struct { |
| 241 | 428 | var i: usize = 0; |
| 242 | 429 | while (i < entries.len) : (i += 1) { |
| 243 | 430 | const current = entries[i]; |
| 244 | if (target == null or target.? != current.target) { | |
| 431 | if (target == null or !target.?.eql(current.target)) { | |
| 245 | 432 | switch (state) { |
| 246 | 433 | .start => {}, |
| 247 | 434 | .bind_single => try doBind(writer), |
| ... | ... | @@ -250,7 +437,7 @@ pub const WeakBind = struct { |
| 250 | 437 | state = .start; |
| 251 | 438 | target = current.target; |
| 252 | 439 | |
| 253 | const sym = ctx.getSymbol(current.target); | |
| 440 | const sym = current.target.getSymbol(ctx).?; | |
| 254 | 441 | const name = sym.getName(ctx); |
| 255 | 442 | const flags: u8 = 0; // TODO NON_WEAK_DEFINITION |
| 256 | 443 | |
| ... | ... | @@ -322,7 +509,6 @@ pub const WeakBind = struct { |
| 322 | 509 | } |
| 323 | 510 | |
| 324 | 511 | pub fn write(self: Self, writer: anytype) !void { |
| 325 | if (self.size() == 0) return; | |
| 326 | 512 | try writer.writeAll(self.buffer.items); |
| 327 | 513 | } |
| 328 | 514 | }; |
| ... | ... | @@ -340,11 +526,36 @@ pub const LazyBind = struct { |
| 340 | 526 | self.offsets.deinit(gpa); |
| 341 | 527 | } |
| 342 | 528 | |
| 343 | pub fn size(self: Self) u64 { | |
| 344 | return @intCast(self.buffer.items.len); | |
| 529 | pub fn updateSize(self: *Self, macho_file: *MachO) !void { | |
| 530 | const tracy = trace(@src()); | |
| 531 | defer tracy.end(); | |
| 532 | ||
| 533 | const gpa = macho_file.base.comp.gpa; | |
| 534 | ||
| 535 | const sid = macho_file.la_symbol_ptr_sect_index.?; | |
| 536 | const sect = macho_file.sections.items(.header)[sid]; | |
| 537 | const seg_id = macho_file.sections.items(.segment_id)[sid]; | |
| 538 | const seg = macho_file.segments.items[seg_id]; | |
| 539 | ||
| 540 | for (macho_file.stubs.symbols.items, 0..) |ref, idx| { | |
| 541 | const sym = ref.getSymbol(macho_file).?; | |
| 542 | const addr = sect.addr + idx * @sizeOf(u64); | |
| 543 | const bind_entry = Entry{ | |
| 544 | .target = ref, | |
| 545 | .offset = addr - seg.vmaddr, | |
| 546 | .segment_id = seg_id, | |
| 547 | .addend = 0, | |
| 548 | }; | |
| 549 | if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) { | |
| 550 | try self.entries.append(gpa, bind_entry); | |
| 551 | } | |
| 552 | } | |
| 553 | ||
| 554 | try self.finalize(gpa, macho_file); | |
| 555 | macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); | |
| 345 | 556 | } |
| 346 | 557 | |
| 347 | pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { | |
| 558 | fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { | |
| 348 | 559 | try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len); |
| 349 | 560 | |
| 350 | 561 | const writer = self.buffer.writer(gpa); |
| ... | ... | @@ -356,7 +567,7 @@ pub const LazyBind = struct { |
| 356 | 567 | for (self.entries.items) |entry| { |
| 357 | 568 | self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len)); |
| 358 | 569 | |
| 359 | const sym = ctx.getSymbol(entry.target); | |
| 570 | const sym = entry.target.getSymbol(ctx).?; | |
| 360 | 571 | const name = sym.getName(ctx); |
| 361 | 572 | const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; |
| 362 | 573 | const ordinal: i16 = ord: { |
| ... | ... | @@ -474,3 +685,17 @@ fn done(writer: anytype) !void { |
| 474 | 685 | log.debug(">>> done", .{}); |
| 475 | 686 | try writer.writeByte(macho.BIND_OPCODE_DONE); |
| 476 | 687 | } |
| 688 | ||
| 689 | const assert = std.debug.assert; | |
| 690 | const leb = std.leb; | |
| 691 | const log = std.log.scoped(.link_dyld_info); | |
| 692 | const macho = std.macho; | |
| 693 | const mem = std.mem; | |
| 694 | const testing = std.testing; | |
| 695 | const trace = @import("../../../tracy.zig").trace; | |
| 696 | const std = @import("std"); | |
| 697 | ||
| 698 | const Allocator = mem.Allocator; | |
| 699 | const File = @import("../file.zig").File; | |
| 700 | const MachO = @import("../../MachO.zig"); | |
| 701 | const Symbol = @import("../Symbol.zig"); |
src/link/MachO/eh_frame.zig+11-6| ... | ... | @@ -68,7 +68,8 @@ pub const Cie = struct { |
| 68 | 68 | |
| 69 | 69 | pub fn getPersonality(cie: Cie, macho_file: *MachO) ?*Symbol { |
| 70 | 70 | const personality = cie.personality orelse return null; |
| 71 | return macho_file.getSymbol(personality.index); | |
| 71 | const object = cie.getObject(macho_file); | |
| 72 | return object.getSymbolRef(personality.index, macho_file).getSymbol(macho_file); | |
| 72 | 73 | } |
| 73 | 74 | |
| 74 | 75 | pub fn eql(cie: Cie, other: Cie, macho_file: *MachO) bool { |
| ... | ... | @@ -223,11 +224,11 @@ pub const Fde = struct { |
| 223 | 224 | } |
| 224 | 225 | |
| 225 | 226 | pub fn getAtom(fde: Fde, macho_file: *MachO) *Atom { |
| 226 | return macho_file.getAtom(fde.atom).?; | |
| 227 | return fde.getObject(macho_file).getAtom(fde.atom).?; | |
| 227 | 228 | } |
| 228 | 229 | |
| 229 | 230 | pub fn getLsdaAtom(fde: Fde, macho_file: *MachO) ?*Atom { |
| 230 | return macho_file.getAtom(fde.lsda); | |
| 231 | return fde.getObject(macho_file).getAtom(fde.lsda); | |
| 231 | 232 | } |
| 232 | 233 | |
| 233 | 234 | pub fn format( |
| ... | ... | @@ -448,7 +449,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { |
| 448 | 449 | } |
| 449 | 450 | } |
| 450 | 451 | |
| 451 | pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho.relocation_info)) error{Overflow}!void { | |
| 452 | pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: []macho.relocation_info) error{Overflow}!void { | |
| 452 | 453 | const tracy = trace(@src()); |
| 453 | 454 | defer tracy.end(); |
| 454 | 455 | |
| ... | ... | @@ -459,6 +460,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 459 | 460 | else => 0, |
| 460 | 461 | }; |
| 461 | 462 | |
| 463 | var i: usize = 0; | |
| 462 | 464 | for (macho_file.objects.items) |index| { |
| 463 | 465 | const object = macho_file.getFile(index).?.object; |
| 464 | 466 | for (object.cies.items) |cie| { |
| ... | ... | @@ -469,7 +471,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 469 | 471 | if (cie.getPersonality(macho_file)) |sym| { |
| 470 | 472 | const r_address = math.cast(i32, cie.out_offset + cie.personality.?.offset) orelse return error.Overflow; |
| 471 | 473 | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; |
| 472 | relocs.appendAssumeCapacity(.{ | |
| 474 | relocs[i] = .{ | |
| 473 | 475 | .r_address = r_address, |
| 474 | 476 | .r_symbolnum = r_symbolnum, |
| 475 | 477 | .r_length = 2, |
| ... | ... | @@ -480,7 +482,8 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 480 | 482 | .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_GOT), |
| 481 | 483 | else => unreachable, |
| 482 | 484 | }, |
| 483 | }); | |
| 485 | }; | |
| 486 | i += 1; | |
| 484 | 487 | } |
| 485 | 488 | } |
| 486 | 489 | } |
| ... | ... | @@ -531,6 +534,8 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 531 | 534 | } |
| 532 | 535 | } |
| 533 | 536 | } |
| 537 | ||
| 538 | assert(relocs.len == i); | |
| 534 | 539 | } |
| 535 | 540 | |
| 536 | 541 | pub const EH_PE = struct { |
src/link/MachO/file.zig+224-97| ... | ... | @@ -24,41 +24,194 @@ pub const File = union(enum) { |
| 24 | 24 | _ = options; |
| 25 | 25 | switch (file) { |
| 26 | 26 | .zig_object => |x| try writer.writeAll(x.path), |
| 27 | .internal => try writer.writeAll(""), | |
| 27 | .internal => try writer.writeAll("internal"), | |
| 28 | 28 | .object => |x| try writer.print("{}", .{x.fmtPath()}), |
| 29 | 29 | .dylib => |x| try writer.writeAll(x.path), |
| 30 | 30 | } |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | pub fn resolveSymbols(file: File, macho_file: *MachO) void { | |
| 34 | switch (file) { | |
| 35 | .internal => unreachable, | |
| 33 | pub fn resolveSymbols(file: File, macho_file: *MachO) !void { | |
| 34 | return switch (file) { | |
| 36 | 35 | inline else => |x| x.resolveSymbols(macho_file), |
| 37 | } | |
| 36 | }; | |
| 38 | 37 | } |
| 39 | 38 | |
| 40 | pub fn resetGlobals(file: File, macho_file: *MachO) void { | |
| 39 | pub fn scanRelocs(file: File, macho_file: *MachO) !void { | |
| 41 | 40 | switch (file) { |
| 42 | .internal => unreachable, | |
| 43 | inline else => |x| x.resetGlobals(macho_file), | |
| 41 | .dylib => unreachable, | |
| 42 | .internal => |x| x.scanRelocs(macho_file), | |
| 43 | inline else => |x| x.scanRelocs(macho_file), | |
| 44 | } | |
| 45 | } | |
| 46 | ||
| 47 | /// Encodes symbol rank so that the following ordering applies: | |
| 48 | /// * strong in object | |
| 49 | /// * weak in object | |
| 50 | /// * tentative in object | |
| 51 | /// * strong in archive/dylib | |
| 52 | /// * weak in archive/dylib | |
| 53 | /// * tentative in archive | |
| 54 | /// * unclaimed | |
| 55 | pub fn getSymbolRank(file: File, args: struct { | |
| 56 | archive: bool = false, | |
| 57 | weak: bool = false, | |
| 58 | tentative: bool = false, | |
| 59 | }) u32 { | |
| 60 | if (file != .dylib and !args.archive) { | |
| 61 | const base: u32 = blk: { | |
| 62 | if (args.tentative) break :blk 3; | |
| 63 | break :blk if (args.weak) 2 else 1; | |
| 64 | }; | |
| 65 | return (base << 16) + file.getIndex(); | |
| 66 | } | |
| 67 | const base: u32 = blk: { | |
| 68 | if (args.tentative) break :blk 3; | |
| 69 | break :blk if (args.weak) 2 else 1; | |
| 70 | }; | |
| 71 | return base + (file.getIndex() << 24); | |
| 72 | } | |
| 73 | ||
| 74 | pub fn getAtom(file: File, atom_index: Atom.Index) ?*Atom { | |
| 75 | return switch (file) { | |
| 76 | .dylib => unreachable, | |
| 77 | inline else => |x| x.getAtom(atom_index), | |
| 78 | }; | |
| 79 | } | |
| 80 | ||
| 81 | pub fn getAtoms(file: File) []const Atom.Index { | |
| 82 | return switch (file) { | |
| 83 | .dylib => unreachable, | |
| 84 | inline else => |x| x.getAtoms(), | |
| 85 | }; | |
| 86 | } | |
| 87 | ||
| 88 | pub fn addAtomExtra(file: File, allocator: Allocator, extra: Atom.Extra) !u32 { | |
| 89 | return switch (file) { | |
| 90 | .dylib => unreachable, | |
| 91 | inline else => |x| x.addAtomExtra(allocator, extra), | |
| 92 | }; | |
| 93 | } | |
| 94 | ||
| 95 | pub fn getAtomExtra(file: File, index: u32) Atom.Extra { | |
| 96 | return switch (file) { | |
| 97 | .dylib => unreachable, | |
| 98 | inline else => |x| x.getAtomExtra(index), | |
| 99 | }; | |
| 100 | } | |
| 101 | ||
| 102 | pub fn setAtomExtra(file: File, index: u32, extra: Atom.Extra) void { | |
| 103 | return switch (file) { | |
| 104 | .dylib => unreachable, | |
| 105 | inline else => |x| x.setAtomExtra(index, extra), | |
| 106 | }; | |
| 107 | } | |
| 108 | ||
| 109 | pub fn getSymbols(file: File) []Symbol { | |
| 110 | return switch (file) { | |
| 111 | inline else => |x| x.symbols.items, | |
| 112 | }; | |
| 113 | } | |
| 114 | ||
| 115 | pub fn getSymbolRef(file: File, sym_index: Symbol.Index, macho_file: *MachO) MachO.Ref { | |
| 116 | return switch (file) { | |
| 117 | inline else => |x| x.getSymbolRef(sym_index, macho_file), | |
| 118 | }; | |
| 119 | } | |
| 120 | ||
| 121 | pub fn getNlists(file: File) []macho.nlist_64 { | |
| 122 | return switch (file) { | |
| 123 | .dylib => unreachable, | |
| 124 | .internal => |x| x.symtab.items, | |
| 125 | inline else => |x| x.symtab.items(.nlist), | |
| 126 | }; | |
| 127 | } | |
| 128 | ||
| 129 | pub fn getGlobals(file: File) []MachO.SymbolResolver.Index { | |
| 130 | return switch (file) { | |
| 131 | inline else => |x| x.globals.items, | |
| 132 | }; | |
| 133 | } | |
| 134 | ||
| 135 | pub fn markImportsExports(file: File, macho_file: *MachO) void { | |
| 136 | const tracy = trace(@src()); | |
| 137 | defer tracy.end(); | |
| 138 | ||
| 139 | const nsyms = switch (file) { | |
| 140 | .dylib => unreachable, | |
| 141 | inline else => |x| x.symbols.items.len, | |
| 142 | }; | |
| 143 | for (0..nsyms) |i| { | |
| 144 | const ref = file.getSymbolRef(@intCast(i), macho_file); | |
| 145 | if (ref.getFile(macho_file) == null) continue; | |
| 146 | const sym = ref.getSymbol(macho_file).?; | |
| 147 | if (sym.visibility != .global) continue; | |
| 148 | if (sym.getFile(macho_file).? == .dylib and !sym.flags.abs) { | |
| 149 | sym.flags.import = true; | |
| 150 | continue; | |
| 151 | } | |
| 152 | if (file.getIndex() == ref.file) { | |
| 153 | sym.flags.@"export" = true; | |
| 154 | } | |
| 44 | 155 | } |
| 45 | 156 | } |
| 46 | 157 | |
| 47 | pub fn claimUnresolved(file: File, macho_file: *MachO) error{OutOfMemory}!void { | |
| 158 | pub fn markExportsRelocatable(file: File, macho_file: *MachO) void { | |
| 159 | const tracy = trace(@src()); | |
| 160 | defer tracy.end(); | |
| 161 | ||
| 48 | 162 | assert(file == .object or file == .zig_object); |
| 49 | 163 | |
| 50 | for (file.getSymbols(), 0..) |sym_index, i| { | |
| 51 | const nlist_idx = @as(Symbol.Index, @intCast(i)); | |
| 52 | const nlist = switch (file) { | |
| 53 | .object => |x| x.symtab.items(.nlist)[nlist_idx], | |
| 54 | .zig_object => |x| x.symtab.items(.nlist)[nlist_idx], | |
| 55 | else => unreachable, | |
| 56 | }; | |
| 164 | for (file.getSymbols(), 0..) |*sym, i| { | |
| 165 | const ref = file.getSymbolRef(@intCast(i), macho_file); | |
| 166 | const other_file = ref.getFile(macho_file) orelse continue; | |
| 167 | if (other_file.getIndex() != file.getIndex()) continue; | |
| 168 | if (sym.visibility != .global) continue; | |
| 169 | sym.flags.@"export" = true; | |
| 170 | } | |
| 171 | } | |
| 172 | ||
| 173 | pub fn createSymbolIndirection(file: File, macho_file: *MachO) !void { | |
| 174 | const tracy = trace(@src()); | |
| 175 | defer tracy.end(); | |
| 176 | ||
| 177 | const nsyms = switch (file) { | |
| 178 | inline else => |x| x.symbols.items.len, | |
| 179 | }; | |
| 180 | for (0..nsyms) |i| { | |
| 181 | const ref = file.getSymbolRef(@intCast(i), macho_file); | |
| 182 | if (ref.getFile(macho_file) == null) continue; | |
| 183 | if (ref.file != file.getIndex()) continue; | |
| 184 | const sym = ref.getSymbol(macho_file).?; | |
| 185 | if (sym.flags.needs_got) { | |
| 186 | log.debug("'{s}' needs GOT", .{sym.getName(macho_file)}); | |
| 187 | try macho_file.got.addSymbol(ref, macho_file); | |
| 188 | } | |
| 189 | if (sym.flags.stubs) { | |
| 190 | log.debug("'{s}' needs STUBS", .{sym.getName(macho_file)}); | |
| 191 | try macho_file.stubs.addSymbol(ref, macho_file); | |
| 192 | } | |
| 193 | if (sym.flags.tlv_ptr) { | |
| 194 | log.debug("'{s}' needs TLV pointer", .{sym.getName(macho_file)}); | |
| 195 | try macho_file.tlv_ptr.addSymbol(ref, macho_file); | |
| 196 | } | |
| 197 | if (sym.flags.objc_stubs) { | |
| 198 | log.debug("'{s}' needs OBJC STUBS", .{sym.getName(macho_file)}); | |
| 199 | try macho_file.objc_stubs.addSymbol(ref, macho_file); | |
| 200 | } | |
| 201 | } | |
| 202 | } | |
| 203 | ||
| 204 | pub fn claimUnresolved(file: File, macho_file: *MachO) void { | |
| 205 | const tracy = trace(@src()); | |
| 206 | defer tracy.end(); | |
| 207 | ||
| 208 | assert(file == .object or file == .zig_object); | |
| 209 | ||
| 210 | for (file.getSymbols(), file.getNlists(), 0..) |*sym, nlist, i| { | |
| 57 | 211 | if (!nlist.ext()) continue; |
| 58 | 212 | if (!nlist.undf()) continue; |
| 59 | 213 | |
| 60 | const sym = macho_file.getSymbol(sym_index); | |
| 61 | if (sym.getFile(macho_file) != null) continue; | |
| 214 | if (file.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue; | |
| 62 | 215 | |
| 63 | 216 | const is_import = switch (macho_file.undefined_treatment) { |
| 64 | 217 | .@"error" => false, |
| ... | ... | @@ -67,111 +220,95 @@ pub const File = union(enum) { |
| 67 | 220 | }; |
| 68 | 221 | if (is_import) { |
| 69 | 222 | sym.value = 0; |
| 70 | sym.atom = 0; | |
| 71 | sym.nlist_idx = 0; | |
| 72 | sym.file = macho_file.internal_object.?; | |
| 223 | sym.atom_ref = .{ .index = 0, .file = 0 }; | |
| 73 | 224 | sym.flags.weak = false; |
| 74 | 225 | sym.flags.weak_ref = nlist.weakRef(); |
| 75 | 226 | sym.flags.import = is_import; |
| 76 | 227 | sym.visibility = .global; |
| 77 | try macho_file.getInternalObject().?.symbols.append(macho_file.base.comp.gpa, sym_index); | |
| 228 | ||
| 229 | const idx = file.getGlobals()[i]; | |
| 230 | macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = file.getIndex() }; | |
| 78 | 231 | } |
| 79 | 232 | } |
| 80 | 233 | } |
| 81 | 234 | |
| 82 | 235 | pub fn claimUnresolvedRelocatable(file: File, macho_file: *MachO) void { |
| 236 | const tracy = trace(@src()); | |
| 237 | defer tracy.end(); | |
| 238 | ||
| 83 | 239 | assert(file == .object or file == .zig_object); |
| 84 | 240 | |
| 85 | for (file.getSymbols(), 0..) |sym_index, i| { | |
| 86 | const nlist_idx = @as(Symbol.Index, @intCast(i)); | |
| 87 | const nlist = switch (file) { | |
| 88 | .object => |x| x.symtab.items(.nlist)[nlist_idx], | |
| 89 | .zig_object => |x| x.symtab.items(.nlist)[nlist_idx], | |
| 90 | else => unreachable, | |
| 91 | }; | |
| 241 | for (file.getSymbols(), file.getNlists(), 0..) |*sym, nlist, i| { | |
| 92 | 242 | if (!nlist.ext()) continue; |
| 93 | 243 | if (!nlist.undf()) continue; |
| 94 | ||
| 95 | const sym = macho_file.getSymbol(sym_index); | |
| 96 | if (sym.getFile(macho_file) != null) continue; | |
| 244 | if (file.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue; | |
| 97 | 245 | |
| 98 | 246 | sym.value = 0; |
| 99 | sym.atom = 0; | |
| 100 | sym.nlist_idx = nlist_idx; | |
| 101 | sym.file = file.getIndex(); | |
| 247 | sym.atom_ref = .{ .index = 0, .file = 0 }; | |
| 102 | 248 | sym.flags.weak_ref = nlist.weakRef(); |
| 103 | 249 | sym.flags.import = true; |
| 104 | 250 | sym.visibility = .global; |
| 251 | ||
| 252 | const idx = file.getGlobals()[i]; | |
| 253 | macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = file.getIndex() }; | |
| 105 | 254 | } |
| 106 | 255 | } |
| 107 | 256 | |
| 108 | pub fn markImportsExports(file: File, macho_file: *MachO) void { | |
| 109 | assert(file == .object or file == .zig_object); | |
| 257 | pub fn checkDuplicates(file: File, macho_file: *MachO) !void { | |
| 258 | const tracy = trace(@src()); | |
| 259 | defer tracy.end(); | |
| 260 | ||
| 261 | const gpa = macho_file.base.comp.gpa; | |
| 110 | 262 | |
| 111 | for (file.getSymbols()) |sym_index| { | |
| 112 | const sym = macho_file.getSymbol(sym_index); | |
| 113 | const other_file = sym.getFile(macho_file) orelse continue; | |
| 263 | for (file.getSymbols(), file.getNlists(), 0..) |sym, nlist, i| { | |
| 114 | 264 | if (sym.visibility != .global) continue; |
| 115 | if (other_file == .dylib and !sym.flags.abs) { | |
| 116 | sym.flags.import = true; | |
| 117 | continue; | |
| 118 | } | |
| 119 | if (other_file.getIndex() == file.getIndex()) { | |
| 120 | sym.flags.@"export" = true; | |
| 265 | if (sym.flags.weak) continue; | |
| 266 | if (nlist.undf()) continue; | |
| 267 | const ref = file.getSymbolRef(@intCast(i), macho_file); | |
| 268 | const ref_file = ref.getFile(macho_file) orelse continue; | |
| 269 | if (ref_file.getIndex() == file.getIndex()) continue; | |
| 270 | ||
| 271 | const gop = try macho_file.dupes.getOrPut(gpa, file.getGlobals()[i]); | |
| 272 | if (!gop.found_existing) { | |
| 273 | gop.value_ptr.* = .{}; | |
| 121 | 274 | } |
| 275 | try gop.value_ptr.append(gpa, file.getIndex()); | |
| 122 | 276 | } |
| 123 | 277 | } |
| 124 | 278 | |
| 125 | pub fn markExportsRelocatable(file: File, macho_file: *MachO) void { | |
| 126 | assert(file == .object or file == .zig_object); | |
| 127 | ||
| 128 | for (file.getSymbols()) |sym_index| { | |
| 129 | const sym = macho_file.getSymbol(sym_index); | |
| 130 | const other_file = sym.getFile(macho_file) orelse continue; | |
| 131 | if (sym.visibility != .global) continue; | |
| 132 | if (other_file.getIndex() == file.getIndex()) { | |
| 133 | sym.flags.@"export" = true; | |
| 134 | } | |
| 279 | pub fn initOutputSections(file: File, macho_file: *MachO) !void { | |
| 280 | const tracy = trace(@src()); | |
| 281 | defer tracy.end(); | |
| 282 | for (file.getAtoms()) |atom_index| { | |
| 283 | const atom = file.getAtom(atom_index) orelse continue; | |
| 284 | if (!atom.flags.alive) continue; | |
| 285 | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file); | |
| 135 | 286 | } |
| 136 | 287 | } |
| 137 | 288 | |
| 138 | /// Encodes symbol rank so that the following ordering applies: | |
| 139 | /// * strong in object | |
| 140 | /// * weak in object | |
| 141 | /// * tentative in object | |
| 142 | /// * strong in archive/dylib | |
| 143 | /// * weak in archive/dylib | |
| 144 | /// * tentative in archive | |
| 145 | /// * unclaimed | |
| 146 | pub fn getSymbolRank(file: File, args: struct { | |
| 147 | archive: bool = false, | |
| 148 | weak: bool = false, | |
| 149 | tentative: bool = false, | |
| 150 | }) u32 { | |
| 151 | if (file == .object and !args.archive) { | |
| 152 | const base: u32 = blk: { | |
| 153 | if (args.tentative) break :blk 3; | |
| 154 | break :blk if (args.weak) 2 else 1; | |
| 155 | }; | |
| 156 | return (base << 16) + file.getIndex(); | |
| 157 | } | |
| 158 | const base: u32 = blk: { | |
| 159 | if (args.tentative) break :blk 3; | |
| 160 | break :blk if (args.weak) 2 else 1; | |
| 289 | pub fn dedupLiterals(file: File, lp: MachO.LiteralPool, macho_file: *MachO) void { | |
| 290 | return switch (file) { | |
| 291 | .dylib => unreachable, | |
| 292 | inline else => |x| x.dedupLiterals(lp, macho_file), | |
| 161 | 293 | }; |
| 162 | return base + (file.getIndex() << 24); | |
| 163 | 294 | } |
| 164 | 295 | |
| 165 | pub fn getSymbols(file: File) []const Symbol.Index { | |
| 296 | pub fn writeAtoms(file: File, macho_file: *MachO) !void { | |
| 166 | 297 | return switch (file) { |
| 167 | inline else => |x| x.symbols.items, | |
| 298 | .dylib, .zig_object => unreachable, | |
| 299 | inline else => |x| x.writeAtoms(macho_file), | |
| 168 | 300 | }; |
| 169 | 301 | } |
| 170 | 302 | |
| 171 | pub fn getAtoms(file: File) []const Atom.Index { | |
| 303 | pub fn calcSymtabSize(file: File, macho_file: *MachO) void { | |
| 172 | 304 | return switch (file) { |
| 173 | .dylib => unreachable, | |
| 174 | inline else => |x| x.atoms.items, | |
| 305 | inline else => |x| x.calcSymtabSize(macho_file), | |
| 306 | }; | |
| 307 | } | |
| 308 | ||
| 309 | pub fn writeSymtab(file: File, macho_file: *MachO, ctx: anytype) void { | |
| 310 | return switch (file) { | |
| 311 | inline else => |x| x.writeSymtab(macho_file, ctx), | |
| 175 | 312 | }; |
| 176 | 313 | } |
| 177 | 314 | |
| ... | ... | @@ -198,18 +335,6 @@ pub const File = union(enum) { |
| 198 | 335 | }; |
| 199 | 336 | } |
| 200 | 337 | |
| 201 | pub fn calcSymtabSize(file: File, macho_file: *MachO) !void { | |
| 202 | return switch (file) { | |
| 203 | inline else => |x| x.calcSymtabSize(macho_file), | |
| 204 | }; | |
| 205 | } | |
| 206 | ||
| 207 | pub fn writeSymtab(file: File, macho_file: *MachO, ctx: anytype) !void { | |
| 208 | return switch (file) { | |
| 209 | inline else => |x| x.writeSymtab(macho_file, ctx), | |
| 210 | }; | |
| 211 | } | |
| 212 | ||
| 213 | 338 | pub const Index = u32; |
| 214 | 339 | |
| 215 | 340 | pub const Entry = union(enum) { |
| ... | ... | @@ -225,8 +350,10 @@ pub const File = union(enum) { |
| 225 | 350 | }; |
| 226 | 351 | |
| 227 | 352 | const assert = std.debug.assert; |
| 353 | const log = std.log.scoped(.link); | |
| 228 | 354 | const macho = std.macho; |
| 229 | 355 | const std = @import("std"); |
| 356 | const trace = @import("../../tracy.zig").trace; | |
| 230 | 357 | |
| 231 | 358 | const Allocator = std.mem.Allocator; |
| 232 | 359 | const Archive = @import("Archive.zig"); |
src/link/MachO/relocatable.zig+222-286| ... | ... | @@ -44,9 +44,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c |
| 44 | 44 | |
| 45 | 45 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 46 | 46 | |
| 47 | try macho_file.addUndefinedGlobals(); | |
| 48 | 47 | try macho_file.resolveSymbols(); |
| 49 | try macho_file.parseDebugInfo(); | |
| 50 | 48 | try macho_file.dedupLiterals(); |
| 51 | 49 | markExports(macho_file); |
| 52 | 50 | claimUnresolved(macho_file); |
| ... | ... | @@ -59,28 +57,13 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c |
| 59 | 57 | try allocateSections(macho_file); |
| 60 | 58 | allocateSegment(macho_file); |
| 61 | 59 | |
| 62 | var off = off: { | |
| 63 | const seg = macho_file.segments.items[0]; | |
| 64 | const off = math.cast(u32, seg.fileoff + seg.filesize) orelse return error.Overflow; | |
| 65 | break :off mem.alignForward(u32, off, @alignOf(macho.relocation_info)); | |
| 66 | }; | |
| 67 | off = allocateSectionsRelocs(macho_file, off); | |
| 68 | ||
| 69 | 60 | if (build_options.enable_logging) { |
| 70 | 61 | state_log.debug("{}", .{macho_file.dumpState()}); |
| 71 | 62 | } |
| 72 | 63 | |
| 73 | try macho_file.calcSymtabSize(); | |
| 74 | try writeAtoms(macho_file); | |
| 75 | try writeCompactUnwind(macho_file); | |
| 76 | try writeEhFrame(macho_file); | |
| 77 | ||
| 78 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 79 | off = try macho_file.writeDataInCode(0, off); | |
| 80 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 81 | off = try macho_file.writeSymtab(off); | |
| 82 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 83 | off = try macho_file.writeStrtab(off); | |
| 64 | try writeSections(macho_file); | |
| 65 | sortRelocs(macho_file); | |
| 66 | try writeSectionsToFile(macho_file); | |
| 84 | 67 | |
| 85 | 68 | // In order to please Apple ld (and possibly other MachO linkers in the wild), |
| 86 | 69 | // we will now sanitize segment names of Zig-specific segments. |
| ... | ... | @@ -129,7 +112,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 129 | 112 | |
| 130 | 113 | // First, we flush relocatable object file generated with our backends. |
| 131 | 114 | if (macho_file.getZigObject()) |zo| { |
| 132 | zo.resolveSymbols(macho_file); | |
| 115 | try zo.resolveSymbols(macho_file); | |
| 133 | 116 | zo.asFile().markExportsRelocatable(macho_file); |
| 134 | 117 | zo.asFile().claimUnresolvedRelocatable(macho_file); |
| 135 | 118 | try macho_file.sortSections(); |
| ... | ... | @@ -139,26 +122,13 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 139 | 122 | try allocateSections(macho_file); |
| 140 | 123 | allocateSegment(macho_file); |
| 141 | 124 | |
| 142 | var off = off: { | |
| 143 | const seg = macho_file.segments.items[0]; | |
| 144 | const off = math.cast(u32, seg.fileoff + seg.filesize) orelse return error.Overflow; | |
| 145 | break :off mem.alignForward(u32, off, @alignOf(macho.relocation_info)); | |
| 146 | }; | |
| 147 | off = allocateSectionsRelocs(macho_file, off); | |
| 148 | ||
| 149 | 125 | if (build_options.enable_logging) { |
| 150 | 126 | state_log.debug("{}", .{macho_file.dumpState()}); |
| 151 | 127 | } |
| 152 | 128 | |
| 153 | try macho_file.calcSymtabSize(); | |
| 154 | try writeAtoms(macho_file); | |
| 155 | ||
| 156 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 157 | off = try macho_file.writeDataInCode(0, off); | |
| 158 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 159 | off = try macho_file.writeSymtab(off); | |
| 160 | off = mem.alignForward(u32, off, @alignOf(u64)); | |
| 161 | off = try macho_file.writeStrtab(off); | |
| 129 | try writeSections(macho_file); | |
| 130 | sortRelocs(macho_file); | |
| 131 | try writeSectionsToFile(macho_file); | |
| 162 | 132 | |
| 163 | 133 | // In order to please Apple ld (and possibly other MachO linkers in the wild), |
| 164 | 134 | // we will now sanitize segment names of Zig-specific segments. |
| ... | ... | @@ -169,7 +139,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 169 | 139 | |
| 170 | 140 | // TODO we can avoid reading in the file contents we just wrote if we give the linker |
| 171 | 141 | // ability to write directly to a buffer. |
| 172 | try zo.readFileContents(off, macho_file); | |
| 142 | try zo.readFileContents(macho_file); | |
| 173 | 143 | } |
| 174 | 144 | |
| 175 | 145 | var files = std.ArrayList(File.Index).init(gpa); |
| ... | ... | @@ -286,12 +256,15 @@ fn parseObject(macho_file: *MachO, path: []const u8) MachO.ParseError!void { |
| 286 | 256 | break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); |
| 287 | 257 | }; |
| 288 | 258 | const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa))); |
| 289 | macho_file.files.set(index, .{ .object = .{ | |
| 290 | .path = try gpa.dupe(u8, path), | |
| 291 | .file_handle = handle, | |
| 292 | .mtime = mtime, | |
| 293 | .index = index, | |
| 294 | } }); | |
| 259 | macho_file.files.set(index, .{ | |
| 260 | .object = .{ | |
| 261 | .offset = 0, // TODO FAT objects | |
| 262 | .path = try gpa.dupe(u8, path), | |
| 263 | .file_handle = handle, | |
| 264 | .mtime = mtime, | |
| 265 | .index = index, | |
| 266 | }, | |
| 267 | }); | |
| 295 | 268 | try macho_file.objects.append(gpa, index); |
| 296 | 269 | |
| 297 | 270 | const object = macho_file.getFile(index).?.object; |
| ... | ... | @@ -347,9 +320,9 @@ pub fn claimUnresolved(macho_file: *MachO) void { |
| 347 | 320 | |
| 348 | 321 | fn initOutputSections(macho_file: *MachO) !void { |
| 349 | 322 | for (macho_file.objects.items) |index| { |
| 350 | const object = macho_file.getFile(index).?.object; | |
| 351 | for (object.atoms.items) |atom_index| { | |
| 352 | const atom = macho_file.getAtom(atom_index) orelse continue; | |
| 323 | const file = macho_file.getFile(index).?; | |
| 324 | for (file.getAtoms()) |atom_index| { | |
| 325 | const atom = file.getAtom(atom_index) orelse continue; | |
| 353 | 326 | if (!atom.flags.alive) continue; |
| 354 | 327 | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file); |
| 355 | 328 | } |
| ... | ... | @@ -377,69 +350,147 @@ fn calcSectionSizes(macho_file: *MachO) !void { |
| 377 | 350 | const tracy = trace(@src()); |
| 378 | 351 | defer tracy.end(); |
| 379 | 352 | |
| 380 | const slice = macho_file.sections.slice(); | |
| 381 | for (slice.items(.header), slice.items(.atoms)) |*header, atoms| { | |
| 353 | for (macho_file.sections.items(.atoms), 0..) |atoms, i| { | |
| 382 | 354 | if (atoms.items.len == 0) continue; |
| 383 | for (atoms.items) |atom_index| { | |
| 384 | const atom = macho_file.getAtom(atom_index).?; | |
| 385 | const atom_alignment = atom.alignment.toByteUnits() orelse 1; | |
| 386 | const offset = mem.alignForward(u64, header.size, atom_alignment); | |
| 387 | const padding = offset - header.size; | |
| 388 | atom.value = offset; | |
| 389 | header.size += padding + atom.size; | |
| 390 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); | |
| 391 | header.nreloc += atom.calcNumRelocs(macho_file); | |
| 392 | } | |
| 355 | calcSectionSize(macho_file, @intCast(i)); | |
| 393 | 356 | } |
| 394 | 357 | |
| 395 | if (macho_file.unwind_info_sect_index) |index| { | |
| 396 | calcCompactUnwindSize(macho_file, index); | |
| 358 | if (macho_file.getZigObject()) |zo| { | |
| 359 | // TODO this will create a race | |
| 360 | zo.calcNumRelocs(macho_file); | |
| 361 | zo.calcSymtabSize(macho_file); | |
| 397 | 362 | } |
| 398 | 363 | |
| 399 | if (macho_file.eh_frame_sect_index) |index| { | |
| 400 | const sect = &macho_file.sections.items(.header)[index]; | |
| 401 | sect.size = try eh_frame.calcSize(macho_file); | |
| 402 | sect.@"align" = 3; | |
| 403 | sect.nreloc = eh_frame.calcNumRelocs(macho_file); | |
| 364 | if (macho_file.eh_frame_sect_index) |_| { | |
| 365 | try calcEhFrameSize(macho_file); | |
| 404 | 366 | } |
| 405 | 367 | |
| 406 | if (macho_file.getZigObject()) |zo| { | |
| 407 | for (zo.atoms.items) |atom_index| { | |
| 408 | const atom = macho_file.getAtom(atom_index) orelse continue; | |
| 409 | if (!atom.flags.alive) continue; | |
| 410 | const header = &macho_file.sections.items(.header)[atom.out_n_sect]; | |
| 411 | if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; | |
| 412 | header.nreloc += atom.calcNumRelocs(macho_file); | |
| 368 | for (macho_file.objects.items) |index| { | |
| 369 | if (macho_file.unwind_info_sect_index) |_| { | |
| 370 | macho_file.getFile(index).?.object.calcCompactUnwindSizeRelocatable(macho_file); | |
| 413 | 371 | } |
| 372 | macho_file.getFile(index).?.calcSymtabSize(macho_file); | |
| 414 | 373 | } |
| 374 | ||
| 375 | try macho_file.data_in_code.updateSize(macho_file); | |
| 376 | ||
| 377 | if (macho_file.unwind_info_sect_index) |_| { | |
| 378 | calcCompactUnwindSize(macho_file); | |
| 379 | } | |
| 380 | try calcSymtabSize(macho_file); | |
| 381 | } | |
| 382 | ||
| 383 | fn calcSectionSize(macho_file: *MachO, sect_id: u8) void { | |
| 384 | const tracy = trace(@src()); | |
| 385 | defer tracy.end(); | |
| 386 | ||
| 387 | const slice = macho_file.sections.slice(); | |
| 388 | const header = &slice.items(.header)[sect_id]; | |
| 389 | const atoms = slice.items(.atoms)[sect_id].items; | |
| 390 | for (atoms) |ref| { | |
| 391 | const atom = ref.getAtom(macho_file).?; | |
| 392 | const atom_alignment = atom.alignment.toByteUnits() orelse 1; | |
| 393 | const offset = mem.alignForward(u64, header.size, atom_alignment); | |
| 394 | const padding = offset - header.size; | |
| 395 | atom.value = offset; | |
| 396 | header.size += padding + atom.size; | |
| 397 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); | |
| 398 | const nreloc = atom.calcNumRelocs(macho_file); | |
| 399 | atom.addExtra(.{ .rel_out_index = header.nreloc, .rel_out_count = nreloc }, macho_file); | |
| 400 | header.nreloc += nreloc; | |
| 401 | } | |
| 402 | } | |
| 403 | ||
| 404 | fn calcEhFrameSize(macho_file: *MachO) !void { | |
| 405 | const tracy = trace(@src()); | |
| 406 | defer tracy.end(); | |
| 407 | ||
| 408 | const header = &macho_file.sections.items(.header)[macho_file.eh_frame_sect_index.?]; | |
| 409 | header.size = try eh_frame.calcSize(macho_file); | |
| 410 | header.@"align" = 3; | |
| 411 | header.nreloc = eh_frame.calcNumRelocs(macho_file); | |
| 415 | 412 | } |
| 416 | 413 | |
| 417 | fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { | |
| 418 | var size: u32 = 0; | |
| 414 | fn calcCompactUnwindSize(macho_file: *MachO) void { | |
| 415 | const tracy = trace(@src()); | |
| 416 | defer tracy.end(); | |
| 417 | ||
| 418 | var nrec: u32 = 0; | |
| 419 | 419 | var nreloc: u32 = 0; |
| 420 | 420 | |
| 421 | 421 | for (macho_file.objects.items) |index| { |
| 422 | const object = macho_file.getFile(index).?.object; | |
| 423 | for (object.unwind_records.items) |irec| { | |
| 424 | const rec = macho_file.getUnwindRecord(irec); | |
| 425 | if (!rec.alive) continue; | |
| 426 | size += @sizeOf(macho.compact_unwind_entry); | |
| 427 | nreloc += 1; | |
| 428 | if (rec.getPersonality(macho_file)) |_| { | |
| 429 | nreloc += 1; | |
| 430 | } | |
| 431 | if (rec.getLsdaAtom(macho_file)) |_| { | |
| 432 | nreloc += 1; | |
| 433 | } | |
| 434 | } | |
| 422 | const ctx = &macho_file.getFile(index).?.object.compact_unwind_ctx; | |
| 423 | ctx.rec_index = nrec; | |
| 424 | ctx.reloc_index = nreloc; | |
| 425 | nrec += ctx.rec_count; | |
| 426 | nreloc += ctx.reloc_count; | |
| 435 | 427 | } |
| 436 | 428 | |
| 437 | const sect = &macho_file.sections.items(.header)[sect_index]; | |
| 438 | sect.size = size; | |
| 429 | const sect = &macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?]; | |
| 430 | sect.size = nrec * @sizeOf(macho.compact_unwind_entry); | |
| 439 | 431 | sect.nreloc = nreloc; |
| 440 | 432 | sect.@"align" = 3; |
| 441 | 433 | } |
| 442 | 434 | |
| 435 | fn calcSymtabSize(macho_file: *MachO) error{OutOfMemory}!void { | |
| 436 | const tracy = trace(@src()); | |
| 437 | defer tracy.end(); | |
| 438 | ||
| 439 | const gpa = macho_file.base.comp.gpa; | |
| 440 | ||
| 441 | var nlocals: u32 = 0; | |
| 442 | var nstabs: u32 = 0; | |
| 443 | var nexports: u32 = 0; | |
| 444 | var nimports: u32 = 0; | |
| 445 | var strsize: u32 = 1; | |
| 446 | ||
| 447 | var objects = try std.ArrayList(File.Index).initCapacity(gpa, macho_file.objects.items.len + 1); | |
| 448 | defer objects.deinit(); | |
| 449 | if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index); | |
| 450 | objects.appendSliceAssumeCapacity(macho_file.objects.items); | |
| 451 | ||
| 452 | for (objects.items) |index| { | |
| 453 | const ctx = switch (macho_file.getFile(index).?) { | |
| 454 | inline else => |x| &x.output_symtab_ctx, | |
| 455 | }; | |
| 456 | ctx.ilocal = nlocals; | |
| 457 | ctx.istab = nstabs; | |
| 458 | ctx.iexport = nexports; | |
| 459 | ctx.iimport = nimports; | |
| 460 | ctx.stroff = strsize; | |
| 461 | nlocals += ctx.nlocals; | |
| 462 | nstabs += ctx.nstabs; | |
| 463 | nexports += ctx.nexports; | |
| 464 | nimports += ctx.nimports; | |
| 465 | strsize += ctx.strsize; | |
| 466 | } | |
| 467 | ||
| 468 | for (objects.items) |index| { | |
| 469 | const ctx = switch (macho_file.getFile(index).?) { | |
| 470 | inline else => |x| &x.output_symtab_ctx, | |
| 471 | }; | |
| 472 | ctx.istab += nlocals; | |
| 473 | ctx.iexport += nlocals + nstabs; | |
| 474 | ctx.iimport += nlocals + nstabs + nexports; | |
| 475 | } | |
| 476 | ||
| 477 | { | |
| 478 | const cmd = &macho_file.symtab_cmd; | |
| 479 | cmd.nsyms = nlocals + nstabs + nexports + nimports; | |
| 480 | cmd.strsize = strsize; | |
| 481 | } | |
| 482 | ||
| 483 | { | |
| 484 | const cmd = &macho_file.dysymtab_cmd; | |
| 485 | cmd.ilocalsym = 0; | |
| 486 | cmd.nlocalsym = nlocals + nstabs; | |
| 487 | cmd.iextdefsym = nlocals + nstabs; | |
| 488 | cmd.nextdefsym = nexports; | |
| 489 | cmd.iundefsym = nlocals + nstabs + nexports; | |
| 490 | cmd.nundefsym = nimports; | |
| 491 | } | |
| 492 | } | |
| 493 | ||
| 443 | 494 | fn allocateSections(macho_file: *MachO) !void { |
| 444 | 495 | const slice = macho_file.sections.slice(); |
| 445 | 496 | for (slice.items(.header)) |*header| { |
| ... | ... | @@ -457,6 +508,37 @@ fn allocateSections(macho_file: *MachO) !void { |
| 457 | 508 | } |
| 458 | 509 | header.size = needed_size; |
| 459 | 510 | } |
| 511 | ||
| 512 | var fileoff: u32 = 0; | |
| 513 | for (slice.items(.header)) |header| { | |
| 514 | fileoff = @max(fileoff, header.offset + @as(u32, @intCast(header.size))); | |
| 515 | } | |
| 516 | ||
| 517 | for (slice.items(.header)) |*header| { | |
| 518 | if (header.nreloc == 0) continue; | |
| 519 | header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info)); | |
| 520 | fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info); | |
| 521 | } | |
| 522 | ||
| 523 | // In -r mode, there is no LINKEDIT segment and so we allocate required LINKEDIT commands | |
| 524 | // as if they were detached or part of the single segment. | |
| 525 | ||
| 526 | // DATA_IN_CODE | |
| 527 | { | |
| 528 | const cmd = &macho_file.data_in_code_cmd; | |
| 529 | cmd.dataoff = fileoff; | |
| 530 | fileoff += cmd.datasize; | |
| 531 | fileoff = mem.alignForward(u32, fileoff, @alignOf(u64)); | |
| 532 | } | |
| 533 | ||
| 534 | // SYMTAB | |
| 535 | { | |
| 536 | const cmd = &macho_file.symtab_cmd; | |
| 537 | cmd.symoff = fileoff; | |
| 538 | fileoff += cmd.nsyms * @sizeOf(macho.nlist_64); | |
| 539 | fileoff = mem.alignForward(u32, fileoff, @alignOf(u32)); | |
| 540 | cmd.stroff = fileoff; | |
| 541 | } | |
| 460 | 542 | } |
| 461 | 543 | |
| 462 | 544 | /// Renames segment names in Zig sections to standard MachO segment names such as |
| ... | ... | @@ -519,232 +601,86 @@ fn allocateSegment(macho_file: *MachO) void { |
| 519 | 601 | seg.filesize = fileoff - seg.fileoff; |
| 520 | 602 | } |
| 521 | 603 | |
| 522 | fn allocateSectionsRelocs(macho_file: *MachO, off: u32) u32 { | |
| 523 | var fileoff = off; | |
| 524 | const slice = macho_file.sections.slice(); | |
| 525 | for (slice.items(.header)) |*header| { | |
| 526 | if (header.nreloc == 0) continue; | |
| 527 | header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info)); | |
| 528 | fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info); | |
| 529 | } | |
| 530 | return fileoff; | |
| 531 | } | |
| 532 | ||
| 533 | 604 | // We need to sort relocations in descending order to be compatible with Apple's linker. |
| 534 | 605 | fn sortReloc(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation_info) bool { |
| 535 | 606 | _ = ctx; |
| 536 | 607 | return lhs.r_address > rhs.r_address; |
| 537 | 608 | } |
| 538 | 609 | |
| 539 | fn writeAtoms(macho_file: *MachO) !void { | |
| 610 | fn sortRelocs(macho_file: *MachO) void { | |
| 611 | const tracy = trace(@src()); | |
| 612 | defer tracy.end(); | |
| 613 | ||
| 614 | for (macho_file.sections.items(.relocs)) |*relocs| { | |
| 615 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); | |
| 616 | } | |
| 617 | } | |
| 618 | ||
| 619 | fn writeSections(macho_file: *MachO) !void { | |
| 540 | 620 | const tracy = trace(@src()); |
| 541 | 621 | defer tracy.end(); |
| 542 | 622 | |
| 543 | 623 | const gpa = macho_file.base.comp.gpa; |
| 544 | 624 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 545 | 625 | const slice = macho_file.sections.slice(); |
| 546 | ||
| 547 | var relocs = std.ArrayList(macho.relocation_info).init(gpa); | |
| 548 | defer relocs.deinit(); | |
| 549 | ||
| 550 | for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| { | |
| 551 | if (atoms.items.len == 0) continue; | |
| 626 | for (slice.items(.header), slice.items(.out), slice.items(.relocs), 0..) |header, *out, *relocs, n_sect| { | |
| 552 | 627 | if (header.isZerofill()) continue; |
| 553 | if (macho_file.isZigSection(@intCast(i)) or macho_file.isDebugSection(@intCast(i))) continue; | |
| 554 | ||
| 555 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 556 | const code = try gpa.alloc(u8, size); | |
| 557 | defer gpa.free(code); | |
| 558 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; | |
| 559 | @memset(code, padding_byte); | |
| 560 | ||
| 561 | try relocs.ensureTotalCapacity(header.nreloc); | |
| 562 | ||
| 563 | for (atoms.items) |atom_index| { | |
| 564 | const atom = macho_file.getAtom(atom_index).?; | |
| 565 | assert(atom.flags.alive); | |
| 566 | const off = math.cast(usize, atom.value) orelse return error.Overflow; | |
| 567 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 568 | try atom.getData(macho_file, code[off..][0..atom_size]); | |
| 569 | try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs); | |
| 628 | if (!macho_file.isZigSection(@intCast(n_sect))) { // TODO this is wrong; what about debug sections? | |
| 629 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 630 | try out.resize(gpa, size); | |
| 631 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; | |
| 632 | @memset(out.items, padding_byte); | |
| 570 | 633 | } |
| 634 | try relocs.resize(gpa, header.nreloc); | |
| 635 | } | |
| 571 | 636 | |
| 572 | assert(relocs.items.len == header.nreloc); | |
| 573 | ||
| 574 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); | |
| 575 | ||
| 576 | // TODO scattered writes? | |
| 577 | try macho_file.base.file.?.pwriteAll(code, header.offset); | |
| 578 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | |
| 637 | const cmd = macho_file.symtab_cmd; | |
| 638 | try macho_file.symtab.resize(gpa, cmd.nsyms); | |
| 639 | try macho_file.strtab.resize(gpa, cmd.strsize); | |
| 640 | macho_file.strtab.items[0] = 0; | |
| 579 | 641 | |
| 580 | relocs.clearRetainingCapacity(); | |
| 642 | for (macho_file.objects.items) |index| { | |
| 643 | try macho_file.getFile(index).?.object.writeAtomsRelocatable(macho_file); | |
| 644 | macho_file.getFile(index).?.writeSymtab(macho_file, macho_file); | |
| 581 | 645 | } |
| 582 | 646 | |
| 583 | 647 | if (macho_file.getZigObject()) |zo| { |
| 584 | // TODO: this is ugly; perhaps we should aggregrate before? | |
| 585 | var zo_relocs = std.AutoArrayHashMap(u8, std.ArrayList(macho.relocation_info)).init(gpa); | |
| 586 | defer { | |
| 587 | for (zo_relocs.values()) |*list| { | |
| 588 | list.deinit(); | |
| 589 | } | |
| 590 | zo_relocs.deinit(); | |
| 591 | } | |
| 592 | ||
| 593 | for (macho_file.sections.items(.header), 0..) |header, n_sect| { | |
| 594 | if (header.isZerofill()) continue; | |
| 595 | if (!macho_file.isZigSection(@intCast(n_sect)) and !macho_file.isDebugSection(@intCast(n_sect))) continue; | |
| 596 | const gop = try zo_relocs.getOrPut(@intCast(n_sect)); | |
| 597 | if (gop.found_existing) continue; | |
| 598 | gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc); | |
| 599 | } | |
| 600 | ||
| 601 | for (zo.atoms.items) |atom_index| { | |
| 602 | const atom = macho_file.getAtom(atom_index) orelse continue; | |
| 603 | if (!atom.flags.alive) continue; | |
| 604 | const header = macho_file.sections.items(.header)[atom.out_n_sect]; | |
| 605 | if (header.isZerofill()) continue; | |
| 606 | if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; | |
| 607 | if (atom.getRelocs(macho_file).len == 0) continue; | |
| 608 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 609 | const code = try gpa.alloc(u8, atom_size); | |
| 610 | defer gpa.free(code); | |
| 611 | atom.getData(macho_file, code) catch |err| switch (err) { | |
| 612 | error.InputOutput => { | |
| 613 | try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{ | |
| 614 | atom.getName(macho_file), | |
| 615 | }); | |
| 616 | return error.FlushFailure; | |
| 617 | }, | |
| 618 | else => |e| { | |
| 619 | try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{ | |
| 620 | atom.getName(macho_file), | |
| 621 | @errorName(e), | |
| 622 | }); | |
| 623 | return error.FlushFailure; | |
| 624 | }, | |
| 625 | }; | |
| 626 | const file_offset = header.offset + atom.value; | |
| 627 | const rels = zo_relocs.getPtr(atom.out_n_sect).?; | |
| 628 | try atom.writeRelocs(macho_file, code, rels); | |
| 629 | try macho_file.base.file.?.pwriteAll(code, file_offset); | |
| 630 | } | |
| 631 | ||
| 632 | for (zo_relocs.keys(), zo_relocs.values()) |sect_id, rels| { | |
| 633 | const header = macho_file.sections.items(.header)[sect_id]; | |
| 634 | assert(rels.items.len == header.nreloc); | |
| 635 | mem.sort(macho.relocation_info, rels.items, {}, sortReloc); | |
| 636 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(rels.items), header.reloff); | |
| 637 | } | |
| 648 | try zo.writeRelocs(macho_file); | |
| 649 | try zo.writeAtomsRelocatable(macho_file); | |
| 650 | zo.writeSymtab(macho_file, macho_file); | |
| 638 | 651 | } |
| 639 | } | |
| 640 | ||
| 641 | fn writeCompactUnwind(macho_file: *MachO) !void { | |
| 642 | const sect_index = macho_file.unwind_info_sect_index orelse return; | |
| 643 | const gpa = macho_file.base.comp.gpa; | |
| 644 | const header = macho_file.sections.items(.header)[sect_index]; | |
| 645 | ||
| 646 | const nrecs = math.cast(usize, @divExact(header.size, @sizeOf(macho.compact_unwind_entry))) orelse return error.Overflow; | |
| 647 | var entries = try std.ArrayList(macho.compact_unwind_entry).initCapacity(gpa, nrecs); | |
| 648 | defer entries.deinit(); | |
| 649 | ||
| 650 | var relocs = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc); | |
| 651 | defer relocs.deinit(); | |
| 652 | ||
| 653 | const addReloc = struct { | |
| 654 | fn addReloc(offset: i32, cpu_arch: std.Target.Cpu.Arch) macho.relocation_info { | |
| 655 | return .{ | |
| 656 | .r_address = offset, | |
| 657 | .r_symbolnum = 0, | |
| 658 | .r_pcrel = 0, | |
| 659 | .r_length = 3, | |
| 660 | .r_extern = 0, | |
| 661 | .r_type = switch (cpu_arch) { | |
| 662 | .aarch64 => @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), | |
| 663 | .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), | |
| 664 | else => unreachable, | |
| 665 | }, | |
| 666 | }; | |
| 667 | } | |
| 668 | }.addReloc; | |
| 669 | ||
| 670 | var offset: i32 = 0; | |
| 671 | for (macho_file.objects.items) |index| { | |
| 672 | const object = macho_file.getFile(index).?.object; | |
| 673 | for (object.unwind_records.items) |irec| { | |
| 674 | const rec = macho_file.getUnwindRecord(irec); | |
| 675 | if (!rec.alive) continue; | |
| 676 | ||
| 677 | var out: macho.compact_unwind_entry = .{ | |
| 678 | .rangeStart = 0, | |
| 679 | .rangeLength = rec.length, | |
| 680 | .compactUnwindEncoding = rec.enc.enc, | |
| 681 | .personalityFunction = 0, | |
| 682 | .lsda = 0, | |
| 683 | }; | |
| 684 | ||
| 685 | { | |
| 686 | // Function address | |
| 687 | const atom = rec.getAtom(macho_file); | |
| 688 | const addr = rec.getAtomAddress(macho_file); | |
| 689 | out.rangeStart = addr; | |
| 690 | var reloc = addReloc(offset, macho_file.getTarget().cpu.arch); | |
| 691 | reloc.r_symbolnum = atom.out_n_sect + 1; | |
| 692 | relocs.appendAssumeCapacity(reloc); | |
| 693 | } | |
| 694 | 652 | |
| 695 | // Personality function | |
| 696 | if (rec.getPersonality(macho_file)) |sym| { | |
| 697 | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; | |
| 698 | var reloc = addReloc(offset + 16, macho_file.getTarget().cpu.arch); | |
| 699 | reloc.r_symbolnum = r_symbolnum; | |
| 700 | reloc.r_extern = 1; | |
| 701 | relocs.appendAssumeCapacity(reloc); | |
| 702 | } | |
| 703 | ||
| 704 | // LSDA address | |
| 705 | if (rec.getLsdaAtom(macho_file)) |atom| { | |
| 706 | const addr = rec.getLsdaAddress(macho_file); | |
| 707 | out.lsda = addr; | |
| 708 | var reloc = addReloc(offset + 24, macho_file.getTarget().cpu.arch); | |
| 709 | reloc.r_symbolnum = atom.out_n_sect + 1; | |
| 710 | relocs.appendAssumeCapacity(reloc); | |
| 711 | } | |
| 653 | if (macho_file.eh_frame_sect_index) |_| { | |
| 654 | try writeEhFrame(macho_file); | |
| 655 | } | |
| 712 | 656 | |
| 713 | entries.appendAssumeCapacity(out); | |
| 714 | offset += @sizeOf(macho.compact_unwind_entry); | |
| 657 | if (macho_file.unwind_info_sect_index) |_| { | |
| 658 | for (macho_file.objects.items) |index| { | |
| 659 | try macho_file.getFile(index).?.object.writeCompactUnwindRelocatable(macho_file); | |
| 715 | 660 | } |
| 716 | 661 | } |
| 717 | ||
| 718 | assert(entries.items.len == nrecs); | |
| 719 | assert(relocs.items.len == header.nreloc); | |
| 720 | ||
| 721 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); | |
| 722 | ||
| 723 | // TODO scattered writes? | |
| 724 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(entries.items), header.offset); | |
| 725 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | |
| 726 | 662 | } |
| 727 | 663 | |
| 728 | 664 | fn writeEhFrame(macho_file: *MachO) !void { |
| 729 | const sect_index = macho_file.eh_frame_sect_index orelse return; | |
| 730 | const gpa = macho_file.base.comp.gpa; | |
| 731 | const header = macho_file.sections.items(.header)[sect_index]; | |
| 732 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 733 | ||
| 734 | const code = try gpa.alloc(u8, size); | |
| 735 | defer gpa.free(code); | |
| 736 | ||
| 737 | var relocs = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc); | |
| 738 | defer relocs.deinit(); | |
| 665 | const sect_index = macho_file.eh_frame_sect_index.?; | |
| 666 | const buffer = macho_file.sections.items(.out)[sect_index]; | |
| 667 | const relocs = macho_file.sections.items(.relocs)[sect_index]; | |
| 668 | try eh_frame.writeRelocs(macho_file, buffer.items, relocs.items); | |
| 669 | } | |
| 739 | 670 | |
| 740 | try eh_frame.writeRelocs(macho_file, code, &relocs); | |
| 741 | assert(relocs.items.len == header.nreloc); | |
| 671 | fn writeSectionsToFile(macho_file: *MachO) !void { | |
| 672 | const tracy = trace(@src()); | |
| 673 | defer tracy.end(); | |
| 742 | 674 | |
| 743 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); | |
| 675 | const slice = macho_file.sections.slice(); | |
| 676 | for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, out, relocs| { | |
| 677 | try macho_file.base.file.?.pwriteAll(out.items, header.offset); | |
| 678 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | |
| 679 | } | |
| 744 | 680 | |
| 745 | // TODO scattered writes? | |
| 746 | try macho_file.base.file.?.pwriteAll(code, header.offset); | |
| 747 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | |
| 681 | try macho_file.writeDataInCode(); | |
| 682 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff); | |
| 683 | try macho_file.base.file.?.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff); | |
| 748 | 684 | } |
| 749 | 685 | |
| 750 | 686 | fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { |
src/link/MachO/synthetic.zig+151-204| ... | ... | @@ -18,15 +18,15 @@ pub const ZigGotSection = struct { |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, macho_file: *MachO) !Index { |
| 21 | const comp = macho_file.base.comp; | |
| 22 | const gpa = comp.gpa; | |
| 21 | const gpa = macho_file.base.comp.gpa; | |
| 22 | const zo = macho_file.getZigObject().?; | |
| 23 | 23 | const index = try zig_got.allocateEntry(gpa); |
| 24 | 24 | const entry = &zig_got.entries.items[index]; |
| 25 | 25 | entry.* = sym_index; |
| 26 | const symbol = macho_file.getSymbol(sym_index); | |
| 26 | const symbol = &zo.symbols.items[sym_index]; | |
| 27 | 27 | assert(symbol.flags.needs_zig_got); |
| 28 | 28 | symbol.flags.has_zig_got = true; |
| 29 | try symbol.addExtra(.{ .zig_got = index }, macho_file); | |
| 29 | symbol.addExtra(.{ .zig_got = index }, macho_file); | |
| 30 | 30 | return index; |
| 31 | 31 | } |
| 32 | 32 | |
| ... | ... | @@ -53,9 +53,10 @@ pub const ZigGotSection = struct { |
| 53 | 53 | try macho_file.growSection(macho_file.zig_got_sect_index.?, needed_size); |
| 54 | 54 | zig_got.dirty = false; |
| 55 | 55 | } |
| 56 | const zo = macho_file.getZigObject().?; | |
| 56 | 57 | const off = zig_got.entryOffset(index, macho_file); |
| 57 | 58 | const entry = zig_got.entries.items[index]; |
| 58 | const value = macho_file.getSymbol(entry).getAddress(.{ .stubs = false }, macho_file); | |
| 59 | const value = zo.symbols.items[entry].getAddress(.{ .stubs = false }, macho_file); | |
| 59 | 60 | |
| 60 | 61 | var buf: [8]u8 = undefined; |
| 61 | 62 | std.mem.writeInt(u64, &buf, value, .little); |
| ... | ... | @@ -63,29 +64,14 @@ pub const ZigGotSection = struct { |
| 63 | 64 | } |
| 64 | 65 | |
| 65 | 66 | pub fn writeAll(zig_got: ZigGotSection, macho_file: *MachO, writer: anytype) !void { |
| 67 | const zo = macho_file.getZigObject().?; | |
| 66 | 68 | for (zig_got.entries.items) |entry| { |
| 67 | const symbol = macho_file.getSymbol(entry); | |
| 69 | const symbol = zo.symbols.items[entry]; | |
| 68 | 70 | const value = symbol.address(.{ .stubs = false }, macho_file); |
| 69 | 71 | try writer.writeInt(u64, value, .little); |
| 70 | 72 | } |
| 71 | 73 | } |
| 72 | 74 | |
| 73 | pub fn addDyldRelocs(zig_got: ZigGotSection, macho_file: *MachO) !void { | |
| 74 | const tracy = trace(@src()); | |
| 75 | defer tracy.end(); | |
| 76 | const gpa = macho_file.base.comp.gpa; | |
| 77 | const seg_id = macho_file.sections.items(.segment_id)[macho_file.zig_got_sect_index.?]; | |
| 78 | const seg = macho_file.segments.items[seg_id]; | |
| 79 | ||
| 80 | for (0..zig_got.entries.items.len) |idx| { | |
| 81 | const addr = zig_got.entryAddress(@intCast(idx), macho_file); | |
| 82 | try macho_file.rebase.entries.append(gpa, .{ | |
| 83 | .offset = addr - seg.vmaddr, | |
| 84 | .segment_id = seg_id, | |
| 85 | }); | |
| 86 | } | |
| 87 | } | |
| 88 | ||
| 89 | 75 | const FormatCtx = struct { |
| 90 | 76 | zig_got: ZigGotSection, |
| 91 | 77 | macho_file: *MachO, |
| ... | ... | @@ -103,22 +89,25 @@ pub const ZigGotSection = struct { |
| 103 | 89 | ) !void { |
| 104 | 90 | _ = options; |
| 105 | 91 | _ = unused_fmt_string; |
| 92 | const zig_got = ctx.zig_got; | |
| 93 | const macho_file = ctx.macho_file; | |
| 106 | 94 | try writer.writeAll("__zig_got\n"); |
| 107 | for (ctx.zig_got.entries.items, 0..) |entry, index| { | |
| 108 | const symbol = ctx.macho_file.getSymbol(entry); | |
| 95 | for (zig_got.entries.items, 0..) |entry, index| { | |
| 96 | const zo = macho_file.getZigObject().?; | |
| 97 | const symbol = zo.symbols.items[entry]; | |
| 109 | 98 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 110 | 99 | index, |
| 111 | ctx.zig_got.entryAddress(@intCast(index), ctx.macho_file), | |
| 100 | zig_got.entryAddress(@intCast(index), macho_file), | |
| 112 | 101 | entry, |
| 113 | symbol.getAddress(.{}, ctx.macho_file), | |
| 114 | symbol.getName(ctx.macho_file), | |
| 102 | symbol.getAddress(.{}, macho_file), | |
| 103 | symbol.getName(macho_file), | |
| 115 | 104 | }); |
| 116 | 105 | } |
| 117 | 106 | } |
| 118 | 107 | }; |
| 119 | 108 | |
| 120 | 109 | pub const GotSection = struct { |
| 121 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 110 | symbols: std.ArrayListUnmanaged(MachO.Ref) = .{}, | |
| 122 | 111 | |
| 123 | 112 | pub const Index = u32; |
| 124 | 113 | |
| ... | ... | @@ -126,14 +115,14 @@ pub const GotSection = struct { |
| 126 | 115 | got.symbols.deinit(allocator); |
| 127 | 116 | } |
| 128 | 117 | |
| 129 | pub fn addSymbol(got: *GotSection, sym_index: Symbol.Index, macho_file: *MachO) !void { | |
| 118 | pub fn addSymbol(got: *GotSection, ref: MachO.Ref, macho_file: *MachO) !void { | |
| 130 | 119 | const gpa = macho_file.base.comp.gpa; |
| 131 | 120 | const index = @as(Index, @intCast(got.symbols.items.len)); |
| 132 | 121 | const entry = try got.symbols.addOne(gpa); |
| 133 | entry.* = sym_index; | |
| 134 | const symbol = macho_file.getSymbol(sym_index); | |
| 122 | entry.* = ref; | |
| 123 | const symbol = ref.getSymbol(macho_file).?; | |
| 135 | 124 | symbol.flags.has_got = true; |
| 136 | try symbol.addExtra(.{ .got = index }, macho_file); | |
| 125 | symbol.addExtra(.{ .got = index }, macho_file); | |
| 137 | 126 | } |
| 138 | 127 | |
| 139 | 128 | pub fn getAddress(got: GotSection, index: Index, macho_file: *MachO) u64 { |
| ... | ... | @@ -146,46 +135,11 @@ pub const GotSection = struct { |
| 146 | 135 | return got.symbols.items.len * @sizeOf(u64); |
| 147 | 136 | } |
| 148 | 137 | |
| 149 | pub fn addDyldRelocs(got: GotSection, macho_file: *MachO) !void { | |
| 150 | const tracy = trace(@src()); | |
| 151 | defer tracy.end(); | |
| 152 | const gpa = macho_file.base.comp.gpa; | |
| 153 | const seg_id = macho_file.sections.items(.segment_id)[macho_file.got_sect_index.?]; | |
| 154 | const seg = macho_file.segments.items[seg_id]; | |
| 155 | ||
| 156 | for (got.symbols.items, 0..) |sym_index, idx| { | |
| 157 | const sym = macho_file.getSymbol(sym_index); | |
| 158 | const addr = got.getAddress(@intCast(idx), macho_file); | |
| 159 | const entry = bind.Entry{ | |
| 160 | .target = sym_index, | |
| 161 | .offset = addr - seg.vmaddr, | |
| 162 | .segment_id = seg_id, | |
| 163 | .addend = 0, | |
| 164 | }; | |
| 165 | if (sym.flags.import) { | |
| 166 | try macho_file.bind.entries.append(gpa, entry); | |
| 167 | if (sym.flags.weak) { | |
| 168 | try macho_file.weak_bind.entries.append(gpa, entry); | |
| 169 | } | |
| 170 | } else { | |
| 171 | try macho_file.rebase.entries.append(gpa, .{ | |
| 172 | .offset = addr - seg.vmaddr, | |
| 173 | .segment_id = seg_id, | |
| 174 | }); | |
| 175 | if (sym.flags.weak) { | |
| 176 | try macho_file.weak_bind.entries.append(gpa, entry); | |
| 177 | } else if (sym.flags.interposable) { | |
| 178 | try macho_file.bind.entries.append(gpa, entry); | |
| 179 | } | |
| 180 | } | |
| 181 | } | |
| 182 | } | |
| 183 | ||
| 184 | 138 | pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void { |
| 185 | 139 | const tracy = trace(@src()); |
| 186 | 140 | defer tracy.end(); |
| 187 | for (got.symbols.items) |sym_index| { | |
| 188 | const sym = macho_file.getSymbol(sym_index); | |
| 141 | for (got.symbols.items) |ref| { | |
| 142 | const sym = ref.getSymbol(macho_file).?; | |
| 189 | 143 | const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file); |
| 190 | 144 | try writer.writeInt(u64, value, .little); |
| 191 | 145 | } |
| ... | ... | @@ -208,12 +162,12 @@ pub const GotSection = struct { |
| 208 | 162 | ) !void { |
| 209 | 163 | _ = options; |
| 210 | 164 | _ = unused_fmt_string; |
| 211 | for (ctx.got.symbols.items, 0..) |entry, i| { | |
| 212 | const symbol = ctx.macho_file.getSymbol(entry); | |
| 165 | for (ctx.got.symbols.items, 0..) |ref, i| { | |
| 166 | const symbol = ref.getSymbol(ctx.macho_file).?; | |
| 213 | 167 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 214 | 168 | i, |
| 215 | 169 | symbol.getGotAddress(ctx.macho_file), |
| 216 | entry, | |
| 170 | ref, | |
| 217 | 171 | symbol.getAddress(.{}, ctx.macho_file), |
| 218 | 172 | symbol.getName(ctx.macho_file), |
| 219 | 173 | }); |
| ... | ... | @@ -222,7 +176,7 @@ pub const GotSection = struct { |
| 222 | 176 | }; |
| 223 | 177 | |
| 224 | 178 | pub const StubsSection = struct { |
| 225 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 179 | symbols: std.ArrayListUnmanaged(MachO.Ref) = .{}, | |
| 226 | 180 | |
| 227 | 181 | pub const Index = u32; |
| 228 | 182 | |
| ... | ... | @@ -230,13 +184,13 @@ pub const StubsSection = struct { |
| 230 | 184 | stubs.symbols.deinit(allocator); |
| 231 | 185 | } |
| 232 | 186 | |
| 233 | pub fn addSymbol(stubs: *StubsSection, sym_index: Symbol.Index, macho_file: *MachO) !void { | |
| 187 | pub fn addSymbol(stubs: *StubsSection, ref: MachO.Ref, macho_file: *MachO) !void { | |
| 234 | 188 | const gpa = macho_file.base.comp.gpa; |
| 235 | 189 | const index = @as(Index, @intCast(stubs.symbols.items.len)); |
| 236 | 190 | const entry = try stubs.symbols.addOne(gpa); |
| 237 | entry.* = sym_index; | |
| 238 | const symbol = macho_file.getSymbol(sym_index); | |
| 239 | try symbol.addExtra(.{ .stubs = index }, macho_file); | |
| 191 | entry.* = ref; | |
| 192 | const symbol = ref.getSymbol(macho_file).?; | |
| 193 | symbol.addExtra(.{ .stubs = index }, macho_file); | |
| 240 | 194 | } |
| 241 | 195 | |
| 242 | 196 | pub fn getAddress(stubs: StubsSection, index: Index, macho_file: *MachO) u64 { |
| ... | ... | @@ -256,8 +210,8 @@ pub const StubsSection = struct { |
| 256 | 210 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 257 | 211 | const laptr_sect = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_sect_index.?]; |
| 258 | 212 | |
| 259 | for (stubs.symbols.items, 0..) |sym_index, idx| { | |
| 260 | const sym = macho_file.getSymbol(sym_index); | |
| 213 | for (stubs.symbols.items, 0..) |ref, idx| { | |
| 214 | const sym = ref.getSymbol(macho_file).?; | |
| 261 | 215 | const source = sym.getAddress(.{ .stubs = true }, macho_file); |
| 262 | 216 | const target = laptr_sect.addr + idx * @sizeOf(u64); |
| 263 | 217 | switch (cpu_arch) { |
| ... | ... | @@ -299,12 +253,12 @@ pub const StubsSection = struct { |
| 299 | 253 | ) !void { |
| 300 | 254 | _ = options; |
| 301 | 255 | _ = unused_fmt_string; |
| 302 | for (ctx.stubs.symbols.items, 0..) |entry, i| { | |
| 303 | const symbol = ctx.macho_file.getSymbol(entry); | |
| 256 | for (ctx.stubs.symbols.items, 0..) |ref, i| { | |
| 257 | const symbol = ref.getSymbol(ctx.macho_file).?; | |
| 304 | 258 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 305 | 259 | i, |
| 306 | 260 | symbol.getStubsAddress(ctx.macho_file), |
| 307 | entry, | |
| 261 | ref, | |
| 308 | 262 | symbol.getAddress(.{}, ctx.macho_file), |
| 309 | 263 | symbol.getName(ctx.macho_file), |
| 310 | 264 | }); |
| ... | ... | @@ -335,8 +289,8 @@ pub const StubsHelperSection = struct { |
| 335 | 289 | _ = stubs_helper; |
| 336 | 290 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 337 | 291 | var s: usize = preambleSize(cpu_arch); |
| 338 | for (macho_file.stubs.symbols.items) |sym_index| { | |
| 339 | const sym = macho_file.getSymbol(sym_index); | |
| 292 | for (macho_file.stubs.symbols.items) |ref| { | |
| 293 | const sym = ref.getSymbol(macho_file).?; | |
| 340 | 294 | if (sym.flags.weak) continue; |
| 341 | 295 | s += entrySize(cpu_arch); |
| 342 | 296 | } |
| ... | ... | @@ -355,8 +309,8 @@ pub const StubsHelperSection = struct { |
| 355 | 309 | const entry_size = entrySize(cpu_arch); |
| 356 | 310 | |
| 357 | 311 | var idx: usize = 0; |
| 358 | for (macho_file.stubs.symbols.items) |sym_index| { | |
| 359 | const sym = macho_file.getSymbol(sym_index); | |
| 312 | for (macho_file.stubs.symbols.items) |ref| { | |
| 313 | const sym = ref.getSymbol(macho_file).?; | |
| 360 | 314 | if (sym.flags.weak) continue; |
| 361 | 315 | const offset = macho_file.lazy_bind.offsets.items[idx]; |
| 362 | 316 | const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx); |
| ... | ... | @@ -390,14 +344,15 @@ pub const StubsHelperSection = struct { |
| 390 | 344 | |
| 391 | 345 | fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void { |
| 392 | 346 | _ = stubs_helper; |
| 347 | const obj = macho_file.getInternalObject().?; | |
| 393 | 348 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 394 | 349 | const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?]; |
| 395 | 350 | const dyld_private_addr = target: { |
| 396 | const sym = macho_file.getSymbol(macho_file.dyld_private_index.?); | |
| 351 | const sym = obj.getDyldPrivateRef(macho_file).?.getSymbol(macho_file).?; | |
| 397 | 352 | break :target sym.getAddress(.{}, macho_file); |
| 398 | 353 | }; |
| 399 | 354 | const dyld_stub_binder_addr = target: { |
| 400 | const sym = macho_file.getSymbol(macho_file.dyld_stub_binder_index.?); | |
| 355 | const sym = obj.getDyldStubBinderRef(macho_file).?.getSymbol(macho_file).?; | |
| 401 | 356 | break :target sym.getGotAddress(macho_file); |
| 402 | 357 | }; |
| 403 | 358 | switch (cpu_arch) { |
| ... | ... | @@ -446,49 +401,6 @@ pub const LaSymbolPtrSection = struct { |
| 446 | 401 | return macho_file.stubs.symbols.items.len * @sizeOf(u64); |
| 447 | 402 | } |
| 448 | 403 | |
| 449 | pub fn addDyldRelocs(laptr: LaSymbolPtrSection, macho_file: *MachO) !void { | |
| 450 | const tracy = trace(@src()); | |
| 451 | defer tracy.end(); | |
| 452 | _ = laptr; | |
| 453 | const gpa = macho_file.base.comp.gpa; | |
| 454 | ||
| 455 | const sect = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_sect_index.?]; | |
| 456 | const seg_id = macho_file.sections.items(.segment_id)[macho_file.la_symbol_ptr_sect_index.?]; | |
| 457 | const seg = macho_file.segments.items[seg_id]; | |
| 458 | ||
| 459 | for (macho_file.stubs.symbols.items, 0..) |sym_index, idx| { | |
| 460 | const sym = macho_file.getSymbol(sym_index); | |
| 461 | const addr = sect.addr + idx * @sizeOf(u64); | |
| 462 | const rebase_entry = Rebase.Entry{ | |
| 463 | .offset = addr - seg.vmaddr, | |
| 464 | .segment_id = seg_id, | |
| 465 | }; | |
| 466 | const bind_entry = bind.Entry{ | |
| 467 | .target = sym_index, | |
| 468 | .offset = addr - seg.vmaddr, | |
| 469 | .segment_id = seg_id, | |
| 470 | .addend = 0, | |
| 471 | }; | |
| 472 | if (sym.flags.import) { | |
| 473 | if (sym.flags.weak) { | |
| 474 | try macho_file.bind.entries.append(gpa, bind_entry); | |
| 475 | try macho_file.weak_bind.entries.append(gpa, bind_entry); | |
| 476 | } else { | |
| 477 | try macho_file.lazy_bind.entries.append(gpa, bind_entry); | |
| 478 | try macho_file.rebase.entries.append(gpa, rebase_entry); | |
| 479 | } | |
| 480 | } else { | |
| 481 | if (sym.flags.weak) { | |
| 482 | try macho_file.rebase.entries.append(gpa, rebase_entry); | |
| 483 | try macho_file.weak_bind.entries.append(gpa, bind_entry); | |
| 484 | } else if (sym.flags.interposable) { | |
| 485 | try macho_file.lazy_bind.entries.append(gpa, bind_entry); | |
| 486 | try macho_file.rebase.entries.append(gpa, rebase_entry); | |
| 487 | } | |
| 488 | } | |
| 489 | } | |
| 490 | } | |
| 491 | ||
| 492 | 404 | pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void { |
| 493 | 405 | const tracy = trace(@src()); |
| 494 | 406 | defer tracy.end(); |
| ... | ... | @@ -496,8 +408,8 @@ pub const LaSymbolPtrSection = struct { |
| 496 | 408 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 497 | 409 | const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?]; |
| 498 | 410 | var stub_helper_idx: u32 = 0; |
| 499 | for (macho_file.stubs.symbols.items) |sym_index| { | |
| 500 | const sym = macho_file.getSymbol(sym_index); | |
| 411 | for (macho_file.stubs.symbols.items) |ref| { | |
| 412 | const sym = ref.getSymbol(macho_file).?; | |
| 501 | 413 | if (sym.flags.weak) { |
| 502 | 414 | const value = sym.getAddress(.{ .stubs = false }, macho_file); |
| 503 | 415 | try writer.writeInt(u64, @intCast(value), .little); |
| ... | ... | @@ -512,7 +424,7 @@ pub const LaSymbolPtrSection = struct { |
| 512 | 424 | }; |
| 513 | 425 | |
| 514 | 426 | pub const TlvPtrSection = struct { |
| 515 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 427 | symbols: std.ArrayListUnmanaged(MachO.Ref) = .{}, | |
| 516 | 428 | |
| 517 | 429 | pub const Index = u32; |
| 518 | 430 | |
| ... | ... | @@ -520,13 +432,13 @@ pub const TlvPtrSection = struct { |
| 520 | 432 | tlv.symbols.deinit(allocator); |
| 521 | 433 | } |
| 522 | 434 | |
| 523 | pub fn addSymbol(tlv: *TlvPtrSection, sym_index: Symbol.Index, macho_file: *MachO) !void { | |
| 435 | pub fn addSymbol(tlv: *TlvPtrSection, ref: MachO.Ref, macho_file: *MachO) !void { | |
| 524 | 436 | const gpa = macho_file.base.comp.gpa; |
| 525 | 437 | const index = @as(Index, @intCast(tlv.symbols.items.len)); |
| 526 | 438 | const entry = try tlv.symbols.addOne(gpa); |
| 527 | entry.* = sym_index; | |
| 528 | const symbol = macho_file.getSymbol(sym_index); | |
| 529 | try symbol.addExtra(.{ .tlv_ptr = index }, macho_file); | |
| 439 | entry.* = ref; | |
| 440 | const symbol = ref.getSymbol(macho_file).?; | |
| 441 | symbol.addExtra(.{ .tlv_ptr = index }, macho_file); | |
| 530 | 442 | } |
| 531 | 443 | |
| 532 | 444 | pub fn getAddress(tlv: TlvPtrSection, index: Index, macho_file: *MachO) u64 { |
| ... | ... | @@ -539,47 +451,12 @@ pub const TlvPtrSection = struct { |
| 539 | 451 | return tlv.symbols.items.len * @sizeOf(u64); |
| 540 | 452 | } |
| 541 | 453 | |
| 542 | pub fn addDyldRelocs(tlv: TlvPtrSection, macho_file: *MachO) !void { | |
| 543 | const tracy = trace(@src()); | |
| 544 | defer tracy.end(); | |
| 545 | const gpa = macho_file.base.comp.gpa; | |
| 546 | const seg_id = macho_file.sections.items(.segment_id)[macho_file.tlv_ptr_sect_index.?]; | |
| 547 | const seg = macho_file.segments.items[seg_id]; | |
| 548 | ||
| 549 | for (tlv.symbols.items, 0..) |sym_index, idx| { | |
| 550 | const sym = macho_file.getSymbol(sym_index); | |
| 551 | const addr = tlv.getAddress(@intCast(idx), macho_file); | |
| 552 | const entry = bind.Entry{ | |
| 553 | .target = sym_index, | |
| 554 | .offset = addr - seg.vmaddr, | |
| 555 | .segment_id = seg_id, | |
| 556 | .addend = 0, | |
| 557 | }; | |
| 558 | if (sym.flags.import) { | |
| 559 | try macho_file.bind.entries.append(gpa, entry); | |
| 560 | if (sym.flags.weak) { | |
| 561 | try macho_file.weak_bind.entries.append(gpa, entry); | |
| 562 | } | |
| 563 | } else { | |
| 564 | try macho_file.rebase.entries.append(gpa, .{ | |
| 565 | .offset = addr - seg.vmaddr, | |
| 566 | .segment_id = seg_id, | |
| 567 | }); | |
| 568 | if (sym.flags.weak) { | |
| 569 | try macho_file.weak_bind.entries.append(gpa, entry); | |
| 570 | } else if (sym.flags.interposable) { | |
| 571 | try macho_file.bind.entries.append(gpa, entry); | |
| 572 | } | |
| 573 | } | |
| 574 | } | |
| 575 | } | |
| 576 | ||
| 577 | 454 | pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void { |
| 578 | 455 | const tracy = trace(@src()); |
| 579 | 456 | defer tracy.end(); |
| 580 | 457 | |
| 581 | for (tlv.symbols.items) |sym_index| { | |
| 582 | const sym = macho_file.getSymbol(sym_index); | |
| 458 | for (tlv.symbols.items) |ref| { | |
| 459 | const sym = ref.getSymbol(macho_file).?; | |
| 583 | 460 | if (sym.flags.import) { |
| 584 | 461 | try writer.writeInt(u64, 0, .little); |
| 585 | 462 | } else { |
| ... | ... | @@ -605,12 +482,12 @@ pub const TlvPtrSection = struct { |
| 605 | 482 | ) !void { |
| 606 | 483 | _ = options; |
| 607 | 484 | _ = unused_fmt_string; |
| 608 | for (ctx.tlv.symbols.items, 0..) |entry, i| { | |
| 609 | const symbol = ctx.macho_file.getSymbol(entry); | |
| 485 | for (ctx.tlv.symbols.items, 0..) |ref, i| { | |
| 486 | const symbol = ref.getSymbol(ctx.macho_file).?; | |
| 610 | 487 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 611 | 488 | i, |
| 612 | 489 | symbol.getTlvPtrAddress(ctx.macho_file), |
| 613 | entry, | |
| 490 | ref, | |
| 614 | 491 | symbol.getAddress(.{}, ctx.macho_file), |
| 615 | 492 | symbol.getName(ctx.macho_file), |
| 616 | 493 | }); |
| ... | ... | @@ -619,7 +496,7 @@ pub const TlvPtrSection = struct { |
| 619 | 496 | }; |
| 620 | 497 | |
| 621 | 498 | pub const ObjcStubsSection = struct { |
| 622 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 499 | symbols: std.ArrayListUnmanaged(MachO.Ref) = .{}, | |
| 623 | 500 | |
| 624 | 501 | pub fn deinit(objc: *ObjcStubsSection, allocator: Allocator) void { |
| 625 | 502 | objc.symbols.deinit(allocator); |
| ... | ... | @@ -633,13 +510,13 @@ pub const ObjcStubsSection = struct { |
| 633 | 510 | }; |
| 634 | 511 | } |
| 635 | 512 | |
| 636 | pub fn addSymbol(objc: *ObjcStubsSection, sym_index: Symbol.Index, macho_file: *MachO) !void { | |
| 513 | pub fn addSymbol(objc: *ObjcStubsSection, ref: MachO.Ref, macho_file: *MachO) !void { | |
| 637 | 514 | const gpa = macho_file.base.comp.gpa; |
| 638 | 515 | const index = @as(Index, @intCast(objc.symbols.items.len)); |
| 639 | 516 | const entry = try objc.symbols.addOne(gpa); |
| 640 | entry.* = sym_index; | |
| 641 | const symbol = macho_file.getSymbol(sym_index); | |
| 642 | try symbol.addExtra(.{ .objc_stubs = index }, macho_file); | |
| 517 | entry.* = ref; | |
| 518 | const symbol = ref.getSymbol(macho_file).?; | |
| 519 | symbol.addExtra(.{ .objc_stubs = index }, macho_file); | |
| 643 | 520 | } |
| 644 | 521 | |
| 645 | 522 | pub fn getAddress(objc: ObjcStubsSection, index: Index, macho_file: *MachO) u64 { |
| ... | ... | @@ -656,8 +533,10 @@ pub const ObjcStubsSection = struct { |
| 656 | 533 | const tracy = trace(@src()); |
| 657 | 534 | defer tracy.end(); |
| 658 | 535 | |
| 659 | for (objc.symbols.items, 0..) |sym_index, idx| { | |
| 660 | const sym = macho_file.getSymbol(sym_index); | |
| 536 | const obj = macho_file.getInternalObject().?; | |
| 537 | ||
| 538 | for (objc.symbols.items, 0..) |ref, idx| { | |
| 539 | const sym = ref.getSymbol(macho_file).?; | |
| 661 | 540 | const addr = objc.getAddress(@intCast(idx), macho_file); |
| 662 | 541 | switch (macho_file.getTarget().cpu.arch) { |
| 663 | 542 | .x86_64 => { |
| ... | ... | @@ -669,7 +548,7 @@ pub const ObjcStubsSection = struct { |
| 669 | 548 | } |
| 670 | 549 | try writer.writeAll(&.{ 0xff, 0x25 }); |
| 671 | 550 | { |
| 672 | const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?); | |
| 551 | const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?; | |
| 673 | 552 | const target = target_sym.getGotAddress(macho_file); |
| 674 | 553 | const source = addr + 7; |
| 675 | 554 | try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); |
| ... | ... | @@ -689,7 +568,7 @@ pub const ObjcStubsSection = struct { |
| 689 | 568 | ); |
| 690 | 569 | } |
| 691 | 570 | { |
| 692 | const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?); | |
| 571 | const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?; | |
| 693 | 572 | const target = target_sym.getGotAddress(macho_file); |
| 694 | 573 | const source = addr + 2 * @sizeOf(u32); |
| 695 | 574 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| ... | ... | @@ -728,12 +607,12 @@ pub const ObjcStubsSection = struct { |
| 728 | 607 | ) !void { |
| 729 | 608 | _ = options; |
| 730 | 609 | _ = unused_fmt_string; |
| 731 | for (ctx.objc.symbols.items, 0..) |entry, i| { | |
| 732 | const symbol = ctx.macho_file.getSymbol(entry); | |
| 610 | for (ctx.objc.symbols.items, 0..) |ref, i| { | |
| 611 | const symbol = ref.getSymbol(ctx.macho_file).?; | |
| 733 | 612 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 734 | 613 | i, |
| 735 | 614 | symbol.getObjcStubsAddress(ctx.macho_file), |
| 736 | entry, | |
| 615 | ref, | |
| 737 | 616 | symbol.getAddress(.{}, ctx.macho_file), |
| 738 | 617 | symbol.getName(ctx.macho_file), |
| 739 | 618 | }); |
| ... | ... | @@ -749,44 +628,112 @@ pub const Indsymtab = struct { |
| 749 | 628 | return @intCast(macho_file.stubs.symbols.items.len * 2 + macho_file.got.symbols.items.len); |
| 750 | 629 | } |
| 751 | 630 | |
| 631 | pub fn updateSize(ind: *Indsymtab, macho_file: *MachO) !void { | |
| 632 | macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file); | |
| 633 | } | |
| 634 | ||
| 752 | 635 | pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void { |
| 753 | 636 | const tracy = trace(@src()); |
| 754 | 637 | defer tracy.end(); |
| 755 | 638 | |
| 756 | 639 | _ = ind; |
| 757 | 640 | |
| 758 | for (macho_file.stubs.symbols.items) |sym_index| { | |
| 759 | const sym = macho_file.getSymbol(sym_index); | |
| 641 | for (macho_file.stubs.symbols.items) |ref| { | |
| 642 | const sym = ref.getSymbol(macho_file).?; | |
| 760 | 643 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); |
| 761 | 644 | } |
| 762 | 645 | |
| 763 | for (macho_file.got.symbols.items) |sym_index| { | |
| 764 | const sym = macho_file.getSymbol(sym_index); | |
| 646 | for (macho_file.got.symbols.items) |ref| { | |
| 647 | const sym = ref.getSymbol(macho_file).?; | |
| 765 | 648 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); |
| 766 | 649 | } |
| 767 | 650 | |
| 768 | for (macho_file.stubs.symbols.items) |sym_index| { | |
| 769 | const sym = macho_file.getSymbol(sym_index); | |
| 651 | for (macho_file.stubs.symbols.items) |ref| { | |
| 652 | const sym = ref.getSymbol(macho_file).?; | |
| 770 | 653 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); |
| 771 | 654 | } |
| 772 | 655 | } |
| 773 | 656 | }; |
| 774 | 657 | |
| 775 | pub const RebaseSection = Rebase; | |
| 776 | pub const BindSection = bind.Bind; | |
| 777 | pub const WeakBindSection = bind.WeakBind; | |
| 778 | pub const LazyBindSection = bind.LazyBind; | |
| 779 | pub const ExportTrieSection = Trie; | |
| 658 | pub const DataInCode = struct { | |
| 659 | entries: std.ArrayListUnmanaged(Entry) = .{}, | |
| 660 | ||
| 661 | pub fn deinit(dice: *DataInCode, allocator: Allocator) void { | |
| 662 | dice.entries.deinit(allocator); | |
| 663 | } | |
| 664 | ||
| 665 | pub fn size(dice: DataInCode) usize { | |
| 666 | return dice.entries.items.len * @sizeOf(macho.data_in_code_entry); | |
| 667 | } | |
| 668 | ||
| 669 | pub fn updateSize(dice: *DataInCode, macho_file: *MachO) !void { | |
| 670 | const gpa = macho_file.base.comp.gpa; | |
| 671 | ||
| 672 | for (macho_file.objects.items) |index| { | |
| 673 | const object = macho_file.getFile(index).?.object; | |
| 674 | const dices = object.getDataInCode(); | |
| 675 | ||
| 676 | try dice.entries.ensureUnusedCapacity(gpa, dices.len); | |
| 677 | ||
| 678 | var next_dice: usize = 0; | |
| 679 | for (object.getAtoms()) |atom_index| { | |
| 680 | if (next_dice >= dices.len) break; | |
| 681 | const atom = object.getAtom(atom_index) orelse continue; | |
| 682 | const start_off = atom.getInputAddress(macho_file); | |
| 683 | const end_off = start_off + atom.size; | |
| 684 | const start_dice = next_dice; | |
| 685 | ||
| 686 | if (end_off < dices[next_dice].offset) continue; | |
| 687 | ||
| 688 | while (next_dice < dices.len and | |
| 689 | dices[next_dice].offset < end_off) : (next_dice += 1) | |
| 690 | {} | |
| 691 | ||
| 692 | if (atom.flags.alive) for (dices[start_dice..next_dice]) |d| { | |
| 693 | dice.entries.appendAssumeCapacity(.{ | |
| 694 | .atom_ref = .{ .index = atom_index, .file = index }, | |
| 695 | .offset = @intCast(d.offset - start_off), | |
| 696 | .length = d.length, | |
| 697 | .kind = d.kind, | |
| 698 | }); | |
| 699 | }; | |
| 700 | } | |
| 701 | } | |
| 702 | ||
| 703 | macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow; | |
| 704 | } | |
| 705 | ||
| 706 | pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void { | |
| 707 | const base_address = if (!macho_file.base.isRelocatable()) | |
| 708 | macho_file.getTextSegment().vmaddr | |
| 709 | else | |
| 710 | 0; | |
| 711 | for (dice.entries.items) |entry| { | |
| 712 | const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file); | |
| 713 | const offset = atom_address + entry.offset - base_address; | |
| 714 | try writer.writeStruct(macho.data_in_code_entry{ | |
| 715 | .offset = @intCast(offset), | |
| 716 | .length = entry.length, | |
| 717 | .kind = entry.kind, | |
| 718 | }); | |
| 719 | } | |
| 720 | } | |
| 721 | ||
| 722 | const Entry = struct { | |
| 723 | atom_ref: MachO.Ref, | |
| 724 | offset: u32, | |
| 725 | length: u16, | |
| 726 | kind: u16, | |
| 727 | }; | |
| 728 | }; | |
| 780 | 729 | |
| 781 | 730 | const aarch64 = @import("../aarch64.zig"); |
| 782 | 731 | const assert = std.debug.assert; |
| 783 | const bind = @import("dyld_info/bind.zig"); | |
| 732 | const macho = std.macho; | |
| 784 | 733 | const math = std.math; |
| 785 | 734 | const std = @import("std"); |
| 786 | 735 | const trace = @import("../../tracy.zig").trace; |
| 787 | 736 | |
| 788 | 737 | const Allocator = std.mem.Allocator; |
| 789 | 738 | const MachO = @import("../MachO.zig"); |
| 790 | const Rebase = @import("dyld_info/Rebase.zig"); | |
| 791 | 739 | const Symbol = @import("Symbol.zig"); |
| 792 | const Trie = @import("dyld_info/Trie.zig"); |
src/link/MachO/thunks.zig+40-32| ... | ... | @@ -5,55 +5,45 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void { |
| 5 | 5 | const gpa = macho_file.base.comp.gpa; |
| 6 | 6 | const slice = macho_file.sections.slice(); |
| 7 | 7 | const header = &slice.items(.header)[sect_id]; |
| 8 | const thnks = &slice.items(.thunks)[sect_id]; | |
| 8 | 9 | const atoms = slice.items(.atoms)[sect_id].items; |
| 9 | 10 | assert(atoms.len > 0); |
| 10 | 11 | |
| 11 | for (atoms) |atom_index| { | |
| 12 | macho_file.getAtom(atom_index).?.value = @bitCast(@as(i64, -1)); | |
| 12 | for (atoms) |ref| { | |
| 13 | ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1)); | |
| 13 | 14 | } |
| 14 | 15 | |
| 15 | 16 | var i: usize = 0; |
| 16 | 17 | while (i < atoms.len) { |
| 17 | 18 | const start = i; |
| 18 | const start_atom = macho_file.getAtom(atoms[start]).?; | |
| 19 | const start_atom = atoms[start].getAtom(macho_file).?; | |
| 19 | 20 | assert(start_atom.flags.alive); |
| 20 | start_atom.value = try advance(header, start_atom.size, start_atom.alignment); | |
| 21 | start_atom.value = advance(header, start_atom.size, start_atom.alignment); | |
| 21 | 22 | i += 1; |
| 22 | 23 | |
| 23 | 24 | while (i < atoms.len and |
| 24 | 25 | header.size - start_atom.value < max_allowed_distance) : (i += 1) |
| 25 | 26 | { |
| 26 | const atom_index = atoms[i]; | |
| 27 | const atom = macho_file.getAtom(atom_index).?; | |
| 27 | const atom = atoms[i].getAtom(macho_file).?; | |
| 28 | 28 | assert(atom.flags.alive); |
| 29 | atom.value = try advance(header, atom.size, atom.alignment); | |
| 29 | atom.value = advance(header, atom.size, atom.alignment); | |
| 30 | 30 | } |
| 31 | 31 | |
| 32 | 32 | // Insert a thunk at the group end |
| 33 | 33 | const thunk_index = try macho_file.addThunk(); |
| 34 | 34 | const thunk = macho_file.getThunk(thunk_index); |
| 35 | 35 | thunk.out_n_sect = sect_id; |
| 36 | try thnks.append(gpa, thunk_index); | |
| 36 | 37 | |
| 37 | 38 | // Scan relocs in the group and create trampolines for any unreachable callsite |
| 38 | for (atoms[start..i]) |atom_index| { | |
| 39 | const atom = macho_file.getAtom(atom_index).?; | |
| 40 | log.debug("atom({d}) {s}", .{ atom_index, atom.getName(macho_file) }); | |
| 41 | for (atom.getRelocs(macho_file)) |rel| { | |
| 42 | if (rel.type != .branch) continue; | |
| 43 | if (isReachable(atom, rel, macho_file)) continue; | |
| 44 | try thunk.symbols.put(gpa, rel.target, {}); | |
| 45 | } | |
| 46 | try atom.addExtra(.{ .thunk = thunk_index }, macho_file); | |
| 47 | atom.flags.thunk = true; | |
| 48 | } | |
| 49 | ||
| 50 | thunk.value = try advance(header, thunk.size(), .@"4"); | |
| 39 | try scanRelocs(thunk_index, gpa, atoms[start..i], macho_file); | |
| 40 | thunk.value = advance(header, thunk.size(), .@"4"); | |
| 51 | 41 | |
| 52 | 42 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) }); |
| 53 | 43 | } |
| 54 | 44 | } |
| 55 | 45 | |
| 56 | fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 { | |
| 46 | fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) u64 { | |
| 57 | 47 | const offset = alignment.forward(sect.size); |
| 58 | 48 | const padding = offset - sect.size; |
| 59 | 49 | sect.size += padding + size; |
| ... | ... | @@ -61,14 +51,32 @@ fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 { |
| 61 | 51 | return offset; |
| 62 | 52 | } |
| 63 | 53 | |
| 54 | fn scanRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref, macho_file: *MachO) !void { | |
| 55 | const tracy = trace(@src()); | |
| 56 | defer tracy.end(); | |
| 57 | ||
| 58 | const thunk = macho_file.getThunk(thunk_index); | |
| 59 | ||
| 60 | for (atoms) |ref| { | |
| 61 | const atom = ref.getAtom(macho_file).?; | |
| 62 | log.debug("atom({d}) {s}", .{ atom.atom_index, atom.getName(macho_file) }); | |
| 63 | for (atom.getRelocs(macho_file)) |rel| { | |
| 64 | if (rel.type != .branch) continue; | |
| 65 | if (isReachable(atom, rel, macho_file)) continue; | |
| 66 | try thunk.symbols.put(gpa, rel.getTargetSymbolRef(atom.*, macho_file), {}); | |
| 67 | } | |
| 68 | atom.addExtra(.{ .thunk = thunk_index }, macho_file); | |
| 69 | } | |
| 70 | } | |
| 71 | ||
| 64 | 72 | fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { |
| 65 | const target = rel.getTargetSymbol(macho_file); | |
| 73 | const target = rel.getTargetSymbol(atom.*, macho_file); | |
| 66 | 74 | if (target.flags.stubs or target.flags.objc_stubs) return false; |
| 67 | if (atom.out_n_sect != target.out_n_sect) return false; | |
| 75 | if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false; | |
| 68 | 76 | const target_atom = target.getAtom(macho_file).?; |
| 69 | 77 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; |
| 70 | 78 | const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off)); |
| 71 | const taddr: i64 = @intCast(rel.getTargetAddress(macho_file)); | |
| 79 | const taddr: i64 = @intCast(rel.getTargetAddress(atom.*, macho_file)); | |
| 72 | 80 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; |
| 73 | 81 | return true; |
| 74 | 82 | } |
| ... | ... | @@ -76,7 +84,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { |
| 76 | 84 | pub const Thunk = struct { |
| 77 | 85 | value: u64 = 0, |
| 78 | 86 | out_n_sect: u8 = 0, |
| 79 | symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, | |
| 87 | symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{}, | |
| 80 | 88 | |
| 81 | 89 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { |
| 82 | 90 | thunk.symbols.deinit(allocator); |
| ... | ... | @@ -91,13 +99,13 @@ pub const Thunk = struct { |
| 91 | 99 | return header.addr + thunk.value; |
| 92 | 100 | } |
| 93 | 101 | |
| 94 | pub fn getTargetAddress(thunk: Thunk, sym_index: Symbol.Index, macho_file: *MachO) u64 { | |
| 95 | return thunk.getAddress(macho_file) + thunk.symbols.getIndex(sym_index).? * trampoline_size; | |
| 102 | pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { | |
| 103 | return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size; | |
| 96 | 104 | } |
| 97 | 105 | |
| 98 | 106 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { |
| 99 | for (thunk.symbols.keys(), 0..) |sym_index, i| { | |
| 100 | const sym = macho_file.getSymbol(sym_index); | |
| 107 | for (thunk.symbols.keys(), 0..) |ref, i| { | |
| 108 | const sym = ref.getSymbol(macho_file).?; | |
| 101 | 109 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; |
| 102 | 110 | const taddr = sym.getAddress(.{}, macho_file); |
| 103 | 111 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); |
| ... | ... | @@ -144,9 +152,9 @@ pub const Thunk = struct { |
| 144 | 152 | const thunk = ctx.thunk; |
| 145 | 153 | const macho_file = ctx.macho_file; |
| 146 | 154 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); |
| 147 | for (thunk.symbols.keys()) |index| { | |
| 148 | const sym = macho_file.getSymbol(index); | |
| 149 | try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.getName(macho_file), sym.value }); | |
| 155 | for (thunk.symbols.keys()) |ref| { | |
| 156 | const sym = ref.getSymbol(macho_file).?; | |
| 157 | try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value }); | |
| 150 | 158 | } |
| 151 | 159 | } |
| 152 | 160 |
test/link/link.zig+2-1| ... | ... | @@ -74,8 +74,9 @@ fn addCompileStep( |
| 74 | 74 | .target = base.target, |
| 75 | 75 | .optimize = base.optimize, |
| 76 | 76 | .root_source_file = rsf: { |
| 77 | const name = b.fmt("{s}.zig", .{overlay.name}); | |
| 77 | 78 | const bytes = overlay.zig_source_bytes orelse break :rsf null; |
| 78 | break :rsf b.addWriteFiles().add("a.zig", bytes); | |
| 79 | break :rsf b.addWriteFiles().add(name, bytes); | |
| 79 | 80 | }, |
| 80 | 81 | .pic = overlay.pic, |
| 81 | 82 | .strip = if (base.strip) |s| s else overlay.strip, |
test/link/macho.zig+99-1| ... | ... | @@ -25,9 +25,12 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 25 | 25 | macho_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = x86_64_target })); |
| 26 | 26 | macho_step.dependOn(testReexportsZig(b, .{ .use_llvm = false, .target = x86_64_target })); |
| 27 | 27 | macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .target = x86_64_target })); |
| 28 | macho_step.dependOn(testTlsZig(b, .{ .use_llvm = false, .target = x86_64_target })); | |
| 29 | macho_step.dependOn(testUnresolvedError(b, .{ .use_llvm = false, .target = x86_64_target })); | |
| 28 | 30 | |
| 29 | 31 | // Exercise linker with LLVM backend |
| 30 | 32 | macho_step.dependOn(testDeadStrip(b, .{ .target = default_target })); |
| 33 | macho_step.dependOn(testDuplicateDefinitions(b, .{ .target = default_target })); | |
| 31 | 34 | macho_step.dependOn(testEmptyObject(b, .{ .target = default_target })); |
| 32 | 35 | macho_step.dependOn(testEmptyZig(b, .{ .target = default_target })); |
| 33 | 36 | macho_step.dependOn(testEntryPoint(b, .{ .target = default_target })); |
| ... | ... | @@ -56,7 +59,9 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 56 | 59 | macho_step.dependOn(testTentative(b, .{ .target = default_target })); |
| 57 | 60 | macho_step.dependOn(testThunks(b, .{ .target = aarch64_target })); |
| 58 | 61 | macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target })); |
| 62 | macho_step.dependOn(testTlsZig(b, .{ .target = default_target })); | |
| 59 | 63 | macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target })); |
| 64 | macho_step.dependOn(testUnresolvedError(b, .{ .target = default_target })); | |
| 60 | 65 | macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target })); |
| 61 | 66 | macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target })); |
| 62 | 67 | macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target })); |
| ... | ... | @@ -178,6 +183,37 @@ fn testDeadStrip(b: *Build, opts: Options) *Step { |
| 178 | 183 | return test_step; |
| 179 | 184 | } |
| 180 | 185 | |
| 186 | fn testDuplicateDefinitions(b: *Build, opts: Options) *Step { | |
| 187 | const test_step = addTestStep(b, "duplicate-definitions", opts); | |
| 188 | ||
| 189 | const obj = addObject(b, opts, .{ .name = "a", .zig_source_bytes = | |
| 190 | \\var x: usize = 1; | |
| 191 | \\export fn strong() void { x += 1; } | |
| 192 | \\export fn weak() void { x += 1; } | |
| 193 | }); | |
| 194 | ||
| 195 | const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = | |
| 196 | \\var x: usize = 1; | |
| 197 | \\export fn strong() void { x += 1; } | |
| 198 | \\comptime { @export(weakImpl, .{ .name = "weak", .linkage = .weak }); } | |
| 199 | \\fn weakImpl() callconv(.C) void { x += 1; } | |
| 200 | \\extern fn weak() void; | |
| 201 | \\pub fn main() void { | |
| 202 | \\ weak(); | |
| 203 | \\ strong(); | |
| 204 | \\} | |
| 205 | }); | |
| 206 | exe.addObject(obj); | |
| 207 | ||
| 208 | expectLinkErrors(exe, test_step, .{ .exact = &.{ | |
| 209 | "error: duplicate symbol definition: _strong", | |
| 210 | "note: defined by /?/a.o", | |
| 211 | "note: defined by /?/main.o", | |
| 212 | } }); | |
| 213 | ||
| 214 | return test_step; | |
| 215 | } | |
| 216 | ||
| 181 | 217 | fn testDeadStripDylibs(b: *Build, opts: Options) *Step { |
| 182 | 218 | const test_step = addTestStep(b, "dead-strip-dylibs", opts); |
| 183 | 219 | |
| ... | ... | @@ -912,7 +948,7 @@ fn testLinksection(b: *Build, opts: Options) *Step { |
| 912 | 948 | |
| 913 | 949 | if (opts.optimize == .Debug) { |
| 914 | 950 | check.checkInSymtab(); |
| 915 | check.checkContains("(__TEXT,__TestGenFnA) _a.testGenericFn__anon_"); | |
| 951 | check.checkContains("(__TEXT,__TestGenFnA) _main.testGenericFn__anon_"); | |
| 916 | 952 | } |
| 917 | 953 | |
| 918 | 954 | test_step.dependOn(&check.step); |
| ... | ... | @@ -2274,6 +2310,32 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { |
| 2274 | 2310 | return test_step; |
| 2275 | 2311 | } |
| 2276 | 2312 | |
| 2313 | fn testTlsZig(b: *Build, opts: Options) *Step { | |
| 2314 | const test_step = addTestStep(b, "tls-zig", opts); | |
| 2315 | ||
| 2316 | const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = | |
| 2317 | \\const std = @import("std"); | |
| 2318 | \\threadlocal var x: i32 = 0; | |
| 2319 | \\threadlocal var y: i32 = -1; | |
| 2320 | \\pub fn main() void { | |
| 2321 | \\ std.io.getStdOut().writer().print("{d} {d}\n", .{x, y}) catch unreachable; | |
| 2322 | \\ x -= 1; | |
| 2323 | \\ y += 1; | |
| 2324 | \\ std.io.getStdOut().writer().print("{d} {d}\n", .{x, y}) catch unreachable; | |
| 2325 | \\} | |
| 2326 | }); | |
| 2327 | ||
| 2328 | const run = addRunArtifact(exe); | |
| 2329 | run.expectStdOutEqual( | |
| 2330 | \\0 -1 | |
| 2331 | \\-1 0 | |
| 2332 | \\ | |
| 2333 | ); | |
| 2334 | test_step.dependOn(&run.step); | |
| 2335 | ||
| 2336 | return test_step; | |
| 2337 | } | |
| 2338 | ||
| 2277 | 2339 | fn testTwoLevelNamespace(b: *Build, opts: Options) *Step { |
| 2278 | 2340 | const test_step = addTestStep(b, "two-level-namespace", opts); |
| 2279 | 2341 | |
| ... | ... | @@ -2471,6 +2533,42 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { |
| 2471 | 2533 | return test_step; |
| 2472 | 2534 | } |
| 2473 | 2535 | |
| 2536 | fn testUnresolvedError(b: *Build, opts: Options) *Step { | |
| 2537 | const test_step = addTestStep(b, "unresolved-error", opts); | |
| 2538 | ||
| 2539 | const obj = addObject(b, opts, .{ .name = "a", .zig_source_bytes = | |
| 2540 | \\extern fn foo() i32; | |
| 2541 | \\export fn bar() i32 { return foo() + 1; } | |
| 2542 | }); | |
| 2543 | ||
| 2544 | const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = | |
| 2545 | \\const std = @import("std"); | |
| 2546 | \\extern fn foo() i32; | |
| 2547 | \\extern fn bar() i32; | |
| 2548 | \\pub fn main() void { | |
| 2549 | \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()}); | |
| 2550 | \\} | |
| 2551 | }); | |
| 2552 | exe.addObject(obj); | |
| 2553 | ||
| 2554 | // TODO order should match across backends if possible | |
| 2555 | if (opts.use_llvm) { | |
| 2556 | expectLinkErrors(exe, test_step, .{ .exact = &.{ | |
| 2557 | "error: undefined symbol: _foo", | |
| 2558 | "note: referenced by /?/a.o:_bar", | |
| 2559 | "note: referenced by /?/main.o:_main.main", | |
| 2560 | } }); | |
| 2561 | } else { | |
| 2562 | expectLinkErrors(exe, test_step, .{ .exact = &.{ | |
| 2563 | "error: undefined symbol: _foo", | |
| 2564 | "note: referenced by /?/main.o:_main.main", | |
| 2565 | "note: referenced by /?/a.o:__TEXT$__text_zig", | |
| 2566 | } }); | |
| 2567 | } | |
| 2568 | ||
| 2569 | return test_step; | |
| 2570 | } | |
| 2571 | ||
| 2474 | 2572 | fn testUnwindInfo(b: *Build, opts: Options) *Step { |
| 2475 | 2573 | const test_step = addTestStep(b, "unwind-info", opts); |
| 2476 | 2574 |