| 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,7 +620,7 @@ fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.St |
| 620 | .root_source_file = b.path("src/main.zig"), | 620 | .root_source_file = b.path("src/main.zig"), |
| 621 | .target = options.target, | 621 | .target = options.target, |
| 622 | .optimize = options.optimize, | 622 | .optimize = options.optimize, |
| 623 | .max_rss = 7_000_000_000, | 623 | .max_rss = 7_100_000_000, |
| 624 | .strip = options.strip, | 624 | .strip = options.strip, |
| 625 | .sanitize_thread = options.sanitize_thread, | 625 | .sanitize_thread = options.sanitize_thread, |
| 626 | .single_threaded = options.single_threaded, | 626 | .single_threaded = options.single_threaded, |
src/Sema.zig+1-2| ... | @@ -17787,8 +17787,7 @@ fn zirBuiltinSrc( | ... | @@ -17787,8 +17787,7 @@ fn zirBuiltinSrc( |
| 17787 | }; | 17787 | }; |
| 17788 | 17788 | ||
| 17789 | const file_name_val = v: { | 17789 | const file_name_val = v: { |
| 17790 | // The compiler must not call realpath anywhere. | 17790 | const file_name = fn_owner_decl.getFileScope(mod).sub_file_path; |
| 17791 | const file_name = try fn_owner_decl.getFileScope(mod).fullPath(sema.arena); | ||
| 17792 | const array_ty = try pt.intern(.{ .array_type = .{ | 17791 | const array_ty = try pt.intern(.{ .array_type = .{ |
| 17793 | .len = file_name.len, | 17792 | .len = file_name.len, |
| 17794 | .sentinel = .zero_u8, | 17793 | .sentinel = .zero_u8, |
src/arch/x86_64/CodeGen.zig+6-4| ... | @@ -12362,8 +12362,9 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -12362,8 +12362,9 @@ fn genCall(self: *Self, info: union(enum) { |
| 12362 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }, .{}); | 12362 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }, .{}); |
| 12363 | try self.asmRegister(.{ ._, .call }, .rax); | 12363 | try self.asmRegister(.{ ._, .call }, .rax); |
| 12364 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 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); | 12365 | const zo = macho_file.getZigObject().?; |
| 12366 | const sym = macho_file.getSymbol(sym_index); | 12366 | const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, func.owner_decl); |
| 12367 | const sym = zo.symbols.items[sym_index]; | ||
| 12367 | try self.genSetReg( | 12368 | try self.genSetReg( |
| 12368 | .rax, | 12369 | .rax, |
| 12369 | Type.usize, | 12370 | Type.usize, |
| ... | @@ -15396,9 +15397,10 @@ fn genLazySymbolRef( | ... | @@ -15396,9 +15397,10 @@ fn genLazySymbolRef( |
| 15396 | else => unreachable, | 15397 | else => unreachable, |
| 15397 | } | 15398 | } |
| 15398 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 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 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); | 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 | switch (tag) { | 15404 | switch (tag) { |
| 15403 | .lea, .call => try self.genSetReg( | 15405 | .lea, .call => try self.genSetReg( |
| 15404 | reg, | 15406 | reg, |
src/arch/x86_64/Emit.zig+8-8| ... | @@ -51,12 +51,12 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -51,12 +51,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 51 | }); | 51 | }); |
| 52 | } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| { | 52 | } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| { |
| 53 | // Add relocation to the decl. | 53 | // Add relocation to the decl. |
| 54 | const atom = macho_file.getSymbol(symbol.atom_index).getAtom(macho_file).?; | 54 | const zo = macho_file.getZigObject().?; |
| 55 | const sym_index = macho_file.getZigObject().?.symbols.items[symbol.sym_index]; | 55 | const atom = zo.symbols.items[symbol.atom_index].getAtom(macho_file).?; |
| 56 | try atom.addReloc(macho_file, .{ | 56 | try atom.addReloc(macho_file, .{ |
| 57 | .tag = .@"extern", | 57 | .tag = .@"extern", |
| 58 | .offset = end_offset - 4, | 58 | .offset = end_offset - 4, |
| 59 | .target = sym_index, | 59 | .target = symbol.sym_index, |
| 60 | .addend = 0, | 60 | .addend = 0, |
| 61 | .type = .branch, | 61 | .type = .branch, |
| 62 | .meta = .{ | 62 | .meta = .{ |
| ... | @@ -160,11 +160,11 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -160,11 +160,11 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 160 | .Obj => true, | 160 | .Obj => true, |
| 161 | .Lib => emit.lower.link_mode == .static, | 161 | .Lib => emit.lower.link_mode == .static, |
| 162 | }; | 162 | }; |
| 163 | const atom = macho_file.getSymbol(data.atom_index).getAtom(macho_file).?; | 163 | const zo = macho_file.getZigObject().?; |
| 164 | const sym_index = macho_file.getZigObject().?.symbols.items[data.sym_index]; | 164 | const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?; |
| 165 | const sym = macho_file.getSymbol(sym_index); | 165 | const sym = &zo.symbols.items[data.sym_index]; |
| 166 | if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { | 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 | const @"type": link.File.MachO.Relocation.Type = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) | 169 | const @"type": link.File.MachO.Relocation.Type = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) |
| 170 | .zig_got_load | 170 | .zig_got_load |
| ... | @@ -179,7 +179,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -179,7 +179,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 179 | try atom.addReloc(macho_file, .{ | 179 | try atom.addReloc(macho_file, .{ |
| 180 | .tag = .@"extern", | 180 | .tag = .@"extern", |
| 181 | .offset = @intCast(end_offset - 4), | 181 | .offset = @intCast(end_offset - 4), |
| 182 | .target = sym_index, | 182 | .target = data.sym_index, |
| 183 | .addend = 0, | 183 | .addend = 0, |
| 184 | .type = @"type", | 184 | .type = @"type", |
| 185 | .meta = .{ | 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,8 +425,8 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 425 | else => unreachable, | 425 | else => unreachable, |
| 426 | }; | 426 | }; |
| 427 | } else if (lower.bin_file.cast(link.File.MachO)) |macho_file| { | 427 | } else if (lower.bin_file.cast(link.File.MachO)) |macho_file| { |
| 428 | const sym_index = macho_file.getZigObject().?.symbols.items[sym.sym_index]; | 428 | const zo = macho_file.getZigObject().?; |
| 429 | const macho_sym = macho_file.getSymbol(sym_index); | 429 | const macho_sym = zo.symbols.items[sym.sym_index]; |
| 430 | 430 | ||
| 431 | if (macho_sym.flags.tlv) { | 431 | if (macho_sym.flags.tlv) { |
| 432 | _ = lower.reloc(.{ .linker_reloc = sym }); | 432 | _ = lower.reloc(.{ .linker_reloc = sym }); |
src/codegen.zig+5-4| ... | @@ -901,15 +901,16 @@ fn genDeclRef( | ... | @@ -901,15 +901,16 @@ fn genDeclRef( |
| 901 | } | 901 | } |
| 902 | return GenResult.mcv(.{ .load_symbol = sym.esym_index }); | 902 | return GenResult.mcv(.{ .load_symbol = sym.esym_index }); |
| 903 | } else if (lf.cast(link.File.MachO)) |macho_file| { | 903 | } else if (lf.cast(link.File.MachO)) |macho_file| { |
| 904 | const zo = macho_file.getZigObject().?; | ||
| 904 | if (is_extern) { | 905 | if (is_extern) { |
| 905 | const name = decl.name.toSlice(ip); | 906 | const name = decl.name.toSlice(ip); |
| 906 | const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null; | 907 | const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null; |
| 907 | const sym_index = try macho_file.getGlobalSymbol(name, lib_name); | 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 | return GenResult.mcv(.{ .load_symbol = sym_index }); | 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_index = try zo.getOrCreateMetadataForDecl(macho_file, decl_index); |
| 912 | const sym = macho_file.getSymbol(sym_index); | 913 | const sym = zo.symbols.items[sym_index]; |
| 913 | if (is_threadlocal) { | 914 | if (is_threadlocal) { |
| 914 | return GenResult.mcv(.{ .load_tlv = sym.nlist_idx }); | 915 | return GenResult.mcv(.{ .load_tlv = sym.nlist_idx }); |
| 915 | } | 916 | } |
| ... | @@ -956,7 +957,7 @@ fn genUnnamedConst( | ... | @@ -956,7 +957,7 @@ fn genUnnamedConst( |
| 956 | }, | 957 | }, |
| 957 | .macho => { | 958 | .macho => { |
| 958 | const macho_file = lf.cast(link.File.MachO).?; | 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 | return GenResult.mcv(.{ .load_symbol = local.nlist_idx }); | 961 | return GenResult.mcv(.{ .load_symbol = local.nlist_idx }); |
| 961 | }, | 962 | }, |
| 962 | .coff => { | 963 | .coff => { |
src/link/MachO.zig+664-1001| ... | @@ -22,16 +22,11 @@ dylibs: std.ArrayListUnmanaged(File.Index) = .{}, | ... | @@ -22,16 +22,11 @@ dylibs: std.ArrayListUnmanaged(File.Index) = .{}, |
| 22 | segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{}, | 22 | segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{}, |
| 23 | sections: std.MultiArrayList(Section) = .{}, | 23 | sections: std.MultiArrayList(Section) = .{}, |
| 24 | 24 | ||
| 25 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | 25 | resolver: SymbolResolver = .{}, |
| 26 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | ||
| 27 | symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{}, | ||
| 28 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, | ||
| 29 | /// This table will be populated after `scanRelocs` has run. | 26 | /// This table will be populated after `scanRelocs` has run. |
| 30 | /// Key is symbol index. | 27 | /// Key is symbol index. |
| 31 | undefs: std.AutoHashMapUnmanaged(Symbol.Index, std.ArrayListUnmanaged(Atom.Index)) = .{}, | 28 | undefs: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .{}, |
| 32 | /// Global symbols we need to resolve for the link to succeed. | 29 | dupes: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .{}, |
| 33 | undefined_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | ||
| 34 | boundary_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | ||
| 35 | 30 | ||
| 36 | dyld_info_cmd: macho.dyld_info_command = .{}, | 31 | dyld_info_cmd: macho.dyld_info_command = .{}, |
| 37 | symtab_cmd: macho.symtab_command = .{}, | 32 | symtab_cmd: macho.symtab_command = .{}, |
| ... | @@ -55,22 +50,7 @@ eh_frame_sect_index: ?u8 = null, | ... | @@ -55,22 +50,7 @@ eh_frame_sect_index: ?u8 = null, |
| 55 | unwind_info_sect_index: ?u8 = null, | 50 | unwind_info_sect_index: ?u8 = null, |
| 56 | objc_stubs_sect_index: ?u8 = null, | 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 | thunks: std.ArrayListUnmanaged(Thunk) = .{}, | 53 | thunks: std.ArrayListUnmanaged(Thunk) = .{}, |
| 70 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{}, | ||
| 71 | |||
| 72 | /// String interning table | ||
| 73 | strings: StringTable = .{}, | ||
| 74 | 54 | ||
| 75 | /// Output synthetic sections | 55 | /// Output synthetic sections |
| 76 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 56 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | @@ -83,12 +63,13 @@ stubs_helper: StubsHelperSection = .{}, | ... | @@ -83,12 +63,13 @@ stubs_helper: StubsHelperSection = .{}, |
| 83 | objc_stubs: ObjcStubsSection = .{}, | 63 | objc_stubs: ObjcStubsSection = .{}, |
| 84 | la_symbol_ptr: LaSymbolPtrSection = .{}, | 64 | la_symbol_ptr: LaSymbolPtrSection = .{}, |
| 85 | tlv_ptr: TlvPtrSection = .{}, | 65 | tlv_ptr: TlvPtrSection = .{}, |
| 86 | rebase: RebaseSection = .{}, | 66 | rebase: Rebase = .{}, |
| 87 | bind: BindSection = .{}, | 67 | bind: Bind = .{}, |
| 88 | weak_bind: WeakBindSection = .{}, | 68 | weak_bind: WeakBind = .{}, |
| 89 | lazy_bind: LazyBindSection = .{}, | 69 | lazy_bind: LazyBind = .{}, |
| 90 | export_trie: ExportTrieSection = .{}, | 70 | export_trie: ExportTrie = .{}, |
| 91 | unwind_info: UnwindInfo = .{}, | 71 | unwind_info: UnwindInfo = .{}, |
| 72 | data_in_code: DataInCode = .{}, | ||
| 92 | 73 | ||
| 93 | /// Tracked loadable segments during incremental linking. | 74 | /// Tracked loadable segments during incremental linking. |
| 94 | zig_text_seg_index: ?u8 = null, | 75 | zig_text_seg_index: ?u8 = null, |
| ... | @@ -245,15 +226,8 @@ pub fn createEmpty( | ... | @@ -245,15 +226,8 @@ pub fn createEmpty( |
| 245 | 226 | ||
| 246 | // Append null file | 227 | // Append null file |
| 247 | try self.files.append(gpa, .null); | 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 | // Append empty string to string tables | 229 | // Append empty string to string tables |
| 252 | try self.strings.buffer.append(gpa, 0); | ||
| 253 | try self.strtab.append(gpa, 0); | 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 | if (opt_zcu) |zcu| { | 232 | if (opt_zcu) |zcu| { |
| 259 | if (!use_llvm) { | 233 | if (!use_llvm) { |
| ... | @@ -317,15 +291,20 @@ pub fn deinit(self: *MachO) void { | ... | @@ -317,15 +291,20 @@ pub fn deinit(self: *MachO) void { |
| 317 | self.dylibs.deinit(gpa); | 291 | self.dylibs.deinit(gpa); |
| 318 | 292 | ||
| 319 | self.segments.deinit(gpa); | 293 | self.segments.deinit(gpa); |
| 320 | for (self.sections.items(.atoms)) |*list| { | 294 | for ( |
| 321 | list.deinit(gpa); | 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 | self.sections.deinit(gpa); | 305 | self.sections.deinit(gpa); |
| 324 | 306 | ||
| 325 | self.symbols.deinit(gpa); | 307 | self.resolver.deinit(gpa); |
| 326 | self.symbols_extra.deinit(gpa); | ||
| 327 | self.symbols_free_list.deinit(gpa); | ||
| 328 | self.globals.deinit(gpa); | ||
| 329 | { | 308 | { |
| 330 | var it = self.undefs.iterator(); | 309 | var it = self.undefs.iterator(); |
| 331 | while (it.next()) |entry| { | 310 | while (it.next()) |entry| { |
| ... | @@ -333,10 +312,14 @@ pub fn deinit(self: *MachO) void { | ... | @@ -333,10 +312,14 @@ pub fn deinit(self: *MachO) void { |
| 333 | } | 312 | } |
| 334 | self.undefs.deinit(gpa); | 313 | self.undefs.deinit(gpa); |
| 335 | } | 314 | } |
| 336 | self.undefined_symbols.deinit(gpa); | 315 | { |
| 337 | self.boundary_symbols.deinit(gpa); | 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 | self.symtab.deinit(gpa); | 323 | self.symtab.deinit(gpa); |
| 341 | self.strtab.deinit(gpa); | 324 | self.strtab.deinit(gpa); |
| 342 | self.got.deinit(gpa); | 325 | self.got.deinit(gpa); |
| ... | @@ -350,14 +333,9 @@ pub fn deinit(self: *MachO) void { | ... | @@ -350,14 +333,9 @@ pub fn deinit(self: *MachO) void { |
| 350 | self.lazy_bind.deinit(gpa); | 333 | self.lazy_bind.deinit(gpa); |
| 351 | self.export_trie.deinit(gpa); | 334 | self.export_trie.deinit(gpa); |
| 352 | self.unwind_info.deinit(gpa); | 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 | self.thunks.deinit(gpa); | 338 | self.thunks.deinit(gpa); |
| 360 | self.unwind_records.deinit(gpa); | ||
| 361 | } | 339 | } |
| 362 | 340 | ||
| 363 | pub fn flush(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { | 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,17 +513,14 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 535 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 513 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 536 | self.files.set(index, .{ .internal = .{ .index = index } }); | 514 | self.files.set(index, .{ .internal = .{ .index = index } }); |
| 537 | self.internal_object = index; | 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 | try self.resolveSymbols(); | 521 | try self.resolveSymbols(); |
| 542 | try self.parseDebugInfo(); | 522 | try self.convertTentativeDefsAndResolveSpecialSymbols(); |
| 543 | try self.resolveSyntheticSymbols(); | ||
| 544 | |||
| 545 | try self.convertTentativeDefinitions(); | ||
| 546 | try self.createObjcSections(); | ||
| 547 | try self.dedupLiterals(); | 523 | try self.dedupLiterals(); |
| 548 | try self.claimUnresolved(); | ||
| 549 | 524 | ||
| 550 | if (self.base.gc_sections) { | 525 | if (self.base.gc_sections) { |
| 551 | try dead_strip.gcAtoms(self); | 526 | try dead_strip.gcAtoms(self); |
| ... | @@ -567,6 +542,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n | ... | @@ -567,6 +542,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 567 | dylib.ordinal = @intCast(ord); | 542 | dylib.ordinal = @intCast(ord); |
| 568 | } | 543 | } |
| 569 | 544 | ||
| 545 | self.claimUnresolved(); | ||
| 546 | |||
| 570 | self.scanRelocs() catch |err| switch (err) { | 547 | self.scanRelocs() catch |err| switch (err) { |
| 571 | error.HasUndefinedSymbols => return error.FlushFailure, | 548 | error.HasUndefinedSymbols => return error.FlushFailure, |
| 572 | else => |e| { | 549 | else => |e| { |
| ... | @@ -580,92 +557,38 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n | ... | @@ -580,92 +557,38 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 580 | try self.sortSections(); | 557 | try self.sortSections(); |
| 581 | try self.addAtomsToSections(); | 558 | try self.addAtomsToSections(); |
| 582 | try self.calcSectionSizes(); | 559 | try self.calcSectionSizes(); |
| 560 | |||
| 583 | try self.generateUnwindInfo(); | 561 | try self.generateUnwindInfo(); |
| 584 | try self.initSegments(); | ||
| 585 | 562 | ||
| 563 | try self.initSegments(); | ||
| 586 | try self.allocateSections(); | 564 | try self.allocateSections(); |
| 587 | self.allocateSegments(); | 565 | self.allocateSegments(); |
| 588 | self.allocateSyntheticSymbols(); | 566 | self.allocateSyntheticSymbols(); |
| 589 | try self.allocateLinkeditSegment(); | ||
| 590 | 567 | ||
| 591 | if (build_options.enable_logging) { | 568 | if (build_options.enable_logging) { |
| 592 | state_log.debug("{}", .{self.dumpState()}); | 569 | state_log.debug("{}", .{self.dumpState()}); |
| 593 | } | 570 | } |
| 594 | 571 | ||
| 595 | try self.initDyldInfoSections(); | ||
| 596 | |||
| 597 | // Beyond this point, everything has been allocated a virtual address and we can resolve | 572 | // Beyond this point, everything has been allocated a virtual address and we can resolve |
| 598 | // the relocations, and commit objects to file. | 573 | // the relocations, and commit objects to file. |
| 599 | if (self.getZigObject()) |zo| { | 574 | try self.resizeSections(); |
| 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 | } | ||
| 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 | 582 | self.writeSectionsAndUpdateLinkeditSizes() catch |err| { | |
| 643 | self.writeAtoms() catch |err| switch (err) { | 583 | switch (err) { |
| 644 | error.ResolveFailed => return error.FlushFailure, | 584 | error.ResolveFailed => return error.FlushFailure, |
| 645 | else => |e| { | 585 | else => |e| return e, |
| 646 | try self.reportUnexpectedError("unexpected error while resolving relocations", .{}); | 586 | } |
| 647 | return e; | ||
| 648 | }, | ||
| 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 | var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: { | 593 | var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: { |
| 671 | // Preallocate space for the code signature. | 594 | // Preallocate space for the code signature. |
| ... | @@ -982,12 +905,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void { | ... | @@ -982,12 +905,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void { |
| 982 | break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); | 905 | break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); |
| 983 | }; | 906 | }; |
| 984 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 907 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 985 | self.files.set(index, .{ .object = .{ | 908 | self.files.set(index, .{ |
| 986 | .path = try gpa.dupe(u8, path), | 909 | .object = .{ |
| 987 | .file_handle = handle, | 910 | .offset = 0, // TODO FAT objects |
| 988 | .mtime = mtime, | 911 | .path = try gpa.dupe(u8, path), |
| 989 | .index = index, | 912 | .file_handle = handle, |
| 990 | } }); | 913 | .mtime = mtime, |
| 914 | .index = index, | ||
| 915 | }, | ||
| 916 | }); | ||
| 991 | try self.objects.append(gpa, index); | 917 | try self.objects.append(gpa, index); |
| 992 | 918 | ||
| 993 | const object = self.getFile(index).?.object; | 919 | const object = self.getFile(index).?.object; |
| ... | @@ -1327,35 +1253,6 @@ fn parseDependentDylibs(self: *MachO) !void { | ... | @@ -1327,35 +1253,6 @@ fn parseDependentDylibs(self: *MachO) !void { |
| 1327 | if (has_errors) return error.MissingLibraryDependencies; | 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 | /// When resolving symbols, we approach the problem similarly to `mold`. | 1256 | /// When resolving symbols, we approach the problem similarly to `mold`. |
| 1360 | /// 1. Resolve symbols across all objects (including those preemptively extracted archives). | 1257 | /// 1. Resolve symbols across all objects (including those preemptively extracted archives). |
| 1361 | /// 2. Resolve symbols across all shared objects. | 1258 | /// 2. Resolve symbols across all shared objects. |
| ... | @@ -1368,18 +1265,17 @@ pub fn resolveSymbols(self: *MachO) !void { | ... | @@ -1368,18 +1265,17 @@ pub fn resolveSymbols(self: *MachO) !void { |
| 1368 | defer tracy.end(); | 1265 | defer tracy.end(); |
| 1369 | 1266 | ||
| 1370 | // Resolve symbols in the ZigObject. For now, we assume that it's always live. | 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 | // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). | 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); | 1270 | for (self.objects.items) |index| try self.getFile(index).?.resolveSymbols(self); |
| 1374 | for (self.dylibs.items) |index| 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 | // Mark live objects. | 1274 | // Mark live objects. |
| 1377 | self.markLive(); | 1275 | self.markLive(); |
| 1378 | 1276 | ||
| 1379 | // Reset state of all globals after marking live objects. | 1277 | // Reset state of all globals after marking live objects. |
| 1380 | if (self.getZigObject()) |zo| zo.asFile().resetGlobals(self); | 1278 | self.resolver.reset(); |
| 1381 | for (self.objects.items) |index| self.getFile(index).?.resetGlobals(self); | ||
| 1382 | for (self.dylibs.items) |index| self.getFile(index).?.resetGlobals(self); | ||
| 1383 | 1279 | ||
| 1384 | // Prune dead objects. | 1280 | // Prune dead objects. |
| 1385 | var i: usize = 0; | 1281 | var i: usize = 0; |
| ... | @@ -1393,37 +1289,26 @@ pub fn resolveSymbols(self: *MachO) !void { | ... | @@ -1393,37 +1289,26 @@ pub fn resolveSymbols(self: *MachO) !void { |
| 1393 | } | 1289 | } |
| 1394 | 1290 | ||
| 1395 | // Re-resolve the symbols. | 1291 | // Re-resolve the symbols. |
| 1396 | if (self.getZigObject()) |zo| zo.resolveSymbols(self); | 1292 | if (self.getZigObject()) |zo| try zo.resolveSymbols(self); |
| 1397 | for (self.objects.items) |index| self.getFile(index).?.resolveSymbols(self); | 1293 | for (self.objects.items) |index| try self.getFile(index).?.resolveSymbols(self); |
| 1398 | for (self.dylibs.items) |index| 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 | fn markLive(self: *MachO) void { | 1302 | fn markLive(self: *MachO) void { |
| 1402 | const tracy = trace(@src()); | 1303 | const tracy = trace(@src()); |
| 1403 | defer tracy.end(); | 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 | if (self.getZigObject()) |zo| zo.markLive(self); | 1306 | if (self.getZigObject()) |zo| zo.markLive(self); |
| 1417 | for (self.objects.items) |index| { | 1307 | for (self.objects.items) |index| { |
| 1418 | const object = self.getFile(index).?.object; | 1308 | const object = self.getFile(index).?.object; |
| 1419 | if (object.alive) object.markLive(self); | 1309 | if (object.alive) object.markLive(self); |
| 1420 | } | 1310 | } |
| 1421 | } | 1311 | if (self.getInternalObject()) |obj| obj.markLive(self); |
| 1422 | |||
| 1423 | pub fn parseDebugInfo(self: *MachO) !void { | ||
| 1424 | for (self.objects.items) |index| { | ||
| 1425 | try self.getFile(index).?.object.parseDebugInfo(self); | ||
| 1426 | } | ||
| 1427 | } | 1312 | } |
| 1428 | 1313 | ||
| 1429 | fn resolveSyntheticSymbols(self: *MachO) !void { | 1314 | fn resolveSyntheticSymbols(self: *MachO) !void { |
| ... | @@ -1473,10 +1358,14 @@ 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 | for (self.objects.items) |index| { | 1362 | for (self.objects.items) |index| { |
| 1478 | try self.getFile(index).?.object.convertTentativeDefinitions(self); | 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 | fn createObjcSections(self: *MachO) !void { | 1371 | fn createObjcSections(self: *MachO) !void { |
| ... | @@ -1514,6 +1403,9 @@ fn createObjcSections(self: *MachO) !void { | ... | @@ -1514,6 +1403,9 @@ fn createObjcSections(self: *MachO) !void { |
| 1514 | } | 1403 | } |
| 1515 | 1404 | ||
| 1516 | pub fn dedupLiterals(self: *MachO) !void { | 1405 | pub fn dedupLiterals(self: *MachO) !void { |
| 1406 | const tracy = trace(@src()); | ||
| 1407 | defer tracy.end(); | ||
| 1408 | |||
| 1517 | const gpa = self.base.comp.gpa; | 1409 | const gpa = self.base.comp.gpa; |
| 1518 | var lp: LiteralPool = .{}; | 1410 | var lp: LiteralPool = .{}; |
| 1519 | defer lp.deinit(gpa); | 1411 | defer lp.deinit(gpa); |
| ... | @@ -1539,80 +1431,46 @@ pub fn dedupLiterals(self: *MachO) !void { | ... | @@ -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 | if (self.getZigObject()) |zo| { | 1435 | if (self.getZigObject()) |zo| { |
| 1544 | try zo.asFile().claimUnresolved(self); | 1436 | zo.asFile().claimUnresolved(self); |
| 1545 | } | 1437 | } |
| 1546 | for (self.objects.items) |index| { | 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 | fn checkDuplicates(self: *MachO) !void { | 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 | if (self.getZigObject()) |zo| { | 1444 | if (self.getZigObject()) |zo| { |
| 1563 | try zo.checkDuplicates(&dupes, self); | 1445 | try zo.asFile().checkDuplicates(self); |
| 1564 | } | 1446 | } |
| 1565 | |||
| 1566 | for (self.objects.items) |index| { | 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 | 1450 | if (self.getInternalObject()) |obj| { | |
| 1570 | try self.reportDuplicates(dupes); | 1451 | try obj.asFile().checkDuplicates(self); |
| 1452 | } | ||
| 1453 | try self.reportDuplicates(); | ||
| 1571 | } | 1454 | } |
| 1572 | 1455 | ||
| 1573 | fn markImportsAndExports(self: *MachO) void { | 1456 | fn markImportsAndExports(self: *MachO) void { |
| 1457 | const tracy = trace(@src()); | ||
| 1458 | defer tracy.end(); | ||
| 1459 | |||
| 1574 | if (self.getZigObject()) |zo| { | 1460 | if (self.getZigObject()) |zo| { |
| 1575 | zo.asFile().markImportsExports(self); | 1461 | zo.asFile().markImportsExports(self); |
| 1576 | } | 1462 | } |
| 1577 | for (self.objects.items) |index| { | 1463 | for (self.objects.items) |index| { |
| 1578 | self.getFile(index).?.markImportsExports(self); | 1464 | self.getFile(index).?.markImportsExports(self); |
| 1579 | } | 1465 | } |
| 1580 | 1466 | if (self.getInternalObject()) |obj| { | |
| 1581 | for (self.undefined_symbols.items) |index| { | 1467 | obj.asFile().markImportsExports(self); |
| 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 | } | ||
| 1600 | } | 1468 | } |
| 1601 | } | 1469 | } |
| 1602 | 1470 | ||
| 1603 | fn deadStripDylibs(self: *MachO) void { | 1471 | fn deadStripDylibs(self: *MachO) void { |
| 1604 | for (&[_]?Symbol.Index{ | 1472 | const tracy = trace(@src()); |
| 1605 | self.entry_index, | 1473 | defer tracy.end(); |
| 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 | } | ||
| 1616 | 1474 | ||
| 1617 | for (self.dylibs.items) |index| { | 1475 | for (self.dylibs.items) |index| { |
| 1618 | self.getFile(index).?.dylib.markReferenced(self); | 1476 | self.getFile(index).?.dylib.markReferenced(self); |
| ... | @@ -1633,50 +1491,29 @@ fn scanRelocs(self: *MachO) !void { | ... | @@ -1633,50 +1491,29 @@ fn scanRelocs(self: *MachO) !void { |
| 1633 | const tracy = trace(@src()); | 1491 | const tracy = trace(@src()); |
| 1634 | defer tracy.end(); | 1492 | defer tracy.end(); |
| 1635 | 1493 | ||
| 1636 | if (self.getZigObject()) |zo| try zo.scanRelocs(self); | 1494 | if (self.getZigObject()) |zo| { |
| 1637 | 1495 | try zo.scanRelocs(self); | |
| 1496 | } | ||
| 1638 | for (self.objects.items) |index| { | 1497 | for (self.objects.items) |index| { |
| 1639 | try self.getFile(index).?.object.scanRelocs(self); | 1498 | try self.getFile(index).?.object.scanRelocs(self); |
| 1640 | } | 1499 | } |
| 1500 | if (self.getInternalObject()) |obj| { | ||
| 1501 | obj.scanRelocs(self); | ||
| 1502 | } | ||
| 1641 | 1503 | ||
| 1642 | try self.reportUndefs(); | 1504 | try self.reportUndefs(); |
| 1643 | 1505 | ||
| 1644 | if (self.entry_index) |index| { | 1506 | if (self.getZigObject()) |zo| { |
| 1645 | const sym = self.getSymbol(index); | 1507 | try zo.asFile().createSymbolIndirection(self); |
| 1646 | if (sym.getFile(self) != null) { | ||
| 1647 | if (sym.flags.import) sym.flags.stubs = true; | ||
| 1648 | } | ||
| 1649 | } | 1508 | } |
| 1650 | 1509 | for (self.objects.items) |index| { | |
| 1651 | if (self.dyld_stub_binder_index) |index| { | 1510 | try self.getFile(index).?.createSymbolIndirection(self); |
| 1652 | const sym = self.getSymbol(index); | ||
| 1653 | if (sym.getFile(self) != null) sym.flags.needs_got = true; | ||
| 1654 | } | 1511 | } |
| 1655 | 1512 | for (self.dylibs.items) |index| { | |
| 1656 | if (self.objc_msg_send_index) |index| { | 1513 | try self.getFile(index).?.createSymbolIndirection(self); |
| 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? | ||
| 1660 | } | 1514 | } |
| 1661 | 1515 | if (self.getInternalObject()) |obj| { | |
| 1662 | for (self.symbols.items, 0..) |*symbol, i| { | 1516 | try obj.asFile().createSymbolIndirection(self); |
| 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 | } | ||
| 1680 | } | 1517 | } |
| 1681 | } | 1518 | } |
| 1682 | 1519 | ||
| ... | @@ -1684,17 +1521,15 @@ fn reportUndefs(self: *MachO) !void { | ... | @@ -1684,17 +1521,15 @@ fn reportUndefs(self: *MachO) !void { |
| 1684 | const tracy = trace(@src()); | 1521 | const tracy = trace(@src()); |
| 1685 | defer tracy.end(); | 1522 | defer tracy.end(); |
| 1686 | 1523 | ||
| 1687 | switch (self.undefined_treatment) { | 1524 | if (self.undefined_treatment == .suppress or |
| 1688 | .dynamic_lookup, .suppress => return, | 1525 | self.undefined_treatment == .dynamic_lookup) return; |
| 1689 | .@"error", .warn => {}, | ||
| 1690 | } | ||
| 1691 | 1526 | ||
| 1692 | const max_notes = 4; | 1527 | const max_notes = 4; |
| 1693 | 1528 | ||
| 1694 | var has_undefs = false; | 1529 | var has_undefs = false; |
| 1695 | var it = self.undefs.iterator(); | 1530 | var it = self.undefs.iterator(); |
| 1696 | while (it.next()) |entry| { | 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 | const notes = entry.value_ptr.*; | 1533 | const notes = entry.value_ptr.*; |
| 1699 | const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); | 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,8 +1539,9 @@ fn reportUndefs(self: *MachO) !void { |
| 1704 | 1539 | ||
| 1705 | var inote: usize = 0; | 1540 | var inote: usize = 0; |
| 1706 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { | 1541 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { |
| 1707 | const atom = self.getAtom(notes.items[inote]).?; | 1542 | const note = notes.items[inote]; |
| 1708 | const file = atom.getFile(self); | 1543 | const file = self.getFile(note.file).?; |
| 1544 | const atom = note.getAtom(self).?; | ||
| 1709 | try err.addNote(self, "referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) }); | 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,64 +1550,18 @@ fn reportUndefs(self: *MachO) !void { |
| 1714 | try err.addNote(self, "referenced {d} more times", .{remaining}); | 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 | if (has_undefs) return error.HasUndefinedSymbols; | 1553 | if (has_undefs) return error.HasUndefinedSymbols; |
| 1758 | } | 1554 | } |
| 1759 | 1555 | ||
| 1760 | fn initOutputSections(self: *MachO) !void { | 1556 | fn initOutputSections(self: *MachO) !void { |
| 1557 | const tracy = trace(@src()); | ||
| 1558 | defer tracy.end(); | ||
| 1559 | |||
| 1761 | for (self.objects.items) |index| { | 1560 | for (self.objects.items) |index| { |
| 1762 | const object = self.getFile(index).?.object; | 1561 | try self.getFile(index).?.initOutputSections(self); |
| 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 | } | ||
| 1768 | } | 1562 | } |
| 1769 | if (self.getInternalObject()) |object| { | 1563 | if (self.getInternalObject()) |obj| { |
| 1770 | for (object.atoms.items) |atom_index| { | 1564 | try obj.asFile().initOutputSections(self); |
| 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 | } | ||
| 1775 | } | 1565 | } |
| 1776 | self.text_sect_index = self.getSectionByName("__TEXT", "__text") orelse | 1566 | self.text_sect_index = self.getSectionByName("__TEXT", "__text") orelse |
| 1777 | try self.addSection("__TEXT", "__text", .{ | 1567 | try self.addSection("__TEXT", "__text", .{ |
| ... | @@ -1844,46 +1634,50 @@ fn initSyntheticSections(self: *MachO) !void { | ... | @@ -1844,46 +1634,50 @@ fn initSyntheticSections(self: *MachO) !void { |
| 1844 | self.eh_frame_sect_index = try self.addSection("__TEXT", "__eh_frame", .{}); | 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 | const gpa = self.base.comp.gpa; | 1638 | const gpa = self.base.comp.gpa; |
| 1849 | const sym = self.getSymbol(sym_index); | 1639 | |
| 1850 | const name = sym.getName(self); | 1640 | for (obj.boundary_symbols.items) |sym_index| { |
| 1851 | 1641 | const ref = obj.getSymbolRef(sym_index, self); | |
| 1852 | if (eatPrefix(name, "segment$start$")) |segname| { | 1642 | const sym = ref.getSymbol(self).?; |
| 1853 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid | 1643 | const name = sym.getName(self); |
| 1854 | const prot = getSegmentProt(segname); | 1644 | |
| 1855 | _ = try self.segments.append(gpa, .{ | 1645 | if (eatPrefix(name, "segment$start$")) |segname| { |
| 1856 | .cmdsize = @sizeOf(macho.segment_command_64), | 1646 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid |
| 1857 | .segname = makeStaticString(segname), | 1647 | const prot = getSegmentProt(segname); |
| 1858 | .initprot = prot, | 1648 | _ = try self.segments.append(gpa, .{ |
| 1859 | .maxprot = prot, | 1649 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1860 | }); | 1650 | .segname = makeStaticString(segname), |
| 1861 | } | 1651 | .initprot = prot, |
| 1862 | } else if (eatPrefix(name, "segment$stop$")) |segname| { | 1652 | .maxprot = prot, |
| 1863 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid | 1653 | }); |
| 1864 | const prot = getSegmentProt(segname); | 1654 | } |
| 1865 | _ = try self.segments.append(gpa, .{ | 1655 | } else if (eatPrefix(name, "segment$stop$")) |segname| { |
| 1866 | .cmdsize = @sizeOf(macho.segment_command_64), | 1656 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid |
| 1867 | .segname = makeStaticString(segname), | 1657 | const prot = getSegmentProt(segname); |
| 1868 | .initprot = prot, | 1658 | _ = try self.segments.append(gpa, .{ |
| 1869 | .maxprot = prot, | 1659 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1870 | }); | 1660 | .segname = makeStaticString(segname), |
| 1871 | } | 1661 | .initprot = prot, |
| 1872 | } else if (eatPrefix(name, "section$start$")) |actual_name| { | 1662 | .maxprot = prot, |
| 1873 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | 1663 | }); |
| 1874 | const segname = actual_name[0..sep]; // TODO check segname is valid | 1664 | } |
| 1875 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid | 1665 | } else if (eatPrefix(name, "section$start$")) |actual_name| { |
| 1876 | if (self.getSectionByName(segname, sectname) == null) { | 1666 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 1877 | _ = try self.addSection(segname, sectname, .{}); | 1667 | const segname = actual_name[0..sep]; // TODO check segname is valid |
| 1878 | } | 1668 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid |
| 1879 | } else if (eatPrefix(name, "section$stop$")) |actual_name| { | 1669 | if (self.getSectionByName(segname, sectname) == null) { |
| 1880 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | 1670 | _ = try self.addSection(segname, sectname, .{}); |
| 1881 | const segname = actual_name[0..sep]; // TODO check segname is valid | 1671 | } |
| 1882 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid | 1672 | } else if (eatPrefix(name, "section$stop$")) |actual_name| { |
| 1883 | if (self.getSectionByName(segname, sectname) == null) { | 1673 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 1884 | _ = try self.addSection(segname, sectname, .{}); | 1674 | const segname = actual_name[0..sep]; // TODO check segname is valid |
| 1885 | } | 1675 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid |
| 1886 | } else unreachable; | 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,38 +1784,25 @@ pub fn sortSections(self: *MachO) !void { |
| 1990 | } | 1784 | } |
| 1991 | 1785 | ||
| 1992 | if (self.getZigObject()) |zo| { | 1786 | if (self.getZigObject()) |zo| { |
| 1993 | for (zo.atoms.items) |atom_index| { | 1787 | for (zo.getAtoms()) |atom_index| { |
| 1994 | const atom = self.getAtom(atom_index) orelse continue; | 1788 | const atom = zo.getAtom(atom_index) orelse continue; |
| 1995 | if (!atom.flags.alive) continue; | 1789 | if (!atom.flags.alive) continue; |
| 1996 | atom.out_n_sect = backlinks[atom.out_n_sect]; | 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 | for (self.objects.items) |index| { | 1794 | for (self.objects.items) |index| { |
| 2015 | for (self.getFile(index).?.object.atoms.items) |atom_index| { | 1795 | const file = self.getFile(index).?; |
| 2016 | const atom = self.getAtom(atom_index) orelse continue; | 1796 | for (file.getAtoms()) |atom_index| { |
| 1797 | const atom = file.getAtom(atom_index) orelse continue; | ||
| 2017 | if (!atom.flags.alive) continue; | 1798 | if (!atom.flags.alive) continue; |
| 2018 | atom.out_n_sect = backlinks[atom.out_n_sect]; | 1799 | atom.out_n_sect = backlinks[atom.out_n_sect]; |
| 2019 | } | 1800 | } |
| 2020 | } | 1801 | } |
| 2021 | 1802 | ||
| 2022 | if (self.getInternalObject()) |object| { | 1803 | if (self.getInternalObject()) |object| { |
| 2023 | for (object.atoms.items) |atom_index| { | 1804 | for (object.getAtoms()) |atom_index| { |
| 2024 | const atom = self.getAtom(atom_index) orelse continue; | 1805 | const atom = object.getAtom(atom_index) orelse continue; |
| 2025 | if (!atom.flags.alive) continue; | 1806 | if (!atom.flags.alive) continue; |
| 2026 | atom.out_n_sect = backlinks[atom.out_n_sect]; | 1807 | atom.out_n_sect = backlinks[atom.out_n_sect]; |
| 2027 | } | 1808 | } |
| ... | @@ -2058,35 +1839,32 @@ pub fn addAtomsToSections(self: *MachO) !void { | ... | @@ -2058,35 +1839,32 @@ pub fn addAtomsToSections(self: *MachO) !void { |
| 2058 | const tracy = trace(@src()); | 1839 | const tracy = trace(@src()); |
| 2059 | defer tracy.end(); | 1840 | defer tracy.end(); |
| 2060 | 1841 | ||
| 2061 | for (self.objects.items) |index| { | 1842 | const gpa = self.base.comp.gpa; |
| 2062 | const object = self.getFile(index).?.object; | 1843 | |
| 2063 | for (object.atoms.items) |atom_index| { | 1844 | if (self.getZigObject()) |zo| { |
| 2064 | const atom = self.getAtom(atom_index) orelse continue; | 1845 | for (zo.getAtoms()) |atom_index| { |
| 1846 | const atom = zo.getAtom(atom_index) orelse continue; | ||
| 2065 | if (!atom.flags.alive) continue; | 1847 | if (!atom.flags.alive) continue; |
| 1848 | if (self.isZigSection(atom.out_n_sect)) continue; | ||
| 2066 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; | 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| { | 1852 | } |
| 2070 | const sym = self.getSymbol(sym_index); | 1853 | for (self.objects.items) |index| { |
| 2071 | const atom = sym.getAtom(self) orelse continue; | 1854 | const file = self.getFile(index).?; |
| 1855 | for (file.getAtoms()) |atom_index| { | ||
| 1856 | const atom = file.getAtom(atom_index) orelse continue; | ||
| 2072 | if (!atom.flags.alive) continue; | 1857 | if (!atom.flags.alive) continue; |
| 2073 | if (sym.getFile(self).?.getIndex() != index) continue; | 1858 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; |
| 2074 | sym.out_n_sect = atom.out_n_sect; | 1859 | try atoms.append(gpa, .{ .index = atom_index, .file = index }); |
| 2075 | } | 1860 | } |
| 2076 | } | 1861 | } |
| 2077 | if (self.getInternalObject()) |object| { | 1862 | if (self.getInternalObject()) |object| { |
| 2078 | for (object.atoms.items) |atom_index| { | 1863 | for (object.getAtoms()) |atom_index| { |
| 2079 | const atom = self.getAtom(atom_index) orelse continue; | 1864 | const atom = object.getAtom(atom_index) orelse continue; |
| 2080 | if (!atom.flags.alive) continue; | 1865 | if (!atom.flags.alive) continue; |
| 2081 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; | 1866 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; |
| 2082 | try atoms.append(self.base.comp.gpa, atom_index); | 1867 | try atoms.append(gpa, .{ .index = atom_index, .file = object.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; | ||
| 2090 | } | 1868 | } |
| 2091 | } | 1869 | } |
| 2092 | } | 1870 | } |
| ... | @@ -2108,8 +1886,8 @@ fn calcSectionSizes(self: *MachO) !void { | ... | @@ -2108,8 +1886,8 @@ fn calcSectionSizes(self: *MachO) !void { |
| 2108 | if (atoms.items.len == 0) continue; | 1886 | if (atoms.items.len == 0) continue; |
| 2109 | if (self.requiresThunks() and header.isCode()) continue; | 1887 | if (self.requiresThunks() and header.isCode()) continue; |
| 2110 | 1888 | ||
| 2111 | for (atoms.items) |atom_index| { | 1889 | for (atoms.items) |ref| { |
| 2112 | const atom = self.getAtom(atom_index).?; | 1890 | const atom = ref.getAtom(self).?; |
| 2113 | const atom_alignment = atom.alignment.toByteUnits() orelse 1; | 1891 | const atom_alignment = atom.alignment.toByteUnits() orelse 1; |
| 2114 | const offset = mem.alignForward(u64, header.size, atom_alignment); | 1892 | const offset = mem.alignForward(u64, header.size, atom_alignment); |
| 2115 | const padding = offset - header.size; | 1893 | const padding = offset - header.size; |
| ... | @@ -2129,6 +1907,22 @@ fn calcSectionSizes(self: *MachO) !void { | ... | @@ -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 | if (self.got_sect_index) |idx| { | 1926 | if (self.got_sect_index) |idx| { |
| 2133 | const header = &self.sections.items(.header)[idx]; | 1927 | const header = &self.sections.items(.header)[idx]; |
| 2134 | header.size = self.got.size(); | 1928 | header.size = self.got.size(); |
| ... | @@ -2409,77 +2203,61 @@ fn allocateSegments(self: *MachO) void { | ... | @@ -2409,77 +2203,61 @@ fn allocateSegments(self: *MachO) void { |
| 2409 | } | 2203 | } |
| 2410 | 2204 | ||
| 2411 | fn allocateSyntheticSymbols(self: *MachO) void { | 2205 | fn allocateSyntheticSymbols(self: *MachO) void { |
| 2412 | const text_seg = self.getTextSegment(); | 2206 | if (self.getInternalObject()) |obj| { |
| 2413 | 2207 | obj.allocateSyntheticSymbols(self); | |
| 2414 | if (self.mh_execute_header_index) |index| { | ||
| 2415 | const global = self.getSymbol(index); | ||
| 2416 | global.value = text_seg.vmaddr; | ||
| 2417 | } | ||
| 2418 | 2208 | ||
| 2419 | if (self.data_sect_index) |idx| { | 2209 | const text_seg = self.getTextSegment(); |
| 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 | } | ||
| 2433 | 2210 | ||
| 2434 | for (self.boundary_symbols.items) |sym_index| { | 2211 | for (obj.boundary_symbols.items) |sym_index| { |
| 2435 | const sym = self.getSymbol(sym_index); | 2212 | const ref = obj.getSymbolRef(sym_index, self); |
| 2436 | const name = sym.getName(self); | 2213 | const sym = ref.getSymbol(self).?; |
| 2214 | const name = sym.getName(self); | ||
| 2437 | 2215 | ||
| 2438 | sym.flags.@"export" = false; | 2216 | sym.value = text_seg.vmaddr; |
| 2439 | sym.value = text_seg.vmaddr; | ||
| 2440 | 2217 | ||
| 2441 | if (mem.startsWith(u8, name, "segment$start$")) { | 2218 | if (mem.startsWith(u8, name, "segment$start$")) { |
| 2442 | const segname = name["segment$start$".len..]; | 2219 | const segname = name["segment$start$".len..]; |
| 2443 | if (self.getSegmentByName(segname)) |seg_id| { | 2220 | if (self.getSegmentByName(segname)) |seg_id| { |
| 2444 | const seg = self.segments.items[seg_id]; | 2221 | const seg = self.segments.items[seg_id]; |
| 2445 | sym.value = seg.vmaddr; | 2222 | sym.value = seg.vmaddr; |
| 2446 | } | 2223 | } |
| 2447 | } else if (mem.startsWith(u8, name, "segment$stop$")) { | 2224 | } else if (mem.startsWith(u8, name, "segment$stop$")) { |
| 2448 | const segname = name["segment$stop$".len..]; | 2225 | const segname = name["segment$stop$".len..]; |
| 2449 | if (self.getSegmentByName(segname)) |seg_id| { | 2226 | if (self.getSegmentByName(segname)) |seg_id| { |
| 2450 | const seg = self.segments.items[seg_id]; | 2227 | const seg = self.segments.items[seg_id]; |
| 2451 | sym.value = seg.vmaddr + seg.vmsize; | 2228 | sym.value = seg.vmaddr + seg.vmsize; |
| 2452 | } | 2229 | } |
| 2453 | } else if (mem.startsWith(u8, name, "section$start$")) { | 2230 | } else if (mem.startsWith(u8, name, "section$start$")) { |
| 2454 | const actual_name = name["section$start$".len..]; | 2231 | const actual_name = name["section$start$".len..]; |
| 2455 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | 2232 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 2456 | const segname = actual_name[0..sep]; | 2233 | const segname = actual_name[0..sep]; |
| 2457 | const sectname = actual_name[sep + 1 ..]; | 2234 | const sectname = actual_name[sep + 1 ..]; |
| 2458 | if (self.getSectionByName(segname, sectname)) |sect_id| { | 2235 | if (self.getSectionByName(segname, sectname)) |sect_id| { |
| 2459 | const sect = self.sections.items(.header)[sect_id]; | 2236 | const sect = self.sections.items(.header)[sect_id]; |
| 2460 | sym.value = sect.addr; | 2237 | sym.value = sect.addr; |
| 2461 | sym.out_n_sect = sect_id; | 2238 | sym.out_n_sect = sect_id; |
| 2462 | } | 2239 | } |
| 2463 | } else if (mem.startsWith(u8, name, "section$stop$")) { | 2240 | } else if (mem.startsWith(u8, name, "section$stop$")) { |
| 2464 | const actual_name = name["section$stop$".len..]; | 2241 | const actual_name = name["section$stop$".len..]; |
| 2465 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic | 2242 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 2466 | const segname = actual_name[0..sep]; | 2243 | const segname = actual_name[0..sep]; |
| 2467 | const sectname = actual_name[sep + 1 ..]; | 2244 | const sectname = actual_name[sep + 1 ..]; |
| 2468 | if (self.getSectionByName(segname, sectname)) |sect_id| { | 2245 | if (self.getSectionByName(segname, sectname)) |sect_id| { |
| 2469 | const sect = self.sections.items(.header)[sect_id]; | 2246 | const sect = self.sections.items(.header)[sect_id]; |
| 2470 | sym.value = sect.addr + sect.size; | 2247 | sym.value = sect.addr + sect.size; |
| 2471 | sym.out_n_sect = sect_id; | 2248 | sym.out_n_sect = sect_id; |
| 2472 | } | 2249 | } |
| 2473 | } else unreachable; | 2250 | } else unreachable; |
| 2474 | } | 2251 | } |
| 2475 | 2252 | ||
| 2476 | if (self.objc_stubs.symbols.items.len > 0) { | 2253 | if (self.objc_stubs.symbols.items.len > 0) { |
| 2477 | const addr = self.sections.items(.header)[self.objc_stubs_sect_index.?].addr; | 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| { | 2256 | for (self.objc_stubs.symbols.items, 0..) |ref, idx| { |
| 2480 | const sym = self.getSymbol(sym_index); | 2257 | const sym = ref.getSymbol(self).?; |
| 2481 | sym.value = addr + idx * ObjcStubsSection.entrySize(self.getTarget().cpu.arch); | 2258 | sym.value = addr + idx * ObjcStubsSection.entrySize(self.getTarget().cpu.arch); |
| 2482 | sym.out_n_sect = self.objc_stubs_sect_index.?; | 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,269 +2275,228 @@ fn allocateLinkeditSegment(self: *MachO) !void { |
| 2497 | const seg = self.getLinkeditSegment(); | 2275 | const seg = self.getLinkeditSegment(); |
| 2498 | seg.vmaddr = mem.alignForward(u64, vmaddr, page_size); | 2276 | seg.vmaddr = mem.alignForward(u64, vmaddr, page_size); |
| 2499 | seg.fileoff = mem.alignForward(u64, fileoff, page_size); | 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); | 2279 | var off = math.cast(u32, seg.fileoff) orelse return error.Overflow; |
| 2509 | if (self.got_sect_index != null) try self.got.addDyldRelocs(self); | 2280 | // DYLD_INFO_ONLY |
| 2510 | if (self.tlv_ptr_sect_index != null) try self.tlv_ptr.addDyldRelocs(self); | 2281 | { |
| 2511 | if (self.la_symbol_ptr_sect_index != null) try self.la_symbol_ptr.addDyldRelocs(self); | 2282 | const cmd = &self.dyld_info_cmd; |
| 2512 | try self.initExportTrie(); | 2283 | cmd.rebase_off = off; |
| 2513 | 2284 | off += cmd.rebase_size; | |
| 2514 | var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1); | 2285 | cmd.bind_off = off; |
| 2515 | defer objects.deinit(); | 2286 | off += cmd.bind_size; |
| 2516 | if (self.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index); | 2287 | cmd.weak_bind_off = off; |
| 2517 | objects.appendSliceAssumeCapacity(self.objects.items); | 2288 | off += cmd.weak_bind_size; |
| 2518 | 2289 | cmd.lazy_bind_off = off; | |
| 2519 | var nrebases: usize = 0; | 2290 | off += cmd.lazy_bind_size; |
| 2520 | var nbinds: usize = 0; | 2291 | cmd.export_off = off; |
| 2521 | var nweak_binds: usize = 0; | 2292 | off += cmd.export_size; |
| 2522 | for (objects.items) |index| { | 2293 | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 2523 | const ctx = switch (self.getFile(index).?) { | 2294 | } |
| 2524 | .zig_object => |x| x.dynamic_relocs, | 2295 | |
| 2525 | .object => |x| x.dynamic_relocs, | 2296 | // FUNCTION_STARTS |
| 2526 | else => unreachable, | 2297 | { |
| 2527 | }; | 2298 | const cmd = &self.function_starts_cmd; |
| 2528 | nrebases += ctx.rebase_relocs; | 2299 | cmd.dataoff = off; |
| 2529 | nbinds += ctx.bind_relocs; | 2300 | off += cmd.datasize; |
| 2530 | nweak_binds += ctx.weak_bind_relocs; | 2301 | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 2531 | } | ||
| 2532 | if (self.getInternalObject()) |int| { | ||
| 2533 | nrebases += int.num_rebase_relocs; | ||
| 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; | 2304 | // DATA_IN_CODE |
| 2545 | try self.export_trie.init(gpa); | 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(); | 2312 | // SYMTAB (symtab) |
| 2548 | for (self.objects.items) |index| { | 2313 | { |
| 2549 | for (self.getFile(index).?.getSymbols()) |sym_index| { | 2314 | const cmd = &self.symtab_cmd; |
| 2550 | const sym = self.getSymbol(sym_index); | 2315 | cmd.symoff = off; |
| 2551 | if (!sym.flags.@"export") continue; | 2316 | off += cmd.nsyms * @sizeOf(macho.nlist_64); |
| 2552 | if (sym.getAtom(self)) |atom| if (!atom.flags.alive) continue; | 2317 | off = mem.alignForward(u32, off, @alignOf(u32)); |
| 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 | } | ||
| 2571 | } | 2318 | } |
| 2572 | 2319 | ||
| 2573 | if (self.mh_execute_header_index) |index| { | 2320 | // DYSYMTAB |
| 2574 | const sym = self.getSymbol(index); | 2321 | { |
| 2575 | try self.export_trie.put(gpa, .{ | 2322 | const cmd = &self.dysymtab_cmd; |
| 2576 | .name = sym.getName(self), | 2323 | cmd.indirectsymoff = off; |
| 2577 | .vmaddr_offset = sym.getAddress(.{}, self) - seg.vmaddr, | 2324 | off += cmd.nindirectsyms * @sizeOf(u32); |
| 2578 | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, | 2325 | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 2579 | }); | ||
| 2580 | } | 2326 | } |
| 2581 | } | ||
| 2582 | 2327 | ||
| 2583 | fn writeAtoms(self: *MachO) !void { | 2328 | // SYMTAB (strtab) |
| 2584 | const tracy = trace(@src()); | 2329 | { |
| 2585 | defer tracy.end(); | 2330 | const cmd = &self.symtab_cmd; |
| 2331 | cmd.stroff = off; | ||
| 2332 | off += cmd.strsize; | ||
| 2333 | } | ||
| 2586 | 2334 | ||
| 2587 | const gpa = self.base.comp.gpa; | 2335 | seg.filesize = off - seg.fileoff; |
| 2588 | var arena = std.heap.ArenaAllocator.init(gpa); | 2336 | } |
| 2589 | defer arena.deinit(); | ||
| 2590 | 2337 | ||
| 2591 | const cpu_arch = self.getTarget().cpu.arch; | 2338 | fn resizeSections(self: *MachO) !void { |
| 2592 | const slice = self.sections.slice(); | 2339 | const slice = self.sections.slice(); |
| 2593 | 2340 | for (slice.items(.header), slice.items(.out), 0..) |header, *out, n_sect| { | |
| 2594 | var has_resolve_error = false; | ||
| 2595 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { | ||
| 2596 | if (atoms.items.len == 0) continue; | ||
| 2597 | if (header.isZerofill()) continue; | 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 | const size = math.cast(usize, header.size) orelse return error.Overflow; | 2344 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2600 | const buffer = try gpa.alloc(u8, size); | 2345 | try out.resize(self.base.comp.gpa, size); |
| 2601 | defer gpa.free(buffer); | ||
| 2602 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; | 2346 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; |
| 2603 | @memset(buffer, padding_byte); | 2347 | @memset(out.items, 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); | ||
| 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 | for (self.thunks.items) |thunk| { | 2368 | for (self.thunks.items) |thunk| { |
| 2621 | const header = slice.items(.header)[thunk.out_n_sect]; | 2369 | const out = self.sections.items(.out)[thunk.out_n_sect].items; |
| 2622 | const offset = thunk.value + header.offset; | 2370 | const off = math.cast(usize, thunk.value) orelse return error.Overflow; |
| 2623 | const buffer = try gpa.alloc(u8, thunk.size()); | 2371 | const size = thunk.size(); |
| 2624 | defer gpa.free(buffer); | 2372 | var stream = std.io.fixedBufferStream(out[off..][0..size]); |
| 2625 | var stream = std.io.fixedBufferStream(buffer); | ||
| 2626 | try thunk.write(self, stream.writer()); | 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; | 2376 | const slice = self.sections.slice(); |
| 2631 | } | 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 { | 2392 | if (self.la_symbol_ptr_sect_index) |_| { |
| 2634 | const tracy = trace(@src()); | 2393 | try self.updateLazyBindSize(); |
| 2635 | defer tracy.end(); | 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| { | 2402 | if (self.getZigObject()) |zo| { |
| 2640 | const header = self.sections.items(.header)[index]; | 2403 | zo.asFile().writeSymtab(self, self); |
| 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); | ||
| 2646 | } | 2404 | } |
| 2647 | 2405 | for (self.objects.items) |index| { | |
| 2648 | if (self.unwind_info_sect_index) |index| { | 2406 | self.getFile(index).?.writeSymtab(self, self); |
| 2649 | const header = self.sections.items(.header)[index]; | 2407 | } |
| 2650 | const size = math.cast(usize, header.size) orelse return error.Overflow; | 2408 | for (self.dylibs.items) |index| { |
| 2651 | const buffer = try gpa.alloc(u8, size); | 2409 | self.getFile(index).?.writeSymtab(self, self); |
| 2652 | defer gpa.free(buffer); | 2410 | } |
| 2653 | try self.unwind_info.write(self, buffer); | 2411 | if (self.getInternalObject()) |obj| { |
| 2654 | try self.base.file.?.pwriteAll(buffer, header.offset); | 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 | const tracy = trace(@src()); | 2417 | const tracy = trace(@src()); |
| 2660 | defer tracy.end(); | 2418 | defer tracy.end(); |
| 2661 | const gpa = self.base.comp.gpa; | ||
| 2662 | 2419 | ||
| 2663 | try self.rebase.finalize(gpa); | 2420 | const Tag = enum { |
| 2664 | try self.bind.finalize(gpa, self); | 2421 | eh_frame, |
| 2665 | try self.weak_bind.finalize(gpa, self); | 2422 | unwind_info, |
| 2666 | try self.lazy_bind.finalize(gpa, self); | 2423 | got, |
| 2667 | try self.export_trie.finalize(gpa); | 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 | const tracy = trace(@src()); | 2460 | const tracy = trace(@src()); |
| 2672 | defer tracy.end(); | 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; | 2469 | fn writeSectionsToFile(self: *MachO) !void { |
| 2675 | 2470 | const tracy = trace(@src()); | |
| 2676 | if (self.got_sect_index) |sect_id| { | 2471 | defer tracy.end(); |
| 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 | } | ||
| 2715 | 2472 | ||
| 2716 | if (self.tlv_ptr_sect_index) |sect_id| { | 2473 | const slice = self.sections.slice(); |
| 2717 | const header = self.sections.items(.header)[sect_id]; | 2474 | for (slice.items(.header), slice.items(.out)) |header, out| { |
| 2718 | const size = math.cast(usize, header.size) orelse return error.Overflow; | 2475 | try self.base.file.?.pwriteAll(out.items, header.offset); |
| 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); | ||
| 2724 | } | 2476 | } |
| 2477 | } | ||
| 2725 | 2478 | ||
| 2726 | if (self.objc_stubs_sect_index) |sect_id| { | 2479 | fn writeLinkeditSectionsToFile(self: *MachO) !void { |
| 2727 | const header = self.sections.items(.header)[sect_id]; | 2480 | const tracy = trace(@src()); |
| 2728 | const size = math.cast(usize, header.size) orelse return error.Overflow; | 2481 | defer tracy.end(); |
| 2729 | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); | 2482 | try self.writeDyldInfo(); |
| 2730 | defer buffer.deinit(); | 2483 | try self.writeDataInCode(); |
| 2731 | try self.objc_stubs.write(self, buffer.writer()); | 2484 | try self.writeSymtabToFile(); |
| 2732 | assert(buffer.items.len == header.size); | 2485 | try self.writeIndsymtab(); |
| 2733 | try self.base.file.?.pwriteAll(buffer.items, header.offset); | ||
| 2734 | } | ||
| 2735 | } | 2486 | } |
| 2736 | 2487 | ||
| 2737 | fn writeDyldInfoSections(self: *MachO, off: u32) !u32 { | 2488 | fn writeDyldInfo(self: *MachO) !void { |
| 2738 | const tracy = trace(@src()); | 2489 | const tracy = trace(@src()); |
| 2739 | defer tracy.end(); | 2490 | defer tracy.end(); |
| 2740 | 2491 | ||
| 2741 | const gpa = self.base.comp.gpa; | 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 | var needed_size: u32 = 0; | 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 | needed_size += cmd.rebase_size; | 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 | needed_size += cmd.bind_size; | 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 | needed_size += cmd.weak_bind_size; | 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 | needed_size += cmd.lazy_bind_size; | 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 | needed_size += cmd.export_size; | 2500 | needed_size += cmd.export_size; |
| 2764 | 2501 | ||
| 2765 | const buffer = try gpa.alloc(u8, needed_size); | 2502 | const buffer = try gpa.alloc(u8, needed_size); |
| ... | @@ -2770,89 +2507,78 @@ fn writeDyldInfoSections(self: *MachO, off: u32) !u32 { | ... | @@ -2770,89 +2507,78 @@ fn writeDyldInfoSections(self: *MachO, off: u32) !u32 { |
| 2770 | const writer = stream.writer(); | 2507 | const writer = stream.writer(); |
| 2771 | 2508 | ||
| 2772 | try self.rebase.write(writer); | 2509 | try self.rebase.write(writer); |
| 2773 | try stream.seekTo(cmd.bind_off); | 2510 | try stream.seekTo(cmd.bind_off - base_off); |
| 2774 | try self.bind.write(writer); | 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 | try self.weak_bind.write(writer); | 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 | try self.lazy_bind.write(writer); | 2515 | try self.lazy_bind.write(writer); |
| 2779 | try stream.seekTo(cmd.export_off); | 2516 | try stream.seekTo(cmd.export_off - base_off); |
| 2780 | try self.export_trie.write(writer); | 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; | 2521 | pub fn writeDataInCode(self: *MachO) !void { |
| 2783 | cmd.bind_off += off; | 2522 | const tracy = trace(@src()); |
| 2784 | cmd.weak_bind_off += off; | 2523 | defer tracy.end(); |
| 2785 | cmd.lazy_bind_off += off; | 2524 | const gpa = self.base.comp.gpa; |
| 2786 | cmd.export_off += off; | 2525 | const cmd = self.data_in_code_cmd; |
| 2787 | 2526 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size()); | |
| 2788 | try self.base.file.?.pwriteAll(buffer, off); | 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 { | 2544 | pub fn writeSymtabToFile(self: *MachO) !void { |
| 2794 | // TODO actually write it out | 2545 | const tracy = trace(@src()); |
| 2795 | const cmd = &self.function_starts_cmd; | 2546 | defer tracy.end(); |
| 2796 | cmd.dataoff = off; | 2547 | const cmd = self.symtab_cmd; |
| 2797 | return off; | 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 { | 2552 | fn writeUnwindInfo(self: *MachO) !void { |
| 2801 | const cmd = &self.data_in_code_cmd; | 2553 | const tracy = trace(@src()); |
| 2802 | cmd.dataoff = off; | 2554 | defer tracy.end(); |
| 2803 | 2555 | ||
| 2804 | const gpa = self.base.comp.gpa; | 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| { | 2558 | if (self.eh_frame_sect_index) |index| { |
| 2809 | const object = self.getFile(index).?.object; | 2559 | const header = self.sections.items(.header)[index]; |
| 2810 | const in_dices = object.getDataInCode(); | 2560 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2811 | 2561 | const buffer = try gpa.alloc(u8, size); | |
| 2812 | try dices.ensureUnusedCapacity(in_dices.len); | 2562 | defer gpa.free(buffer); |
| 2813 | 2563 | eh_frame.write(self, buffer); | |
| 2814 | var next_dice: usize = 0; | 2564 | try self.base.file.?.pwriteAll(buffer, header.offset); |
| 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 | } | ||
| 2836 | } | 2565 | } |
| 2837 | 2566 | ||
| 2838 | const needed_size = math.cast(u32, dices.items.len * @sizeOf(macho.data_in_code_entry)) orelse return error.Overflow; | 2567 | if (self.unwind_info_sect_index) |index| { |
| 2839 | cmd.datasize = needed_size; | 2568 | const header = self.sections.items(.header)[index]; |
| 2840 | 2569 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 2841 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(dices.items), cmd.dataoff); | 2570 | const buffer = try gpa.alloc(u8, size); |
| 2842 | 2571 | defer gpa.free(buffer); | |
| 2843 | return off + needed_size; | 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 | const tracy = trace(@src()); | 2578 | const tracy = trace(@src()); |
| 2848 | defer tracy.end(); | 2579 | defer tracy.end(); |
| 2849 | const gpa = self.base.comp.gpa; | ||
| 2850 | 2580 | ||
| 2851 | var nlocals: u32 = 0; | 2581 | const gpa = self.base.comp.gpa; |
| 2852 | var nstabs: u32 = 0; | ||
| 2853 | var nexports: u32 = 0; | ||
| 2854 | var nimports: u32 = 0; | ||
| 2855 | var strsize: u32 = 0; | ||
| 2856 | 2582 | ||
| 2857 | var files = std.ArrayList(File.Index).init(gpa); | 2583 | var files = std.ArrayList(File.Index).init(gpa); |
| 2858 | defer files.deinit(); | 2584 | defer files.deinit(); |
| ... | @@ -2862,6 +2588,12 @@ pub fn calcSymtabSize(self: *MachO) !void { | ... | @@ -2862,6 +2588,12 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2862 | for (self.dylibs.items) |index| files.appendAssumeCapacity(index); | 2588 | for (self.dylibs.items) |index| files.appendAssumeCapacity(index); |
| 2863 | if (self.internal_object) |index| files.appendAssumeCapacity(index); | 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 | for (files.items) |index| { | 2597 | for (files.items) |index| { |
| 2866 | const file = self.getFile(index).?; | 2598 | const file = self.getFile(index).?; |
| 2867 | const ctx = switch (file) { | 2599 | const ctx = switch (file) { |
| ... | @@ -2871,7 +2603,7 @@ pub fn calcSymtabSize(self: *MachO) !void { | ... | @@ -2871,7 +2603,7 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2871 | ctx.istab = nstabs; | 2603 | ctx.istab = nstabs; |
| 2872 | ctx.iexport = nexports; | 2604 | ctx.iexport = nexports; |
| 2873 | ctx.iimport = nimports; | 2605 | ctx.iimport = nimports; |
| 2874 | try file.calcSymtabSize(self); | 2606 | ctx.stroff = strsize; |
| 2875 | nlocals += ctx.nlocals; | 2607 | nlocals += ctx.nlocals; |
| 2876 | nstabs += ctx.nstabs; | 2608 | nstabs += ctx.nstabs; |
| 2877 | nexports += ctx.nexports; | 2609 | nexports += ctx.nexports; |
| ... | @@ -2889,10 +2621,12 @@ pub fn calcSymtabSize(self: *MachO) !void { | ... | @@ -2889,10 +2621,12 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2889 | ctx.iimport += nlocals + nstabs + nexports; | 2621 | ctx.iimport += nlocals + nstabs + nexports; |
| 2890 | } | 2622 | } |
| 2891 | 2623 | ||
| 2624 | try self.indsymtab.updateSize(self); | ||
| 2625 | |||
| 2892 | { | 2626 | { |
| 2893 | const cmd = &self.symtab_cmd; | 2627 | const cmd = &self.symtab_cmd; |
| 2894 | cmd.nsyms = nlocals + nstabs + nexports + nimports; | 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,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 | fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { | 2643 | fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 2964 | const comp = self.base.comp; | 2644 | const comp = self.base.comp; |
| 2965 | const gpa = comp.gpa; | 2645 | const gpa = comp.gpa; |
| ... | @@ -2999,18 +2679,20 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { | ... | @@ -2999,18 +2679,20 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 2999 | try load_commands.writeDylinkerLC(writer); | 2679 | try load_commands.writeDylinkerLC(writer); |
| 3000 | ncmds += 1; | 2680 | ncmds += 1; |
| 3001 | 2681 | ||
| 3002 | if (self.entry_index) |global_index| { | 2682 | if (self.getInternalObject()) |obj| { |
| 3003 | const sym = self.getSymbol(global_index); | 2683 | if (obj.getEntryRef(self)) |ref| { |
| 3004 | const seg = self.getTextSegment(); | 2684 | const sym = ref.getSymbol(self).?; |
| 3005 | const entryoff: u32 = if (sym.getFile(self) == null) | 2685 | const seg = self.getTextSegment(); |
| 3006 | 0 | 2686 | const entryoff: u32 = if (sym.getFile(self) == null) |
| 3007 | else | 2687 | 0 |
| 3008 | @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr)); | 2688 | else |
| 3009 | try writer.writeStruct(macho.entry_point_command{ | 2689 | @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr)); |
| 3010 | .entryoff = entryoff, | 2690 | try writer.writeStruct(macho.entry_point_command{ |
| 3011 | .stacksize = self.base.stack_size, | 2691 | .entryoff = entryoff, |
| 3012 | }); | 2692 | .stacksize = self.base.stack_size, |
| 3013 | ncmds += 1; | 2693 | }); |
| 2694 | ncmds += 1; | ||
| 2695 | } | ||
| 3014 | } | 2696 | } |
| 3015 | 2697 | ||
| 3016 | if (self.base.isDynLib()) { | 2698 | if (self.base.isDynLib()) { |
| ... | @@ -3919,157 +3601,6 @@ pub fn getFileHandle(self: MachO, index: File.HandleIndex) File.Handle { | ... | @@ -3919,157 +3601,6 @@ pub fn getFileHandle(self: MachO, index: File.HandleIndex) File.Handle { |
| 3919 | return self.file_handles.items[index]; | 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 | pub fn addThunk(self: *MachO) !Thunk.Index { | 3604 | pub fn addThunk(self: *MachO) !Thunk.Index { |
| 4074 | const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); | 3605 | const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); |
| 4075 | const thunk = try self.thunks.addOne(self.base.comp.gpa); | 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,22 +3739,23 @@ pub fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: an |
| 4208 | try err.addNote(self, "please report this as a linker bug on https://github.com/ziglang/zig/issues/new/choose", .{}); | 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 | const tracy = trace(@src()); | 3743 | const tracy = trace(@src()); |
| 4213 | defer tracy.end(); | 3744 | defer tracy.end(); |
| 4214 | 3745 | ||
| 4215 | const max_notes = 3; | 3746 | const max_notes = 3; |
| 4216 | 3747 | ||
| 4217 | var has_dupes = false; | 3748 | var has_dupes = false; |
| 4218 | var it = dupes.iterator(); | 3749 | var it = self.dupes.iterator(); |
| 4219 | while (it.next()) |entry| { | 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 | const notes = entry.value_ptr.*; | 3752 | const notes = entry.value_ptr.*; |
| 4222 | const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); | 3753 | const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); |
| 4223 | 3754 | ||
| 4224 | var err = try self.addErrorWithNotes(nnotes + 1); | 3755 | var err = try self.addErrorWithNotes(nnotes + 1); |
| 4225 | try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.getName(self)}); | 3756 | try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.getName(self)}); |
| 4226 | try err.addNote(self, "defined by {}", .{sym.getFile(self).?.fmtPath()}); | 3757 | try err.addNote(self, "defined by {}", .{sym.getFile(self).?.fmtPath()}); |
| 3758 | has_dupes = true; | ||
| 4227 | 3759 | ||
| 4228 | var inote: usize = 0; | 3760 | var inote: usize = 0; |
| 4229 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { | 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,10 +3767,7 @@ fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMem |
| 4235 | const remaining = notes.items.len - max_notes; | 3767 | const remaining = notes.items.len - max_notes; |
| 4236 | try err.addNote(self, "defined {d} more times", .{remaining}); | 3768 | try err.addNote(self, "defined {d} more times", .{remaining}); |
| 4237 | } | 3769 | } |
| 4238 | |||
| 4239 | has_dupes = true; | ||
| 4240 | } | 3770 | } |
| 4241 | |||
| 4242 | if (has_dupes) return error.HasDuplicates; | 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,15 +3964,18 @@ pub const base_tag: link.File.Tag = link.File.Tag.macho; |
| 4435 | const Section = struct { | 3964 | const Section = struct { |
| 4436 | header: macho.section_64, | 3965 | header: macho.section_64, |
| 4437 | segment_id: u8, | 3966 | segment_id: u8, |
| 4438 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 3967 | atoms: std.ArrayListUnmanaged(Ref) = .{}, |
| 4439 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, | 3968 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 4440 | last_atom_index: Atom.Index = 0, | 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 | pub const LiteralPool = struct { | 3975 | pub const LiteralPool = struct { |
| 4444 | table: std.AutoArrayHashMapUnmanaged(void, void) = .{}, | 3976 | table: std.AutoArrayHashMapUnmanaged(void, void) = .{}, |
| 4445 | keys: std.ArrayListUnmanaged(Key) = .{}, | 3977 | keys: std.ArrayListUnmanaged(Key) = .{}, |
| 4446 | values: std.ArrayListUnmanaged(Atom.Index) = .{}, | 3978 | values: std.ArrayListUnmanaged(MachO.Ref) = .{}, |
| 4447 | data: std.ArrayListUnmanaged(u8) = .{}, | 3979 | data: std.ArrayListUnmanaged(u8) = .{}, |
| 4448 | 3980 | ||
| 4449 | pub fn deinit(lp: *LiteralPool, allocator: Allocator) void { | 3981 | pub fn deinit(lp: *LiteralPool, allocator: Allocator) void { |
| ... | @@ -4453,17 +3985,21 @@ pub const LiteralPool = struct { | ... | @@ -4453,17 +3985,21 @@ pub const LiteralPool = struct { |
| 4453 | lp.data.deinit(allocator); | 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 | const InsertResult = struct { | 3988 | const InsertResult = struct { |
| 4462 | found_existing: bool, | 3989 | found_existing: bool, |
| 4463 | index: Index, | 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 | pub fn insert(lp: *LiteralPool, allocator: Allocator, @"type": u8, string: []const u8) !InsertResult { | 4003 | pub fn insert(lp: *LiteralPool, allocator: Allocator, @"type": u8, string: []const u8) !InsertResult { |
| 4468 | const size: u32 = @intCast(string.len); | 4004 | const size: u32 = @intCast(string.len); |
| 4469 | try lp.data.ensureUnusedCapacity(allocator, size); | 4005 | try lp.data.ensureUnusedCapacity(allocator, size); |
| ... | @@ -4479,7 +4015,7 @@ pub const LiteralPool = struct { | ... | @@ -4479,7 +4015,7 @@ pub const LiteralPool = struct { |
| 4479 | return .{ | 4015 | return .{ |
| 4480 | .found_existing = gop.found_existing, | 4016 | .found_existing = gop.found_existing, |
| 4481 | .index = @intCast(gop.index), | 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,12 +4061,6 @@ const HotUpdateState = struct { |
| 4525 | mach_task: ?std.c.MachTask = null, | 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 | pub const SymtabCtx = struct { | 4064 | pub const SymtabCtx = struct { |
| 4535 | ilocal: u32 = 0, | 4065 | ilocal: u32 = 0, |
| 4536 | istab: u32 = 0, | 4066 | istab: u32 = 0, |
| ... | @@ -4540,6 +4070,7 @@ pub const SymtabCtx = struct { | ... | @@ -4540,6 +4070,7 @@ pub const SymtabCtx = struct { |
| 4540 | nstabs: u32 = 0, | 4070 | nstabs: u32 = 0, |
| 4541 | nexports: u32 = 0, | 4071 | nexports: u32 = 0, |
| 4542 | nimports: u32 = 0, | 4072 | nimports: u32 = 0, |
| 4073 | stroff: u32 = 0, | ||
| 4543 | strsize: u32 = 0, | 4074 | strsize: u32 = 0, |
| 4544 | }; | 4075 | }; |
| 4545 | 4076 | ||
| ... | @@ -4826,6 +4357,136 @@ const UndefinedTreatment = enum { | ... | @@ -4826,6 +4357,136 @@ const UndefinedTreatment = enum { |
| 4826 | dynamic_lookup, | 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 | const MachO = @This(); | 4490 | const MachO = @This(); |
| 4830 | 4491 | ||
| 4831 | const std = @import("std"); | 4492 | const std = @import("std"); |
| ... | @@ -4842,6 +4503,7 @@ const mem = std.mem; | ... | @@ -4842,6 +4503,7 @@ const mem = std.mem; |
| 4842 | const meta = std.meta; | 4503 | const meta = std.meta; |
| 4843 | 4504 | ||
| 4844 | const aarch64 = @import("../arch/aarch64/bits.zig"); | 4505 | const aarch64 = @import("../arch/aarch64/bits.zig"); |
| 4506 | const bind = @import("MachO/dyld_info/bind.zig"); | ||
| 4845 | const calcUuid = @import("MachO/uuid.zig").calcUuid; | 4507 | const calcUuid = @import("MachO/uuid.zig").calcUuid; |
| 4846 | const codegen = @import("../codegen.zig"); | 4508 | const codegen = @import("../codegen.zig"); |
| 4847 | const dead_strip = @import("MachO/dead_strip.zig"); | 4509 | const dead_strip = @import("MachO/dead_strip.zig"); |
| ... | @@ -4862,13 +4524,14 @@ const Alignment = Atom.Alignment; | ... | @@ -4862,13 +4524,14 @@ const Alignment = Atom.Alignment; |
| 4862 | const Allocator = mem.Allocator; | 4524 | const Allocator = mem.Allocator; |
| 4863 | const Archive = @import("MachO/Archive.zig"); | 4525 | const Archive = @import("MachO/Archive.zig"); |
| 4864 | pub const Atom = @import("MachO/Atom.zig"); | 4526 | pub const Atom = @import("MachO/Atom.zig"); |
| 4865 | const BindSection = synthetic.BindSection; | 4527 | const Bind = bind.Bind; |
| 4866 | const Cache = std.Build.Cache; | 4528 | const Cache = std.Build.Cache; |
| 4867 | const CodeSignature = @import("MachO/CodeSignature.zig"); | 4529 | const CodeSignature = @import("MachO/CodeSignature.zig"); |
| 4868 | const Compilation = @import("../Compilation.zig"); | 4530 | const Compilation = @import("../Compilation.zig"); |
| 4531 | const DataInCode = synthetic.DataInCode; | ||
| 4869 | pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); | 4532 | pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 4870 | const Dylib = @import("MachO/Dylib.zig"); | 4533 | const Dylib = @import("MachO/Dylib.zig"); |
| 4871 | const ExportTrieSection = synthetic.ExportTrieSection; | 4534 | const ExportTrie = @import("MachO/dyld_info/Trie.zig"); |
| 4872 | const File = @import("MachO/file.zig").File; | 4535 | const File = @import("MachO/file.zig").File; |
| 4873 | const GotSection = synthetic.GotSection; | 4536 | const GotSection = synthetic.GotSection; |
| 4874 | const Hash = std.hash.Wyhash; | 4537 | const Hash = std.hash.Wyhash; |
| ... | @@ -4876,7 +4539,7 @@ const Indsymtab = synthetic.Indsymtab; | ... | @@ -4876,7 +4539,7 @@ const Indsymtab = synthetic.Indsymtab; |
| 4876 | const InternalObject = @import("MachO/InternalObject.zig"); | 4539 | const InternalObject = @import("MachO/InternalObject.zig"); |
| 4877 | const ObjcStubsSection = synthetic.ObjcStubsSection; | 4540 | const ObjcStubsSection = synthetic.ObjcStubsSection; |
| 4878 | const Object = @import("MachO/Object.zig"); | 4541 | const Object = @import("MachO/Object.zig"); |
| 4879 | const LazyBindSection = synthetic.LazyBindSection; | 4542 | const LazyBind = bind.LazyBind; |
| 4880 | const LaSymbolPtrSection = synthetic.LaSymbolPtrSection; | 4543 | const LaSymbolPtrSection = synthetic.LaSymbolPtrSection; |
| 4881 | const LibStub = tapi.LibStub; | 4544 | const LibStub = tapi.LibStub; |
| 4882 | const Liveness = @import("../Liveness.zig"); | 4545 | const Liveness = @import("../Liveness.zig"); |
| ... | @@ -4886,7 +4549,7 @@ const Zcu = @import("../Zcu.zig"); | ... | @@ -4886,7 +4549,7 @@ const Zcu = @import("../Zcu.zig"); |
| 4886 | /// Deprecated. | 4549 | /// Deprecated. |
| 4887 | const Module = Zcu; | 4550 | const Module = Zcu; |
| 4888 | const InternPool = @import("../InternPool.zig"); | 4551 | const InternPool = @import("../InternPool.zig"); |
| 4889 | const RebaseSection = synthetic.RebaseSection; | 4552 | const Rebase = @import("MachO/dyld_info/Rebase.zig"); |
| 4890 | pub const Relocation = @import("MachO/Relocation.zig"); | 4553 | pub const Relocation = @import("MachO/Relocation.zig"); |
| 4891 | const StringTable = @import("StringTable.zig"); | 4554 | const StringTable = @import("StringTable.zig"); |
| 4892 | const StubsSection = synthetic.StubsSection; | 4555 | const StubsSection = synthetic.StubsSection; |
| ... | @@ -4896,6 +4559,6 @@ const Thunk = thunks.Thunk; | ... | @@ -4896,6 +4559,6 @@ const Thunk = thunks.Thunk; |
| 4896 | const TlvPtrSection = synthetic.TlvPtrSection; | 4559 | const TlvPtrSection = synthetic.TlvPtrSection; |
| 4897 | const Value = @import("../Value.zig"); | 4560 | const Value = @import("../Value.zig"); |
| 4898 | const UnwindInfo = @import("MachO/UnwindInfo.zig"); | 4561 | const UnwindInfo = @import("MachO/UnwindInfo.zig"); |
| 4899 | const WeakBindSection = synthetic.WeakBindSection; | 4562 | const WeakBind = bind.WeakBind; |
| 4900 | const ZigGotSection = synthetic.ZigGotSection; | 4563 | const ZigGotSection = synthetic.ZigGotSection; |
| 4901 | const ZigObject = @import("MachO/ZigObject.zig"); | 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,9 +67,9 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: |
| 67 | mem.eql(u8, name, SYMDEF64_SORTED)) continue; | 67 | mem.eql(u8, name, SYMDEF64_SORTED)) continue; |
| 68 | 68 | ||
| 69 | const object = Object{ | 69 | const object = Object{ |
| 70 | .archive = .{ | 70 | .offset = pos, |
| 71 | .in_archive = .{ | ||
| 71 | .path = try gpa.dupe(u8, path), | 72 | .path = try gpa.dupe(u8, path), |
| 72 | .offset = pos, | ||
| 73 | .size = hdr_size, | 73 | .size = hdr_size, |
| 74 | }, | 74 | }, |
| 75 | .path = try gpa.dupe(u8, name), | 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,16 +47,6 @@ pub fn getFile(self: Atom, macho_file: *MachO) File { |
| 47 | return macho_file.getFile(self.file).?; | 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 | pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation { | 50 | pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation { |
| 61 | return switch (self.getFile(macho_file)) { | 51 | return switch (self.getFile(macho_file)) { |
| 62 | .dylib => unreachable, | 52 | .dylib => unreachable, |
| ... | @@ -88,17 +78,18 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 { | ... | @@ -88,17 +78,18 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 { |
| 88 | } | 78 | } |
| 89 | 79 | ||
| 90 | pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index { | 80 | pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index { |
| 91 | if (!self.flags.unwind) return &[0]UnwindInfo.Record.Index{}; | 81 | const extra = self.getExtra(macho_file); |
| 92 | const extra = self.getExtra(macho_file).?; | ||
| 93 | return switch (self.getFile(macho_file)) { | 82 | return switch (self.getFile(macho_file)) { |
| 94 | .dylib, .zig_object, .internal => unreachable, | 83 | .dylib => unreachable, |
| 95 | .object => |x| x.unwind_records.items[extra.unwind_index..][0..extra.unwind_count], | 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 | pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { | 89 | pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { |
| 90 | const object = self.getFile(macho_file).object; | ||
| 100 | for (self.getUnwindRecords(macho_file)) |cu_index| { | 91 | for (self.getUnwindRecords(macho_file)) |cu_index| { |
| 101 | const cu = macho_file.getUnwindRecord(cu_index); | 92 | const cu = object.getUnwindRecord(cu_index); |
| 102 | cu.alive = false; | 93 | cu.alive = false; |
| 103 | 94 | ||
| 104 | if (cu.getFdePtr(macho_file)) |fde| { | 95 | if (cu.getFdePtr(macho_file)) |fde| { |
| ... | @@ -108,44 +99,39 @@ pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { | ... | @@ -108,44 +99,39 @@ pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { |
| 108 | } | 99 | } |
| 109 | 100 | ||
| 110 | pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { | 101 | pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { |
| 111 | assert(self.flags.thunk); | 102 | const extra = self.getExtra(macho_file); |
| 112 | const extra = self.getExtra(macho_file).?; | ||
| 113 | return macho_file.getThunk(extra.thunk); | 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 | const AddExtraOpts = struct { | 106 | const AddExtraOpts = struct { |
| 122 | thunk: ?u32 = null, | 107 | thunk: ?u32 = null, |
| 123 | rel_index: ?u32 = null, | 108 | rel_index: ?u32 = null, |
| 124 | rel_count: ?u32 = null, | 109 | rel_count: ?u32 = null, |
| 110 | rel_out_index: ?u32 = null, | ||
| 111 | rel_out_count: ?u32 = null, | ||
| 125 | unwind_index: ?u32 = null, | 112 | unwind_index: ?u32 = null, |
| 126 | unwind_count: ?u32 = null, | 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 { | 118 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) void { |
| 131 | if (atom.getExtra(macho_file) == null) { | 119 | const file = atom.getFile(macho_file); |
| 132 | atom.extra = try macho_file.addAtomExtra(.{}); | 120 | var extra = file.getAtomExtra(atom.extra); |
| 133 | } | ||
| 134 | var extra = atom.getExtra(macho_file).?; | ||
| 135 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { | 121 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { |
| 136 | if (@field(opts, field.name)) |x| { | 122 | if (@field(opts, field.name)) |x| { |
| 137 | @field(extra, field.name) = x; | 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 { | 129 | pub inline fn getExtra(atom: Atom, macho_file: *MachO) Extra { |
| 144 | return macho_file.getAtomExtra(atom.extra); | 130 | return atom.getFile(macho_file).getAtomExtra(atom.extra); |
| 145 | } | 131 | } |
| 146 | 132 | ||
| 147 | pub inline fn setExtra(atom: Atom, extra: Extra, macho_file: *MachO) void { | 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 | pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { | 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,7 +213,8 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 { |
| 227 | /// File offset relocation happens transparently, so it is not included in | 213 | /// File offset relocation happens transparently, so it is not included in |
| 228 | /// this calculation. | 214 | /// this calculation. |
| 229 | pub fn capacity(self: Atom, macho_file: *MachO) u64 { | 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 | next.getAddress(macho_file) | 218 | next.getAddress(macho_file) |
| 232 | else | 219 | else |
| 233 | std.math.maxInt(u32); | 220 | std.math.maxInt(u32); |
| ... | @@ -236,7 +223,8 @@ pub fn capacity(self: Atom, macho_file: *MachO) u64 { | ... | @@ -236,7 +223,8 @@ pub fn capacity(self: Atom, macho_file: *MachO) u64 { |
| 236 | 223 | ||
| 237 | pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { | 224 | pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { |
| 238 | // No need to keep a free list node for the last block. | 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 | const cap = next.getAddress(macho_file) - self.getAddress(macho_file); | 228 | const cap = next.getAddress(macho_file) - self.getAddress(macho_file); |
| 241 | const ideal_cap = MachO.padToIdeal(self.size); | 229 | const ideal_cap = MachO.padToIdeal(self.size); |
| 242 | if (cap <= ideal_cap) return false; | 230 | if (cap <= ideal_cap) return false; |
| ... | @@ -245,6 +233,7 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { | ... | @@ -245,6 +233,7 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool { |
| 245 | } | 233 | } |
| 246 | 234 | ||
| 247 | pub fn allocate(self: *Atom, macho_file: *MachO) !void { | 235 | pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 236 | const zo = macho_file.getZigObject().?; | ||
| 248 | const sect = &macho_file.sections.items(.header)[self.out_n_sect]; | 237 | const sect = &macho_file.sections.items(.header)[self.out_n_sect]; |
| 249 | const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect]; | 238 | const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect]; |
| 250 | const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect]; | 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,7 +253,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 264 | var i: usize = free_list.items.len; | 253 | var i: usize = free_list.items.len; |
| 265 | while (i < free_list.items.len) { | 254 | while (i < free_list.items.len) { |
| 266 | const big_atom_index = free_list.items[i]; | 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 | // We now have a pointer to a live atom that has too much capacity. | 257 | // We now have a pointer to a live atom that has too much capacity. |
| 269 | // Is it enough that we could fit this new atom? | 258 | // Is it enough that we could fit this new atom? |
| 270 | const cap = big_atom.capacity(macho_file); | 259 | const cap = big_atom.capacity(macho_file); |
| ... | @@ -296,7 +285,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { | ... | @@ -296,7 +285,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 296 | free_list_removal = i; | 285 | free_list_removal = i; |
| 297 | } | 286 | } |
| 298 | break :blk new_start_vaddr; | 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 | const ideal_capacity = MachO.padToIdeal(last.size); | 289 | const ideal_capacity = MachO.padToIdeal(last.size); |
| 301 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; | 290 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; |
| 302 | const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); | 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,7 +305,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 316 | }); | 305 | }); |
| 317 | 306 | ||
| 318 | const expand_section = if (atom_placement) |placement_index| | 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 | else | 309 | else |
| 321 | true; | 310 | true; |
| 322 | if (expand_section) { | 311 | if (expand_section) { |
| ... | @@ -341,15 +330,15 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { | ... | @@ -341,15 +330,15 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { |
| 341 | // This function can also reallocate an atom. | 330 | // This function can also reallocate an atom. |
| 342 | // In this case we need to "unplug" it from its previous location before | 331 | // In this case we need to "unplug" it from its previous location before |
| 343 | // plugging it in to its new location. | 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 | prev.next_index = self.next_index; | 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 | next.prev_index = self.prev_index; | 337 | next.prev_index = self.prev_index; |
| 349 | } | 338 | } |
| 350 | 339 | ||
| 351 | if (atom_placement) |big_atom_index| { | 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 | self.prev_index = big_atom_index; | 342 | self.prev_index = big_atom_index; |
| 354 | self.next_index = big_atom.next_index; | 343 | self.next_index = big_atom.next_index; |
| 355 | big_atom.next_index = self.atom_index; | 344 | big_atom.next_index = self.atom_index; |
| ... | @@ -379,6 +368,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void { | ... | @@ -379,6 +368,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void { |
| 379 | 368 | ||
| 380 | const comp = macho_file.base.comp; | 369 | const comp = macho_file.base.comp; |
| 381 | const gpa = comp.gpa; | 370 | const gpa = comp.gpa; |
| 371 | const zo = macho_file.getZigObject().?; | ||
| 382 | const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect]; | 372 | const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect]; |
| 383 | const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect]; | 373 | const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect]; |
| 384 | var already_have_free_list_node = false; | 374 | var already_have_free_list_node = false; |
| ... | @@ -397,9 +387,9 @@ pub fn free(self: *Atom, macho_file: *MachO) void { | ... | @@ -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 | if (last_atom.atom_index == self.atom_index) { | 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 | // TODO shrink the section size here | 393 | // TODO shrink the section size here |
| 404 | last_atom_index.* = self.prev_index; | 394 | last_atom_index.* = self.prev_index; |
| 405 | } else { | 395 | } else { |
| ... | @@ -408,7 +398,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void { | ... | @@ -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 | prev.next_index = self.next_index; | 402 | prev.next_index = self.next_index; |
| 413 | if (!already_have_free_list_node and prev.*.freeListEligible(macho_file)) { | 403 | if (!already_have_free_list_node and prev.*.freeListEligible(macho_file)) { |
| 414 | // The free list is heuristics, it doesn't have to be perfect, so we can | 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,7 +409,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void { |
| 419 | self.prev_index = 0; | 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 | next.prev_index = self.prev_index; | 413 | next.prev_index = self.prev_index; |
| 424 | } else { | 414 | } else { |
| 425 | self.next_index = 0; | 415 | self.next_index = 0; |
| ... | @@ -437,8 +427,7 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void { | ... | @@ -437,8 +427,7 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void { |
| 437 | const gpa = macho_file.base.comp.gpa; | 427 | const gpa = macho_file.base.comp.gpa; |
| 438 | const file = self.getFile(macho_file); | 428 | const file = self.getFile(macho_file); |
| 439 | assert(file == .zig_object); | 429 | assert(file == .zig_object); |
| 440 | assert(self.flags.relocs); | 430 | var extra = self.getExtra(macho_file); |
| 441 | var extra = self.getExtra(macho_file).?; | ||
| 442 | const rels = &file.zig_object.relocs.items[extra.rel_index]; | 431 | const rels = &file.zig_object.relocs.items[extra.rel_index]; |
| 443 | try rels.append(gpa, reloc); | 432 | try rels.append(gpa, reloc); |
| 444 | extra.rel_count += 1; | 433 | extra.rel_count += 1; |
| ... | @@ -446,9 +435,8 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void { | ... | @@ -446,9 +435,8 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void { |
| 446 | } | 435 | } |
| 447 | 436 | ||
| 448 | pub fn freeRelocs(self: *Atom, macho_file: *MachO) void { | 437 | pub fn freeRelocs(self: *Atom, macho_file: *MachO) void { |
| 449 | if (!self.flags.relocs) return; | ||
| 450 | self.getFile(macho_file).zig_object.freeAtomRelocs(self.*, macho_file); | 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 | extra.rel_count = 0; | 440 | extra.rel_count = 0; |
| 453 | self.setExtra(extra, macho_file); | 441 | self.setExtra(extra, macho_file); |
| 454 | } | 442 | } |
| ... | @@ -458,11 +446,6 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { | ... | @@ -458,11 +446,6 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 458 | defer tracy.end(); | 446 | defer tracy.end(); |
| 459 | assert(self.flags.alive); | 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 | const relocs = self.getRelocs(macho_file); | 449 | const relocs = self.getRelocs(macho_file); |
| 467 | 450 | ||
| 468 | for (relocs) |rel| { | 451 | for (relocs) |rel| { |
| ... | @@ -470,7 +453,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { | ... | @@ -470,7 +453,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 470 | 453 | ||
| 471 | switch (rel.type) { | 454 | switch (rel.type) { |
| 472 | .branch => { | 455 | .branch => { |
| 473 | const symbol = rel.getTargetSymbol(macho_file); | 456 | const symbol = rel.getTargetSymbol(self, macho_file); |
| 474 | if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) { | 457 | if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) { |
| 475 | symbol.flags.stubs = true; | 458 | symbol.flags.stubs = true; |
| 476 | if (symbol.flags.weak) { | 459 | if (symbol.flags.weak) { |
| ... | @@ -485,7 +468,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { | ... | @@ -485,7 +468,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 485 | .got_load_page, | 468 | .got_load_page, |
| 486 | .got_load_pageoff, | 469 | .got_load_pageoff, |
| 487 | => { | 470 | => { |
| 488 | const symbol = rel.getTargetSymbol(macho_file); | 471 | const symbol = rel.getTargetSymbol(self, macho_file); |
| 489 | if (symbol.flags.import or | 472 | if (symbol.flags.import or |
| 490 | (symbol.flags.@"export" and symbol.flags.weak) or | 473 | (symbol.flags.@"export" and symbol.flags.weak) or |
| 491 | symbol.flags.interposable or | 474 | symbol.flags.interposable or |
| ... | @@ -499,18 +482,18 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { | ... | @@ -499,18 +482,18 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 499 | }, | 482 | }, |
| 500 | 483 | ||
| 501 | .zig_got_load => { | 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 | .got => { | 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 | .tlv, | 492 | .tlv, |
| 510 | .tlvp_page, | 493 | .tlvp_page, |
| 511 | .tlvp_pageoff, | 494 | .tlvp_pageoff, |
| 512 | => { | 495 | => { |
| 513 | const symbol = rel.getTargetSymbol(macho_file); | 496 | const symbol = rel.getTargetSymbol(self, macho_file); |
| 514 | if (!symbol.flags.tlv) { | 497 | if (!symbol.flags.tlv) { |
| 515 | try macho_file.reportParseError2( | 498 | try macho_file.reportParseError2( |
| 516 | self.getFile(macho_file).getIndex(), | 499 | self.getFile(macho_file).getIndex(), |
| ... | @@ -529,27 +512,21 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { | ... | @@ -529,27 +512,21 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 529 | .unsigned => { | 512 | .unsigned => { |
| 530 | if (rel.meta.length == 3) { // TODO this really should check if this is pointer width | 513 | if (rel.meta.length == 3) { // TODO this really should check if this is pointer width |
| 531 | if (rel.tag == .@"extern") { | 514 | if (rel.tag == .@"extern") { |
| 532 | const symbol = rel.getTargetSymbol(macho_file); | 515 | const symbol = rel.getTargetSymbol(self, macho_file); |
| 533 | if (symbol.isTlvInit(macho_file)) { | 516 | if (symbol.isTlvInit(macho_file)) { |
| 534 | macho_file.has_tlv = true; | 517 | macho_file.has_tlv = true; |
| 535 | continue; | 518 | continue; |
| 536 | } | 519 | } |
| 537 | if (symbol.flags.import) { | 520 | if (symbol.flags.import) { |
| 538 | dynrel_ctx.bind_relocs += 1; | ||
| 539 | if (symbol.flags.weak) { | 521 | if (symbol.flags.weak) { |
| 540 | dynrel_ctx.weak_bind_relocs += 1; | ||
| 541 | macho_file.binds_to_weak = true; | 522 | macho_file.binds_to_weak = true; |
| 542 | } | 523 | } |
| 543 | continue; | 524 | continue; |
| 544 | } | 525 | } |
| 545 | if (symbol.flags.@"export" and symbol.flags.weak) { | 526 | if (symbol.flags.@"export" and symbol.flags.weak) { |
| 546 | dynrel_ctx.weak_bind_relocs += 1; | ||
| 547 | macho_file.binds_to_weak = true; | 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,14 +545,15 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { |
| 568 | fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool { | 545 | fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool { |
| 569 | if (rel.tag == .local) return false; | 546 | if (rel.tag == .local) return false; |
| 570 | 547 | ||
| 571 | const sym = rel.getTargetSymbol(macho_file); | 548 | const file = self.getFile(macho_file); |
| 572 | if (sym.getFile(macho_file) == null) { | 549 | const ref = file.getSymbolRef(rel.target, macho_file); |
| 550 | if (ref.getFile(macho_file) == null) { | ||
| 573 | const gpa = macho_file.base.comp.gpa; | 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 | if (!gop.found_existing) { | 553 | if (!gop.found_existing) { |
| 576 | gop.value_ptr.* = .{}; | 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 | return true; | 557 | return true; |
| 580 | } | 558 | } |
| 581 | 559 | ||
| ... | @@ -591,7 +569,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { | ... | @@ -591,7 +569,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 591 | const name = self.getName(macho_file); | 569 | const name = self.getName(macho_file); |
| 592 | const relocs = self.getRelocs(macho_file); | 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 | var has_error = false; | 574 | var has_error = false; |
| 597 | var stream = std.io.fixedBufferStream(buffer); | 575 | var stream = std.io.fixedBufferStream(buffer); |
| ... | @@ -602,7 +580,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { | ... | @@ -602,7 +580,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 602 | const subtractor = if (rel.meta.has_subtractor) relocs[i - 1] else null; | 580 | const subtractor = if (rel.meta.has_subtractor) relocs[i - 1] else null; |
| 603 | 581 | ||
| 604 | if (rel.tag == .@"extern") { | 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 | try stream.seekTo(rel_offset); | 586 | try stream.seekTo(rel_offset); |
| ... | @@ -610,13 +588,19 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { | ... | @@ -610,13 +588,19 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 610 | switch (err) { | 588 | switch (err) { |
| 611 | error.RelaxFail => { | 589 | error.RelaxFail => { |
| 612 | const target = switch (rel.tag) { | 590 | const target = switch (rel.tag) { |
| 613 | .@"extern" => rel.getTargetSymbol(macho_file).getName(macho_file), | 591 | .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file), |
| 614 | .local => rel.getTargetAtom(macho_file).getName(macho_file), | 592 | .local => rel.getTargetAtom(self, macho_file).getName(macho_file), |
| 615 | }; | 593 | }; |
| 616 | try macho_file.reportParseError2( | 594 | try macho_file.reportParseError2( |
| 617 | file.getIndex(), | 595 | file.getIndex(), |
| 618 | "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {s}, target {s}", | 596 | "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}", |
| 619 | .{ name, self.getAddress(macho_file), rel.offset, @tagName(rel.type), target }, | 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 | has_error = true; | 605 | has_error = true; |
| 622 | }, | 606 | }, |
| ... | @@ -649,14 +633,12 @@ fn resolveRelocInner( | ... | @@ -649,14 +633,12 @@ fn resolveRelocInner( |
| 649 | ) ResolveError!void { | 633 | ) ResolveError!void { |
| 650 | const cpu_arch = macho_file.getTarget().cpu.arch; | 634 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 651 | const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; | 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 | const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset)); | 636 | const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset)); |
| 655 | const A = rel.addend + rel.getRelocAddend(cpu_arch); | 637 | const A = rel.addend + rel.getRelocAddend(cpu_arch); |
| 656 | const S: i64 = @intCast(rel.getTargetAddress(macho_file)); | 638 | const S: i64 = @intCast(rel.getTargetAddress(self, macho_file)); |
| 657 | const G: i64 = @intCast(rel.getGotTargetAddress(macho_file)); | 639 | const G: i64 = @intCast(rel.getGotTargetAddress(self, macho_file)); |
| 658 | const TLS = @as(i64, @intCast(macho_file.getTlsAddress())); | 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 | // Address of the __got_zig table entry if any. | 642 | // Address of the __got_zig table entry if any. |
| 661 | const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(macho_file))); | 643 | const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(macho_file))); |
| 662 | 644 | ||
| ... | @@ -674,21 +656,21 @@ fn resolveRelocInner( | ... | @@ -674,21 +656,21 @@ fn resolveRelocInner( |
| 674 | }.divExact; | 656 | }.divExact; |
| 675 | 657 | ||
| 676 | switch (rel.tag) { | 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 | P, | 660 | P, |
| 679 | rel_offset, | 661 | rel_offset, |
| 680 | @tagName(rel.type), | 662 | rel.fmtPretty(cpu_arch), |
| 681 | S + A - SUB, | 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 | P, | 667 | P, |
| 686 | rel_offset, | 668 | rel_offset, |
| 687 | @tagName(rel.type), | 669 | rel.fmtPretty(cpu_arch), |
| 688 | S + A - SUB, | 670 | S + A - SUB, |
| 689 | G + A, | 671 | G + A, |
| 690 | ZIG_GOT + A, | 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,34 +681,13 @@ fn resolveRelocInner( |
| 699 | assert(!rel.meta.pcrel); | 681 | assert(!rel.meta.pcrel); |
| 700 | if (rel.meta.length == 3) { | 682 | if (rel.meta.length == 3) { |
| 701 | if (rel.tag == .@"extern") { | 683 | if (rel.tag == .@"extern") { |
| 702 | const sym = rel.getTargetSymbol(macho_file); | 684 | const sym = rel.getTargetSymbol(self, macho_file); |
| 703 | if (sym.isTlvInit(macho_file)) { | 685 | if (sym.isTlvInit(macho_file)) { |
| 704 | try writer.writeInt(u64, @intCast(S - TLS), .little); | 686 | try writer.writeInt(u64, @intCast(S - TLS), .little); |
| 705 | return; | 687 | return; |
| 706 | } | 688 | } |
| 707 | const entry = bind.Entry{ | 689 | if (sym.flags.import) return; |
| 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 | } | ||
| 725 | } | 690 | } |
| 726 | macho_file.rebase.entries.appendAssumeCapacity(.{ | ||
| 727 | .offset = @as(u64, @intCast(P)) - seg.vmaddr, | ||
| 728 | .segment_id = seg_id, | ||
| 729 | }); | ||
| 730 | try writer.writeInt(u64, @bitCast(S + A - SUB), .little); | 691 | try writer.writeInt(u64, @bitCast(S + A - SUB), .little); |
| 731 | } else if (rel.meta.length == 2) { | 692 | } else if (rel.meta.length == 2) { |
| 732 | try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little); | 693 | try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little); |
| ... | @@ -750,7 +711,7 @@ fn resolveRelocInner( | ... | @@ -750,7 +711,7 @@ fn resolveRelocInner( |
| 750 | .aarch64 => { | 711 | .aarch64 => { |
| 751 | const disp: i28 = math.cast(i28, S + A - P) orelse blk: { | 712 | const disp: i28 = math.cast(i28, S + A - P) orelse blk: { |
| 752 | const thunk = self.getThunk(macho_file); | 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 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; | 715 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; |
| 755 | }; | 716 | }; |
| 756 | aarch64.writeBranchImm(disp, code[rel_offset..][0..4]); | 717 | aarch64.writeBranchImm(disp, code[rel_offset..][0..4]); |
| ... | @@ -763,7 +724,7 @@ fn resolveRelocInner( | ... | @@ -763,7 +724,7 @@ fn resolveRelocInner( |
| 763 | assert(rel.tag == .@"extern"); | 724 | assert(rel.tag == .@"extern"); |
| 764 | assert(rel.meta.length == 2); | 725 | assert(rel.meta.length == 2); |
| 765 | assert(rel.meta.pcrel); | 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 | try writer.writeInt(i32, @intCast(G + A - P), .little); | 728 | try writer.writeInt(i32, @intCast(G + A - P), .little); |
| 768 | } else { | 729 | } else { |
| 769 | try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file); | 730 | try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file); |
| ... | @@ -786,7 +747,7 @@ fn resolveRelocInner( | ... | @@ -786,7 +747,7 @@ fn resolveRelocInner( |
| 786 | assert(rel.tag == .@"extern"); | 747 | assert(rel.tag == .@"extern"); |
| 787 | assert(rel.meta.length == 2); | 748 | assert(rel.meta.length == 2); |
| 788 | assert(rel.meta.pcrel); | 749 | assert(rel.meta.pcrel); |
| 789 | const sym = rel.getTargetSymbol(macho_file); | 750 | const sym = rel.getTargetSymbol(self, macho_file); |
| 790 | if (sym.flags.tlv_ptr) { | 751 | if (sym.flags.tlv_ptr) { |
| 791 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); | 752 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); |
| 792 | try writer.writeInt(i32, @intCast(S_ + A - P), .little); | 753 | try writer.writeInt(i32, @intCast(S_ + A - P), .little); |
| ... | @@ -809,7 +770,7 @@ fn resolveRelocInner( | ... | @@ -809,7 +770,7 @@ fn resolveRelocInner( |
| 809 | assert(rel.tag == .@"extern"); | 770 | assert(rel.tag == .@"extern"); |
| 810 | assert(rel.meta.length == 2); | 771 | assert(rel.meta.length == 2); |
| 811 | assert(rel.meta.pcrel); | 772 | assert(rel.meta.pcrel); |
| 812 | const sym = rel.getTargetSymbol(macho_file); | 773 | const sym = rel.getTargetSymbol(self, macho_file); |
| 813 | const source = math.cast(u64, P) orelse return error.Overflow; | 774 | const source = math.cast(u64, P) orelse return error.Overflow; |
| 814 | const target = target: { | 775 | const target = target: { |
| 815 | const target = switch (rel.type) { | 776 | const target = switch (rel.type) { |
| ... | @@ -868,7 +829,7 @@ fn resolveRelocInner( | ... | @@ -868,7 +829,7 @@ fn resolveRelocInner( |
| 868 | assert(rel.meta.length == 2); | 829 | assert(rel.meta.length == 2); |
| 869 | assert(!rel.meta.pcrel); | 830 | assert(!rel.meta.pcrel); |
| 870 | 831 | ||
| 871 | const sym = rel.getTargetSymbol(macho_file); | 832 | const sym = rel.getTargetSymbol(self, macho_file); |
| 872 | const target = target: { | 833 | const target = target: { |
| 873 | const target = if (sym.flags.tlv_ptr) blk: { | 834 | const target = if (sym.flags.tlv_ptr) blk: { |
| 874 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); | 835 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); |
| ... | @@ -945,11 +906,11 @@ const x86_64 = struct { | ... | @@ -945,11 +906,11 @@ const x86_64 = struct { |
| 945 | }, | 906 | }, |
| 946 | else => |x| { | 907 | else => |x| { |
| 947 | var err = try macho_file.addErrorWithNotes(2); | 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 | self.getName(macho_file), | 910 | self.getName(macho_file), |
| 950 | self.getAddress(macho_file), | 911 | self.getAddress(macho_file), |
| 951 | rel.offset, | 912 | rel.offset, |
| 952 | @tagName(rel.type), | 913 | rel.fmtPretty(.x86_64), |
| 953 | }); | 914 | }); |
| 954 | try err.addNote(macho_file, "expected .mov instruction but found .{s}", .{@tagName(x)}); | 915 | try err.addNote(macho_file, "expected .mov instruction but found .{s}", .{@tagName(x)}); |
| 955 | try err.addNote(macho_file, "while parsing {}", .{self.getFile(macho_file).fmtPath()}); | 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,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 | const tracy = trace(@src()); | 977 | const tracy = trace(@src()); |
| 1017 | defer tracy.end(); | 978 | defer tracy.end(); |
| 1018 | 979 | ||
| 1019 | const cpu_arch = macho_file.getTarget().cpu.arch; | 980 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 1020 | const relocs = self.getRelocs(macho_file); | 981 | const relocs = self.getRelocs(macho_file); |
| 1021 | var stream = std.io.fixedBufferStream(code); | ||
| 1022 | 982 | ||
| 983 | var i: usize = 0; | ||
| 1023 | for (relocs) |rel| { | 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 | const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow; | 987 | const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow; |
| 988 | assert(r_address >= 0); | ||
| 1026 | const r_symbolnum = r_symbolnum: { | 989 | const r_symbolnum = r_symbolnum: { |
| 1027 | const r_symbolnum: u32 = switch (rel.tag) { | 990 | const r_symbolnum: u32 = switch (rel.tag) { |
| 1028 | .local => rel.getTargetAtom(macho_file).out_n_sect + 1, | 991 | .local => rel.getTargetAtom(self, macho_file).out_n_sect + 1, |
| 1029 | .@"extern" => rel.getTargetSymbol(macho_file).getOutputSymtabIndex(macho_file).?, | 992 | .@"extern" => rel.getTargetSymbol(self, macho_file).getOutputSymtabIndex(macho_file).?, |
| 1030 | }; | 993 | }; |
| 1031 | break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow; | 994 | break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow; |
| 1032 | }; | 995 | }; |
| 1033 | const r_extern = rel.tag == .@"extern"; | 996 | const r_extern = rel.tag == .@"extern"; |
| 1034 | var addend = rel.addend + rel.getRelocAddend(cpu_arch); | 997 | var addend = rel.addend + rel.getRelocAddend(cpu_arch); |
| 1035 | if (rel.tag == .local) { | 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 | addend += target; | 1000 | addend += target; |
| 1038 | } | 1001 | } |
| 1039 | 1002 | ||
| 1040 | try stream.seekTo(rel_offset); | ||
| 1041 | |||
| 1042 | switch (cpu_arch) { | 1003 | switch (cpu_arch) { |
| 1043 | .aarch64 => { | 1004 | .aarch64 => { |
| 1044 | if (rel.type == .unsigned) switch (rel.meta.length) { | 1005 | if (rel.type == .unsigned) switch (rel.meta.length) { |
| 1045 | 0, 1 => unreachable, | 1006 | 0, 1 => unreachable, |
| 1046 | 2 => try stream.writer().writeInt(i32, @truncate(addend), .little), | 1007 | 2 => mem.writeInt(i32, code[rel_offset..][0..4], @truncate(addend), .little), |
| 1047 | 3 => try stream.writer().writeInt(i64, addend, .little), | 1008 | 3 => mem.writeInt(i64, code[rel_offset..][0..8], addend, .little), |
| 1048 | } else if (addend > 0) { | 1009 | } else if (addend > 0) { |
| 1049 | buffer.appendAssumeCapacity(.{ | 1010 | buffer[i] = .{ |
| 1050 | .r_address = r_address, | 1011 | .r_address = r_address, |
| 1051 | .r_symbolnum = @bitCast(math.cast(i24, addend) orelse return error.Overflow), | 1012 | .r_symbolnum = @bitCast(math.cast(i24, addend) orelse return error.Overflow), |
| 1052 | .r_pcrel = 0, | 1013 | .r_pcrel = 0, |
| 1053 | .r_length = 2, | 1014 | .r_length = 2, |
| 1054 | .r_extern = 0, | 1015 | .r_extern = 0, |
| 1055 | .r_type = @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_ADDEND), | 1016 | .r_type = @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_ADDEND), |
| 1056 | }); | 1017 | }; |
| 1018 | i += 1; | ||
| 1057 | } | 1019 | } |
| 1058 | 1020 | ||
| 1059 | const r_type: macho.reloc_type_arm64 = switch (rel.type) { | 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,14 +1039,14 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1077 | .tlv, | 1039 | .tlv, |
| 1078 | => unreachable, | 1040 | => unreachable, |
| 1079 | }; | 1041 | }; |
| 1080 | buffer.appendAssumeCapacity(.{ | 1042 | buffer[i] = .{ |
| 1081 | .r_address = r_address, | 1043 | .r_address = r_address, |
| 1082 | .r_symbolnum = r_symbolnum, | 1044 | .r_symbolnum = r_symbolnum, |
| 1083 | .r_pcrel = @intFromBool(rel.meta.pcrel), | 1045 | .r_pcrel = @intFromBool(rel.meta.pcrel), |
| 1084 | .r_extern = @intFromBool(r_extern), | 1046 | .r_extern = @intFromBool(r_extern), |
| 1085 | .r_length = rel.meta.length, | 1047 | .r_length = rel.meta.length, |
| 1086 | .r_type = @intFromEnum(r_type), | 1048 | .r_type = @intFromEnum(r_type), |
| 1087 | }); | 1049 | }; |
| 1088 | }, | 1050 | }, |
| 1089 | .x86_64 => { | 1051 | .x86_64 => { |
| 1090 | if (rel.meta.pcrel) { | 1052 | if (rel.meta.pcrel) { |
| ... | @@ -1096,8 +1058,8 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra | ... | @@ -1096,8 +1058,8 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1096 | } | 1058 | } |
| 1097 | switch (rel.meta.length) { | 1059 | switch (rel.meta.length) { |
| 1098 | 0, 1 => unreachable, | 1060 | 0, 1 => unreachable, |
| 1099 | 2 => try stream.writer().writeInt(i32, @truncate(addend), .little), | 1061 | 2 => mem.writeInt(i32, code[rel_offset..][0..4], @truncate(addend), .little), |
| 1100 | 3 => try stream.writer().writeInt(i64, addend, .little), | 1062 | 3 => mem.writeInt(i64, code[rel_offset..][0..8], addend, .little), |
| 1101 | } | 1063 | } |
| 1102 | 1064 | ||
| 1103 | const r_type: macho.reloc_type_x86_64 = switch (rel.type) { | 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,18 +1083,20 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra |
| 1121 | .tlvp_pageoff, | 1083 | .tlvp_pageoff, |
| 1122 | => unreachable, | 1084 | => unreachable, |
| 1123 | }; | 1085 | }; |
| 1124 | buffer.appendAssumeCapacity(.{ | 1086 | buffer[i] = .{ |
| 1125 | .r_address = r_address, | 1087 | .r_address = r_address, |
| 1126 | .r_symbolnum = r_symbolnum, | 1088 | .r_symbolnum = r_symbolnum, |
| 1127 | .r_pcrel = @intFromBool(rel.meta.pcrel), | 1089 | .r_pcrel = @intFromBool(rel.meta.pcrel), |
| 1128 | .r_extern = @intFromBool(r_extern), | 1090 | .r_extern = @intFromBool(r_extern), |
| 1129 | .r_length = rel.meta.length, | 1091 | .r_length = rel.meta.length, |
| 1130 | .r_type = @intFromEnum(r_type), | 1092 | .r_type = @intFromEnum(r_type), |
| 1131 | }); | 1093 | }; |
| 1132 | }, | 1094 | }, |
| 1133 | else => unreachable, | 1095 | else => unreachable, |
| 1134 | } | 1096 | } |
| 1135 | } | 1097 | } |
| 1098 | |||
| 1099 | assert(i == buffer.len); | ||
| 1136 | } | 1100 | } |
| 1137 | 1101 | ||
| 1138 | pub fn format( | 1102 | pub fn format( |
| ... | @@ -1170,18 +1134,18 @@ fn format2( | ... | @@ -1170,18 +1134,18 @@ fn format2( |
| 1170 | _ = unused_fmt_string; | 1134 | _ = unused_fmt_string; |
| 1171 | const atom = ctx.atom; | 1135 | const atom = ctx.atom; |
| 1172 | const macho_file = ctx.macho_file; | 1136 | const macho_file = ctx.macho_file; |
| 1173 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{ | 1137 | const file = atom.getFile(macho_file); |
| 1174 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), | 1138 | try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{ |
| 1175 | atom.out_n_sect, atom.alignment, atom.size, | 1139 | atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), |
| 1176 | atom.getRelocs(macho_file).len, | 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 | if (!atom.flags.alive) try writer.writeAll(" : [*]"); | 1143 | if (!atom.flags.alive) try writer.writeAll(" : [*]"); |
| 1180 | if (atom.flags.unwind) { | 1144 | if (atom.getUnwindRecords(macho_file).len > 0) { |
| 1181 | try writer.writeAll(" : unwind{ "); | 1145 | try writer.writeAll(" : unwind{ "); |
| 1182 | const extra = atom.getExtra(macho_file).?; | 1146 | const extra = atom.getExtra(macho_file); |
| 1183 | for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| { | 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 | try writer.print("{d}", .{index}); | 1149 | try writer.print("{d}", .{index}); |
| 1186 | if (!rec.alive) try writer.writeAll("([*])"); | 1150 | if (!rec.alive) try writer.writeAll("([*])"); |
| 1187 | if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", "); | 1151 | if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", "); |
| ... | @@ -1198,18 +1162,6 @@ pub const Flags = packed struct { | ... | @@ -1198,18 +1162,6 @@ pub const Flags = packed struct { |
| 1198 | 1162 | ||
| 1199 | /// Specifies if this atom has been visited during garbage collection. | 1163 | /// Specifies if this atom has been visited during garbage collection. |
| 1200 | visited: bool = false, | 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 | pub const Extra = struct { | 1167 | pub const Extra = struct { |
| ... | @@ -1222,6 +1174,12 @@ pub const Extra = struct { | ... | @@ -1222,6 +1174,12 @@ pub const Extra = struct { |
| 1222 | /// Count of relocations belonging to this atom. | 1174 | /// Count of relocations belonging to this atom. |
| 1223 | rel_count: u32 = 0, | 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 | /// Start index of relocations belonging to this atom. | 1183 | /// Start index of relocations belonging to this atom. |
| 1226 | unwind_index: u32 = 0, | 1184 | unwind_index: u32 = 0, |
| 1227 | 1185 | ||
| ... | @@ -1229,14 +1187,16 @@ pub const Extra = struct { | ... | @@ -1229,14 +1187,16 @@ pub const Extra = struct { |
| 1229 | unwind_count: u32 = 0, | 1187 | unwind_count: u32 = 0, |
| 1230 | 1188 | ||
| 1231 | /// Index into LiteralPool entry for this atom. | 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 | pub const Alignment = @import("../../InternPool.zig").Alignment; | 1196 | pub const Alignment = @import("../../InternPool.zig").Alignment; |
| 1236 | 1197 | ||
| 1237 | const aarch64 = @import("../aarch64.zig"); | 1198 | const aarch64 = @import("../aarch64.zig"); |
| 1238 | const assert = std.debug.assert; | 1199 | const assert = std.debug.assert; |
| 1239 | const bind = @import("dyld_info/bind.zig"); | ||
| 1240 | const macho = std.macho; | 1200 | const macho = std.macho; |
| 1241 | const math = std.math; | 1201 | const math = std.math; |
| 1242 | const mem = std.mem; | 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,8 +175,9 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { | 177 | pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { |
| 178 | const zo = macho_file.getZigObject().?; | ||
| 178 | for (self.relocs.items) |*reloc| { | 179 | for (self.relocs.items) |*reloc| { |
| 179 | const sym = macho_file.getSymbol(reloc.target); | 180 | const sym = zo.symbols.items[reloc.target]; |
| 180 | const sym_name = sym.getName(macho_file); | 181 | const sym_name = sym.getName(macho_file); |
| 181 | const addr = switch (reloc.type) { | 182 | const addr = switch (reloc.type) { |
| 182 | .direct_load => sym.getAddress(.{}, macho_file), | 183 | .direct_load => sym.getAddress(.{}, macho_file), |
| ... | @@ -382,23 +383,22 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 { | ... | @@ -382,23 +383,22 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 { |
| 382 | cmd.symoff = off; | 383 | cmd.symoff = off; |
| 383 | 384 | ||
| 384 | try self.symtab.resize(gpa, cmd.nsyms); | 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 | if (macho_file.getZigObject()) |zo| { | 389 | if (macho_file.getZigObject()) |zo| { |
| 388 | zo.writeSymtab(macho_file, self); | 390 | zo.writeSymtab(macho_file, self); |
| 389 | } | 391 | } |
| 390 | for (macho_file.objects.items) |index| { | 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 | for (macho_file.dylibs.items) |index| { | 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 | if (macho_file.getInternalObject()) |internal| { | 398 | if (macho_file.getInternalObject()) |internal| { |
| 397 | internal.writeSymtab(macho_file, self); | 399 | internal.writeSymtab(macho_file, self); |
| 398 | } | 400 | } |
| 399 | 401 | ||
| 400 | assert(self.strtab.items.len == cmd.strsize); | ||
| 401 | |||
| 402 | try self.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); | 402 | try self.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); |
| 403 | 403 | ||
| 404 | return off + cmd.nsyms * @sizeOf(macho.nlist_64); | 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,7 +6,9 @@ strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 6 | id: ?Id = null, | 6 | id: ?Id = null, |
| 7 | ordinal: u16 = 0, | 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 | dependents: std.ArrayListUnmanaged(Id) = .{}, | 12 | dependents: std.ArrayListUnmanaged(Id) = .{}, |
| 11 | rpaths: std.StringArrayHashMapUnmanaged(void) = .{}, | 13 | rpaths: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 12 | umbrella: File.Index = 0, | 14 | umbrella: File.Index = 0, |
| ... | @@ -37,6 +39,8 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void { | ... | @@ -37,6 +39,8 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void { |
| 37 | self.strtab.deinit(allocator); | 39 | self.strtab.deinit(allocator); |
| 38 | if (self.id) |*id| id.deinit(allocator); | 40 | if (self.id) |*id| id.deinit(allocator); |
| 39 | self.symbols.deinit(allocator); | 41 | self.symbols.deinit(allocator); |
| 42 | self.symbols_extra.deinit(allocator); | ||
| 43 | self.globals.deinit(allocator); | ||
| 40 | for (self.dependents.items) |*id| { | 44 | for (self.dependents.items) |*id| { |
| 41 | id.deinit(allocator); | 45 | id.deinit(allocator); |
| 42 | } | 46 | } |
| ... | @@ -494,53 +498,55 @@ fn addObjCExport( | ... | @@ -494,53 +498,55 @@ fn addObjCExport( |
| 494 | pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void { | 498 | pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void { |
| 495 | const gpa = macho_file.base.comp.gpa; | 499 | const gpa = macho_file.base.comp.gpa; |
| 496 | 500 | ||
| 497 | try self.symbols.ensureTotalCapacityPrecise(gpa, self.exports.items(.name).len); | 501 | const nsyms = self.exports.items(.name).len; |
| 498 | 502 | try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms); | |
| 499 | for (self.exports.items(.name)) |noff| { | 503 | try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra)); |
| 500 | const name = self.getString(noff); | 504 | try self.globals.ensureTotalCapacityPrecise(gpa, nsyms); |
| 501 | const off = try macho_file.strings.insert(gpa, name); | 505 | self.globals.resize(gpa, nsyms) catch unreachable; |
| 502 | const gop = try macho_file.getOrCreateGlobal(off); | 506 | @memset(self.globals.items, 0); |
| 503 | self.symbols.addOneAssumeCapacity().* = gop.index; | 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 | const tracy = trace(@src()); | 520 | const tracy = trace(@src()); |
| 509 | defer tracy.end(); | 521 | defer tracy.end(); |
| 510 | 522 | ||
| 511 | if (!self.explicit and !self.hoisted) return; | 523 | if (!self.explicit and !self.hoisted) return; |
| 512 | 524 | ||
| 513 | for (self.symbols.items, self.exports.items(.flags)) |index, flags| { | 525 | const gpa = macho_file.base.comp.gpa; |
| 514 | const global = macho_file.getSymbol(index); | 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 | if (self.asFile().getSymbolRank(.{ | 542 | if (self.asFile().getSymbolRank(.{ |
| 516 | .weak = flags.weak, | 543 | .weak = flags.weak, |
| 517 | }) < global.getSymbolRank(macho_file)) { | 544 | }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) { |
| 518 | global.value = 0; | 545 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; |
| 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; | ||
| 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 | pub fn isAlive(self: Dylib, macho_file: *MachO) bool { | 550 | pub fn isAlive(self: Dylib, macho_file: *MachO) bool { |
| 545 | if (!macho_file.dead_strip_dylibs) return self.explicit or self.referenced or self.needed; | 551 | if (!macho_file.dead_strip_dylibs) return self.explicit or self.referenced or self.needed; |
| 546 | return self.referenced or self.needed; | 552 | return self.referenced or self.needed; |
| ... | @@ -550,30 +556,31 @@ pub fn markReferenced(self: *Dylib, macho_file: *MachO) void { | ... | @@ -550,30 +556,31 @@ pub fn markReferenced(self: *Dylib, macho_file: *MachO) void { |
| 550 | const tracy = trace(@src()); | 556 | const tracy = trace(@src()); |
| 551 | defer tracy.end(); | 557 | defer tracy.end(); |
| 552 | 558 | ||
| 553 | for (self.symbols.items) |global_index| { | 559 | for (0..self.symbols.items.len) |i| { |
| 554 | const global = macho_file.getSymbol(global_index); | 560 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 555 | const file_ptr = global.getFile(macho_file) orelse continue; | 561 | const file = ref.getFile(macho_file) orelse continue; |
| 556 | if (file_ptr.getIndex() != self.index) continue; | 562 | if (file.getIndex() != self.index) continue; |
| 563 | const global = ref.getSymbol(macho_file).?; | ||
| 557 | if (global.isLocal()) continue; | 564 | if (global.isLocal()) continue; |
| 558 | self.referenced = true; | 565 | self.referenced = true; |
| 559 | break; | 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 | const tracy = trace(@src()); | 571 | const tracy = trace(@src()); |
| 565 | defer tracy.end(); | 572 | defer tracy.end(); |
| 566 | 573 | ||
| 567 | for (self.symbols.items) |global_index| { | 574 | for (self.symbols.items, 0..) |*sym, i| { |
| 568 | const global = macho_file.getSymbol(global_index); | 575 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 569 | const file_ptr = global.getFile(macho_file) orelse continue; | 576 | const file = ref.getFile(macho_file) orelse continue; |
| 570 | if (file_ptr.getIndex() != self.index) continue; | 577 | if (file.getIndex() != self.index) continue; |
| 571 | if (global.isLocal()) continue; | 578 | if (sym.isLocal()) continue; |
| 572 | assert(global.flags.import); | 579 | assert(sym.flags.import); |
| 573 | global.flags.output_symtab = true; | 580 | sym.flags.output_symtab = true; |
| 574 | try global.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); | 581 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file); |
| 575 | self.output_symtab_ctx.nimports += 1; | 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,17 +588,20 @@ pub fn writeSymtab(self: Dylib, macho_file: *MachO, ctx: anytype) void { |
| 581 | const tracy = trace(@src()); | 588 | const tracy = trace(@src()); |
| 582 | defer tracy.end(); | 589 | defer tracy.end(); |
| 583 | 590 | ||
| 584 | for (self.symbols.items) |global_index| { | 591 | var n_strx = self.output_symtab_ctx.stroff; |
| 585 | const global = macho_file.getSymbol(global_index); | 592 | for (self.symbols.items, 0..) |sym, i| { |
| 586 | const file = global.getFile(macho_file) orelse continue; | 593 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 594 | const file = ref.getFile(macho_file) orelse continue; | ||
| 587 | if (file.getIndex() != self.index) continue; | 595 | if (file.getIndex() != self.index) continue; |
| 588 | const idx = global.getOutputSymtabIndex(macho_file) orelse continue; | 596 | const idx = sym.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); | ||
| 592 | const out_sym = &ctx.symtab.items[idx]; | 597 | const out_sym = &ctx.symtab.items[idx]; |
| 593 | out_sym.n_strx = n_strx; | 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,7 +615,7 @@ fn addString(self: *Dylib, allocator: Allocator, name: []const u8) !u32 { |
| 605 | return off; | 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 | assert(off < self.strtab.items.len); | 619 | assert(off < self.strtab.items.len); |
| 610 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); | 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,6 +624,66 @@ pub fn asFile(self: *Dylib) File { |
| 614 | return .{ .dylib = self }; | 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 | pub fn format( | 687 | pub fn format( |
| 618 | self: *Dylib, | 688 | self: *Dylib, |
| 619 | comptime unused_fmt_string: []const u8, | 689 | comptime unused_fmt_string: []const u8, |
| ... | @@ -648,10 +718,16 @@ fn formatSymtab( | ... | @@ -648,10 +718,16 @@ fn formatSymtab( |
| 648 | _ = unused_fmt_string; | 718 | _ = unused_fmt_string; |
| 649 | _ = options; | 719 | _ = options; |
| 650 | const dylib = ctx.dylib; | 720 | const dylib = ctx.dylib; |
| 721 | const macho_file = ctx.macho_file; | ||
| 651 | try writer.writeAll(" globals\n"); | 722 | try writer.writeAll(" globals\n"); |
| 652 | for (dylib.symbols.items) |index| { | 723 | for (dylib.symbols.items, 0..) |sym, i| { |
| 653 | const global = ctx.macho_file.getSymbol(index); | 724 | const ref = dylib.getSymbolRef(@intCast(i), macho_file); |
| 654 | try writer.print(" {}\n", .{global.fmt(ctx.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,13 +1,28 @@ |
| 1 | index: File.Index, | 1 | index: File.Index, |
| 2 | 2 | ||
| 3 | sections: std.MultiArrayList(Section) = .{}, | 3 | sections: std.MultiArrayList(Section) = .{}, |
| 4 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 4 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 5 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 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 | objc_methnames: std.ArrayListUnmanaged(u8) = .{}, | 13 | objc_methnames: std.ArrayListUnmanaged(u8) = .{}, |
| 8 | objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64), | 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 | output_symtab_ctx: MachO.SymtabCtx = .{}, | 26 | output_symtab_ctx: MachO.SymtabCtx = .{}, |
| 12 | 27 | ||
| 13 | pub fn deinit(self: *InternalObject, allocator: Allocator) void { | 28 | pub fn deinit(self: *InternalObject, allocator: Allocator) void { |
| ... | @@ -16,39 +31,224 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void { | ... | @@ -16,39 +31,224 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void { |
| 16 | } | 31 | } |
| 17 | self.sections.deinit(allocator); | 32 | self.sections.deinit(allocator); |
| 18 | self.atoms.deinit(allocator); | 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 | self.symbols.deinit(allocator); | 38 | self.symbols.deinit(allocator); |
| 39 | self.symbols_extra.deinit(allocator); | ||
| 40 | self.globals.deinit(allocator); | ||
| 20 | self.objc_methnames.deinit(allocator); | 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 | const gpa = macho_file.base.comp.gpa; | 83 | const gpa = macho_file.base.comp.gpa; |
| 25 | try self.symbols.ensureUnusedCapacity(gpa, 1); | 84 | var nsyms = macho_file.base.comp.force_undefined_symbols.keys().len; |
| 26 | const off = try macho_file.strings.insert(gpa, name); | 85 | nsyms += 1; // dyld_stub_binder |
| 27 | const gop = try macho_file.getOrCreateGlobal(off); | 86 | nsyms += 1; // _objc_msgSend |
| 28 | self.symbols.addOneAssumeCapacity().* = gop.index; | 87 | if (!macho_file.base.isDynLib()) { |
| 29 | const sym = macho_file.getSymbol(gop.index); | 88 | nsyms += 1; // entry |
| 30 | sym.file = self.index; | 89 | nsyms += 1; // __mh_execute_header |
| 31 | sym.value = 0; | 90 | } else { |
| 32 | sym.atom = 0; | 91 | nsyms += 1; // __mh_dylib_header |
| 33 | sym.nlist_idx = 0; | 92 | } |
| 34 | sym.flags = .{ .global = true }; | 93 | nsyms += 1; // ___dso_handle |
| 35 | return gop.index; | 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. | 131 | pub fn resolveSymbols(self: *InternalObject, macho_file: *MachO) !void { |
| 39 | pub fn addObjcMsgsendSections(self: *InternalObject, sym_name: []const u8, macho_file: *MachO) !Atom.Index { | 132 | const tracy = trace(@src()); |
| 40 | const methname_atom_index = try self.addObjcMethnameSection(sym_name, macho_file); | 133 | defer tracy.end(); |
| 41 | return try self.addObjcSelrefsSection(methname_atom_index, macho_file); | 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 | const gpa = macho_file.base.comp.gpa; | 167 | const gpa = macho_file.base.comp.gpa; |
| 46 | const atom_index = try macho_file.addAtom(); | 168 | var boundary_symbols = std.StringArrayHashMap(MachO.Ref).init(gpa); |
| 47 | try self.atoms.append(gpa, atom_index); | 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).?; | 241 | /// Creates a fake input sections __TEXT,__objc_methname and __DATA,__objc_selrefs. |
| 50 | atom.atom_index = atom_index; | 242 | pub fn addObjcMsgsendSections(self: *InternalObject, sym_name: []const u8, macho_file: *MachO) !Symbol.Index { |
| 51 | atom.file = self.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 | atom.size = methname.len + 1; | 252 | atom.size = methname.len + 1; |
| 53 | atom.alignment = .@"1"; | 253 | atom.alignment = .@"1"; |
| 54 | 254 | ||
| ... | @@ -64,17 +264,32 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil | ... | @@ -64,17 +264,32 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil |
| 64 | try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1); | 264 | try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1); |
| 65 | self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable; | 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 | return atom_index; | 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 | const gpa = macho_file.base.comp.gpa; | 289 | const gpa = macho_file.base.comp.gpa; |
| 72 | const atom_index = try macho_file.addAtom(); | 290 | const atom_index = try self.addAtom(gpa); |
| 73 | try self.atoms.append(gpa, atom_index); | 291 | try self.atoms_indexes.append(gpa, atom_index); |
| 74 | 292 | const atom = self.getAtom(atom_index).?; | |
| 75 | const atom = macho_file.getAtom(atom_index).?; | ||
| 76 | atom.atom_index = atom_index; | ||
| 77 | atom.file = self.index; | ||
| 78 | atom.size = @sizeOf(u64); | 293 | atom.size = @sizeOf(u64); |
| 79 | atom.alignment = .@"8"; | 294 | atom.alignment = .@"8"; |
| 80 | 295 | ||
| ... | @@ -90,9 +305,9 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, | ... | @@ -90,9 +305,9 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, |
| 90 | const relocs = &self.sections.items(.relocs)[n_sect]; | 305 | const relocs = &self.sections.items(.relocs)[n_sect]; |
| 91 | try relocs.ensureUnusedCapacity(gpa, 1); | 306 | try relocs.ensureUnusedCapacity(gpa, 1); |
| 92 | relocs.appendAssumeCapacity(.{ | 307 | relocs.appendAssumeCapacity(.{ |
| 93 | .tag = .local, | 308 | .tag = .@"extern", |
| 94 | .offset = 0, | 309 | .offset = 0, |
| 95 | .target = methname_atom_index, | 310 | .target = methname_sym_index, |
| 96 | .addend = 0, | 311 | .addend = 0, |
| 97 | .type = .unsigned, | 312 | .type = .unsigned, |
| 98 | .meta = .{ | 313 | .meta = .{ |
| ... | @@ -102,140 +317,285 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, | ... | @@ -102,140 +317,285 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, |
| 102 | .has_subtractor = false, | 317 | .has_subtractor = false, |
| 103 | }, | 318 | }, |
| 104 | }); | 319 | }); |
| 105 | try atom.addExtra(.{ .rel_index = 0, .rel_count = 1 }, macho_file); | 320 | atom.addExtra(.{ .rel_index = 0, .rel_count = 1 }, macho_file); |
| 106 | atom.flags.relocs = true; | 321 | |
| 107 | self.num_rebase_relocs += 1; | 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 | const gpa = macho_file.base.comp.gpa; | 404 | const gpa = macho_file.base.comp.gpa; |
| 114 | 405 | ||
| 115 | var buffer = std.ArrayList(u8).init(gpa); | 406 | var buffer = std.ArrayList(u8).init(gpa); |
| 116 | defer buffer.deinit(); | 407 | defer buffer.deinit(); |
| 117 | 408 | ||
| 118 | const slice = self.sections.slice(); | 409 | const slice = self.sections.slice(); |
| 119 | for (slice.items(.header), self.atoms.items, 0..) |header, atom_index, n_sect| { | 410 | for (slice.items(.header), self.getAtoms()) |header, atom_index| { |
| 120 | if (Object.isCstringLiteral(header) or Object.isFixedSizeLiteral(header)) { | 411 | if (!Object.isPtrLiteral(header)) continue; |
| 121 | const data = try self.getSectionData(@intCast(n_sect)); | 412 | const atom = self.getAtom(atom_index).?; |
| 122 | const atom = macho_file.getAtom(atom_index).?; | 413 | const relocs = atom.getRelocs(macho_file); |
| 123 | const res = try lp.insert(gpa, header.type(), data); | 414 | assert(relocs.len == 1); |
| 124 | if (!res.found_existing) { | 415 | const rel = relocs[0]; |
| 125 | res.atom.* = atom_index; | 416 | assert(rel.tag == .@"extern"); |
| 126 | } | 417 | const target = rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?; |
| 127 | atom.flags.literal_pool = true; | 418 | const target_size = std.math.cast(usize, target.size) orelse return error.Overflow; |
| 128 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); | 419 | try buffer.ensureUnusedCapacity(target_size); |
| 129 | } else if (Object.isPtrLiteral(header)) { | 420 | buffer.resize(target_size) catch unreachable; |
| 130 | const atom = macho_file.getAtom(atom_index).?; | 421 | @memcpy(buffer.items, try self.getSectionData(target.n_sect)); |
| 131 | const relocs = atom.getRelocs(macho_file); | 422 | const res = try lp.insert(gpa, header.type(), buffer.items); |
| 132 | assert(relocs.len == 1); | 423 | buffer.clearRetainingCapacity(); |
| 133 | const rel = relocs[0]; | 424 | if (!res.found_existing) { |
| 134 | assert(rel.tag == .local); | 425 | res.ref.* = .{ .index = atom.getExtra(macho_file).literal_symbol_index, .file = self.index }; |
| 135 | const target = macho_file.getAtom(rel.target).?; | 426 | } else { |
| 136 | const addend = std.math.cast(u32, rel.addend) orelse return error.Overflow; | 427 | const lp_sym = lp.getSymbol(res.index, macho_file); |
| 137 | const target_size = std.math.cast(usize, target.size) orelse return error.Overflow; | 428 | const lp_atom = lp_sym.getAtom(macho_file).?; |
| 138 | try buffer.ensureUnusedCapacity(target_size); | 429 | lp_atom.alignment = lp_atom.alignment.max(atom.alignment); |
| 139 | buffer.resize(target_size) catch unreachable; | 430 | atom.flags.alive = false; |
| 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); | ||
| 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 { | 436 | pub fn dedupLiterals(self: *InternalObject, lp: MachO.LiteralPool, macho_file: *MachO) void { |
| 153 | for (self.atoms.items) |atom_index| { | 437 | const tracy = trace(@src()); |
| 154 | const atom = macho_file.getAtom(atom_index) orelse continue; | 438 | defer tracy.end(); |
| 439 | |||
| 440 | for (self.getAtoms()) |atom_index| { | ||
| 441 | const atom = self.getAtom(atom_index) orelse continue; | ||
| 155 | if (!atom.flags.alive) continue; | 442 | if (!atom.flags.alive) continue; |
| 156 | if (!atom.flags.relocs) continue; | ||
| 157 | 443 | ||
| 158 | const relocs = blk: { | 444 | const relocs = blk: { |
| 159 | const extra = atom.getExtra(macho_file).?; | 445 | const extra = atom.getExtra(macho_file); |
| 160 | const relocs = self.sections.items(.relocs)[atom.n_sect].items; | 446 | const relocs = self.sections.items(.relocs)[atom.n_sect].items; |
| 161 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; | 447 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; |
| 162 | }; | 448 | }; |
| 163 | for (relocs) |*rel| switch (rel.tag) { | 449 | for (relocs) |*rel| { |
| 164 | .local => { | 450 | if (rel.tag != .@"extern") continue; |
| 165 | const target = macho_file.getAtom(rel.target).?; | 451 | const target_sym_ref = rel.getTargetSymbolRef(atom.*, macho_file); |
| 166 | if (target.getLiteralPoolIndex(macho_file)) |lp_index| { | 452 | const file = target_sym_ref.getFile(macho_file) orelse continue; |
| 167 | const lp_atom = lp.getAtom(lp_index, macho_file); | 453 | if (file.getIndex() != self.index) continue; |
| 168 | if (target.atom_index != lp_atom.atom_index) { | 454 | const target_sym = target_sym_ref.getSymbol(macho_file).?; |
| 169 | lp_atom.alignment = lp_atom.alignment.max(target.alignment); | 455 | const target_atom = target_sym.getAtom(macho_file) orelse continue; |
| 170 | target.flags.alive = false; | 456 | if (!Object.isPtrLiteral(target_atom.getInputSection(macho_file))) continue; |
| 171 | rel.target = lp_atom.atom_index; | 457 | const lp_index = target_atom.getExtra(macho_file).literal_pool_index; |
| 172 | } | 458 | const lp_sym = lp.getSymbol(lp_index, macho_file); |
| 173 | } | 459 | const lp_atom_ref = lp_sym.atom_ref; |
| 174 | }, | 460 | if (target_atom.atom_index != lp_atom_ref.index or target_atom.file != lp_atom_ref.file) { |
| 175 | .@"extern" => { | 461 | target_sym.atom_ref = lp_atom_ref; |
| 176 | const target_sym = rel.getTargetSymbol(macho_file); | 462 | } |
| 177 | if (target_sym.getAtom(macho_file)) |target_atom| { | 463 | } |
| 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 | }; | ||
| 189 | } | 464 | } |
| 190 | 465 | ||
| 191 | for (self.symbols.items) |sym_index| { | 466 | for (self.symbols.items) |*sym| { |
| 192 | const sym = macho_file.getSymbol(sym_index); | ||
| 193 | if (!sym.flags.objc_stubs) continue; | 467 | if (!sym.flags.objc_stubs) continue; |
| 194 | var extra = sym.getExtra(macho_file).?; | 468 | const extra = sym.getExtra(macho_file); |
| 195 | const atom = macho_file.getAtom(extra.objc_selrefs).?; | 469 | const file = sym.getFile(macho_file).?; |
| 196 | if (atom.getLiteralPoolIndex(macho_file)) |lp_index| { | 470 | if (file.getIndex() != self.index) continue; |
| 197 | const lp_atom = lp.getAtom(lp_index, macho_file); | 471 | const tsym = switch (file) { |
| 198 | if (atom.atom_index != lp_atom.atom_index) { | 472 | .dylib => unreachable, |
| 199 | lp_atom.alignment = lp_atom.alignment.max(atom.alignment); | 473 | inline else => |x| &x.symbols.items[extra.objc_selrefs], |
| 200 | atom.flags.alive = false; | 474 | }; |
| 201 | extra.objc_selrefs = lp_atom.atom_index; | 475 | const atom = tsym.getAtom(macho_file) orelse continue; |
| 202 | sym.setExtra(extra, macho_file); | 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 { | 545 | pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) void { |
| 209 | for (self.symbols.items) |sym_index| { | 546 | for (self.symbols.items, 0..) |*sym, i| { |
| 210 | const sym = macho_file.getSymbol(sym_index); | 547 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 211 | if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue; | 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 | sym.flags.output_symtab = true; | 551 | sym.flags.output_symtab = true; |
| 213 | if (sym.isLocal()) { | 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 | self.output_symtab_ctx.nlocals += 1; | 554 | self.output_symtab_ctx.nlocals += 1; |
| 216 | } else if (sym.flags.@"export") { | 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 | self.output_symtab_ctx.nexports += 1; | 557 | self.output_symtab_ctx.nexports += 1; |
| 219 | } else { | 558 | } else { |
| 220 | assert(sym.flags.import); | 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 | self.output_symtab_ctx.nimports += 1; | 561 | self.output_symtab_ctx.nimports += 1; |
| 223 | } | 562 | } |
| 224 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1)); | 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 | pub fn writeSymtab(self: InternalObject, macho_file: *MachO, ctx: anytype) void { | 584 | pub fn writeSymtab(self: InternalObject, macho_file: *MachO, ctx: anytype) void { |
| 229 | for (self.symbols.items) |sym_index| { | 585 | var n_strx = self.output_symtab_ctx.stroff; |
| 230 | const sym = macho_file.getSymbol(sym_index); | 586 | for (self.symbols.items, 0..) |sym, i| { |
| 231 | if (sym.getFile(macho_file)) |file| if (file.getIndex() != self.index) continue; | 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 | const idx = sym.getOutputSymtabIndex(macho_file) orelse continue; | 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 | const out_sym = &ctx.symtab.items[idx]; | 591 | const out_sym = &ctx.symtab.items[idx]; |
| 237 | out_sym.n_strx = n_strx; | 592 | out_sym.n_strx = n_strx; |
| 238 | sym.setOutputSym(macho_file, out_sym); | 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,30 +624,171 @@ fn getSectionData(self: *const InternalObject, index: u32) error{Overflow}![]con |
| 264 | @panic("ref to non-existent section"); | 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 { | 627 | pub fn addString(self: *InternalObject, allocator: Allocator, name: []const u8) !u32 { |
| 268 | assert(buffer.len == atom.size); | 628 | const off: u32 = @intCast(self.strtab.items.len); |
| 269 | const data = try self.getSectionData(atom.n_sect); | 629 | try self.strtab.ensureUnusedCapacity(allocator, name.len + 1); |
| 270 | const off = std.math.cast(usize, atom.off) orelse return error.Overflow; | 630 | self.strtab.appendSliceAssumeCapacity(name); |
| 271 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | 631 | self.strtab.appendAssumeCapacity(0); |
| 272 | @memcpy(buffer, data[off..][0..size]); | 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 | pub fn getAtomRelocs(self: *const InternalObject, atom: Atom, macho_file: *MachO) []const Relocation { | 644 | pub fn getAtomRelocs(self: *const InternalObject, atom: Atom, macho_file: *MachO) []const Relocation { |
| 276 | if (!atom.flags.relocs) return &[0]Relocation{}; | 645 | const extra = atom.getExtra(macho_file); |
| 277 | const extra = atom.getExtra(macho_file).?; | ||
| 278 | const relocs = self.sections.items(.relocs)[atom.n_sect]; | 646 | const relocs = self.sections.items(.relocs)[atom.n_sect]; |
| 279 | return relocs.items[extra.rel_index..][0..extra.rel_count]; | 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 { | 650 | fn addAtom(self: *InternalObject, allocator: Allocator) !Atom.Index { |
| 283 | _ = self; | 651 | const atom_index: Atom.Index = @intCast(self.atoms.items.len); |
| 284 | _ = off; | 652 | const atom = try self.atoms.addOne(allocator); |
| 285 | // We don't have any local strings for synthetic atoms. | 653 | atom.* = .{ |
| 286 | return ""; | 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 { | 661 | pub fn getAtom(self: *InternalObject, atom_index: Atom.Index) ?*Atom { |
| 290 | return .{ .internal = self }; | 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 | const FormatContext = struct { | 794 | const FormatContext = struct { |
| ... | @@ -311,8 +812,8 @@ fn formatAtoms( | ... | @@ -311,8 +812,8 @@ fn formatAtoms( |
| 311 | _ = unused_fmt_string; | 812 | _ = unused_fmt_string; |
| 312 | _ = options; | 813 | _ = options; |
| 313 | try writer.writeAll(" atoms\n"); | 814 | try writer.writeAll(" atoms\n"); |
| 314 | for (ctx.self.atoms.items) |atom_index| { | 815 | for (ctx.self.getAtoms()) |atom_index| { |
| 315 | const atom = ctx.macho_file.getAtom(atom_index).?; | 816 | const atom = ctx.self.getAtom(atom_index) orelse continue; |
| 316 | try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)}); | 817 | try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)}); |
| 317 | } | 818 | } |
| 318 | } | 819 | } |
| ... | @@ -332,10 +833,17 @@ fn formatSymtab( | ... | @@ -332,10 +833,17 @@ fn formatSymtab( |
| 332 | ) !void { | 833 | ) !void { |
| 333 | _ = unused_fmt_string; | 834 | _ = unused_fmt_string; |
| 334 | _ = options; | 835 | _ = options; |
| 836 | const macho_file = ctx.macho_file; | ||
| 837 | const self = ctx.self; | ||
| 335 | try writer.writeAll(" symbols\n"); | 838 | try writer.writeAll(" symbols\n"); |
| 336 | for (ctx.self.symbols.items) |index| { | 839 | for (self.symbols.items, 0..) |sym, i| { |
| 337 | const global = ctx.macho_file.getSymbol(index); | 840 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 338 | try writer.print(" {}\n", .{global.fmt(ctx.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,6 +862,7 @@ const assert = std.debug.assert; |
| 354 | const macho = std.macho; | 862 | const macho = std.macho; |
| 355 | const mem = std.mem; | 863 | const mem = std.mem; |
| 356 | const std = @import("std"); | 864 | const std = @import("std"); |
| 865 | const trace = @import("../../tracy.zig").trace; | ||
| 357 | 866 | ||
| 358 | const Allocator = std.mem.Allocator; | 867 | const Allocator = std.mem.Allocator; |
| 359 | const Atom = @import("Atom.zig"); | 868 | const Atom = @import("Atom.zig"); |
src/link/MachO/Object.zig+1005-488| ... | @@ -1,16 +1,22 @@ | ... | @@ -1,16 +1,22 @@ |
| 1 | archive: ?InArchive = null, | 1 | /// Non-zero for fat object files or archives |
| 2 | offset: u64, | ||
| 2 | path: []const u8, | 3 | path: []const u8, |
| 3 | file_handle: File.HandleIndex, | 4 | file_handle: File.HandleIndex, |
| 4 | mtime: u64, | 5 | mtime: u64, |
| 5 | index: File.Index, | 6 | index: File.Index, |
| 7 | in_archive: ?InArchive = null, | ||
| 6 | 8 | ||
| 7 | header: ?macho.mach_header_64 = null, | 9 | header: ?macho.mach_header_64 = null, |
| 8 | sections: std.MultiArrayList(Section) = .{}, | 10 | sections: std.MultiArrayList(Section) = .{}, |
| 9 | symtab: std.MultiArrayList(Nlist) = .{}, | 11 | symtab: std.MultiArrayList(Nlist) = .{}, |
| 10 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 12 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 11 | 13 | ||
| 12 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 14 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, |
| 13 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 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 | platform: ?MachO.Platform = null, | 21 | platform: ?MachO.Platform = null, |
| 16 | compile_unit: ?CompileUnit = null, | 22 | compile_unit: ?CompileUnit = null, |
| ... | @@ -21,13 +27,14 @@ compact_unwind_sect_index: ?u8 = null, | ... | @@ -21,13 +27,14 @@ compact_unwind_sect_index: ?u8 = null, |
| 21 | cies: std.ArrayListUnmanaged(Cie) = .{}, | 27 | cies: std.ArrayListUnmanaged(Cie) = .{}, |
| 22 | fdes: std.ArrayListUnmanaged(Fde) = .{}, | 28 | fdes: std.ArrayListUnmanaged(Fde) = .{}, |
| 23 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, | 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 | data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, | 32 | data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, |
| 26 | 33 | ||
| 27 | alive: bool = true, | 34 | alive: bool = true, |
| 28 | hidden: bool = false, | 35 | hidden: bool = false, |
| 29 | 36 | ||
| 30 | dynamic_relocs: MachO.DynamicRelocs = .{}, | 37 | compact_unwind_ctx: CompactUnwindCtx = .{}, |
| 31 | output_symtab_ctx: MachO.SymtabCtx = .{}, | 38 | output_symtab_ctx: MachO.SymtabCtx = .{}, |
| 32 | output_ar_state: Archive.ArState = .{}, | 39 | output_ar_state: Archive.ArState = .{}, |
| 33 | 40 | ||
| ... | @@ -39,7 +46,7 @@ pub fn isObject(path: []const u8) !bool { | ... | @@ -39,7 +46,7 @@ pub fn isObject(path: []const u8) !bool { |
| 39 | } | 46 | } |
| 40 | 47 | ||
| 41 | pub fn deinit(self: *Object, allocator: Allocator) void { | 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 | allocator.free(self.path); | 50 | allocator.free(self.path); |
| 44 | for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { | 51 | for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { |
| 45 | relocs.deinit(allocator); | 52 | relocs.deinit(allocator); |
| ... | @@ -49,11 +56,16 @@ pub fn deinit(self: *Object, allocator: Allocator) void { | ... | @@ -49,11 +56,16 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 49 | self.symtab.deinit(allocator); | 56 | self.symtab.deinit(allocator); |
| 50 | self.strtab.deinit(allocator); | 57 | self.strtab.deinit(allocator); |
| 51 | self.symbols.deinit(allocator); | 58 | self.symbols.deinit(allocator); |
| 59 | self.symbols_extra.deinit(allocator); | ||
| 60 | self.globals.deinit(allocator); | ||
| 52 | self.atoms.deinit(allocator); | 61 | self.atoms.deinit(allocator); |
| 62 | self.atoms_indexes.deinit(allocator); | ||
| 63 | self.atoms_extra.deinit(allocator); | ||
| 53 | self.cies.deinit(allocator); | 64 | self.cies.deinit(allocator); |
| 54 | self.fdes.deinit(allocator); | 65 | self.fdes.deinit(allocator); |
| 55 | self.eh_frame_data.deinit(allocator); | 66 | self.eh_frame_data.deinit(allocator); |
| 56 | self.unwind_records.deinit(allocator); | 67 | self.unwind_records.deinit(allocator); |
| 68 | self.unwind_records_indexes.deinit(allocator); | ||
| 57 | for (self.stab_files.items) |*sf| { | 69 | for (self.stab_files.items) |*sf| { |
| 58 | sf.stabs.deinit(allocator); | 70 | sf.stabs.deinit(allocator); |
| 59 | } | 71 | } |
| ... | @@ -65,13 +77,18 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -65,13 +77,18 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 65 | const tracy = trace(@src()); | 77 | const tracy = trace(@src()); |
| 66 | defer tracy.end(); | 78 | defer tracy.end(); |
| 67 | 79 | ||
| 80 | log.debug("parsing {}", .{self.fmtPath()}); | ||
| 81 | |||
| 68 | const gpa = macho_file.base.comp.gpa; | 82 | const gpa = macho_file.base.comp.gpa; |
| 69 | const offset = if (self.archive) |ar| ar.offset else 0; | ||
| 70 | const handle = macho_file.getFileHandle(self.file_handle); | 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 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; | 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 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; | 92 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 76 | } | 93 | } |
| 77 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; | 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,7 +101,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 84 | return error.InvalidCpuArch; | 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 | try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)}); | 105 | try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)}); |
| 89 | return error.InvalidCpuArch; | 106 | return error.InvalidCpuArch; |
| 90 | } | 107 | } |
| ... | @@ -92,7 +109,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -92,7 +109,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 92 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); | 109 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 93 | defer gpa.free(lc_buffer); | 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 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; | 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,14 +136,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 119 | const cmd = lc.cast(macho.symtab_command).?; | 136 | const cmd = lc.cast(macho.symtab_command).?; |
| 120 | try self.strtab.resize(gpa, cmd.strsize); | 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 | if (amt != self.strtab.items.len) return error.InputOutput; | 140 | if (amt != self.strtab.items.len) return error.InputOutput; |
| 124 | } | 141 | } |
| 125 | 142 | ||
| 126 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); | 143 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); |
| 127 | defer gpa.free(symtab_buffer); | 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 | if (amt != symtab_buffer.len) return error.InputOutput; | 147 | if (amt != symtab_buffer.len) return error.InputOutput; |
| 131 | } | 148 | } |
| 132 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; | 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,7 +161,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 144 | const buffer = try gpa.alloc(u8, cmd.datasize); | 161 | const buffer = try gpa.alloc(u8, cmd.datasize); |
| 145 | defer gpa.free(buffer); | 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 | if (amt != buffer.len) return error.InputOutput; | 165 | if (amt != buffer.len) return error.InputOutput; |
| 149 | } | 166 | } |
| 150 | const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry)); | 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,39 +213,39 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 196 | mem.sort(NlistIdx, nlists.items, self, NlistIdx.lessThan); | 213 | mem.sort(NlistIdx, nlists.items, self, NlistIdx.lessThan); |
| 197 | 214 | ||
| 198 | if (self.hasSubsections()) { | 215 | if (self.hasSubsections()) { |
| 199 | try self.initSubsections(nlists.items, macho_file); | 216 | try self.initSubsections(gpa, nlists.items); |
| 200 | } else { | 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); | 221 | try self.initCstringLiterals(gpa, handle, macho_file); |
| 205 | try self.initFixedSizeLiterals(macho_file); | 222 | try self.initFixedSizeLiterals(gpa, macho_file); |
| 206 | try self.initPointerLiterals(macho_file); | 223 | try self.initPointerLiterals(gpa, macho_file); |
| 207 | try self.linkNlistToAtom(macho_file); | 224 | try self.linkNlistToAtom(macho_file); |
| 208 | 225 | ||
| 209 | try self.sortAtoms(macho_file); | 226 | try self.sortAtoms(macho_file); |
| 210 | try self.initSymbols(macho_file); | 227 | try self.initSymbols(gpa, macho_file); |
| 211 | try self.initSymbolStabs(nlists.items, macho_file); | 228 | try self.initSymbolStabs(gpa, nlists.items, macho_file); |
| 212 | try self.initRelocs(macho_file); | 229 | try self.initRelocs(handle, cpu_arch, macho_file); |
| 213 | 230 | ||
| 214 | // Parse DWARF __TEXT,__eh_frame section | 231 | // Parse DWARF __TEXT,__eh_frame section |
| 215 | if (self.eh_frame_sect_index) |index| { | 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 | // Parse Apple's __LD,__compact_unwind section | 236 | // Parse Apple's __LD,__compact_unwind section |
| 220 | if (self.compact_unwind_sect_index) |index| { | 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 | if (self.hasUnwindRecords() or self.hasEhFrameRecords()) { | 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 | if (self.platform) |platform| { | 245 | if (self.platform) |platform| { |
| 229 | if (!macho_file.platform.eqlTarget(platform)) { | 246 | if (!macho_file.platform.eqlTarget(platform)) { |
| 230 | try macho_file.reportParseError2(self.index, "invalid platform: {}", .{ | 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 | return error.InvalidTarget; | 250 | return error.InvalidTarget; |
| 234 | } | 251 | } |
| ... | @@ -244,8 +261,10 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -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| { | 264 | try self.parseDebugInfo(macho_file); |
| 248 | const atom = macho_file.getAtom(atom_index).?; | 265 | |
| 266 | for (self.getAtoms()) |atom_index| { | ||
| 267 | const atom = self.getAtom(atom_index) orelse continue; | ||
| 249 | const isec = atom.getInputSection(macho_file); | 268 | const isec = atom.getInputSection(macho_file); |
| 250 | if (mem.eql(u8, isec.sectName(), "__eh_frame") or | 269 | if (mem.eql(u8, isec.sectName(), "__eh_frame") or |
| 251 | mem.eql(u8, isec.sectName(), "__compact_unwind") or | 270 | mem.eql(u8, isec.sectName(), "__compact_unwind") or |
| ... | @@ -274,10 +293,9 @@ pub fn isPtrLiteral(sect: macho.section_64) bool { | ... | @@ -274,10 +293,9 @@ pub fn isPtrLiteral(sect: macho.section_64) bool { |
| 274 | return sect.type() == macho.S_LITERAL_POINTERS; | 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 | const tracy = trace(@src()); | 297 | const tracy = trace(@src()); |
| 279 | defer tracy.end(); | 298 | defer tracy.end(); |
| 280 | const gpa = macho_file.base.comp.gpa; | ||
| 281 | const slice = self.sections.slice(); | 299 | const slice = self.sections.slice(); |
| 282 | for (slice.items(.header), slice.items(.subsections), 0..) |sect, *subsections, n_sect| { | 300 | for (slice.items(.header), slice.items(.subsections), 0..) |sect, *subsections, n_sect| { |
| 283 | if (isCstringLiteral(sect)) continue; | 301 | if (isCstringLiteral(sect)) continue; |
| ... | @@ -292,17 +310,18 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { | ... | @@ -292,17 +310,18 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 292 | } else nlists.len; | 310 | } else nlists.len; |
| 293 | 311 | ||
| 294 | if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) { | 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() }); | 313 | const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() }); |
| 296 | defer gpa.free(name); | 314 | defer allocator.free(name); |
| 297 | const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr; | 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(.{ | 316 | const atom_index = try self.addAtom(allocator, .{ |
| 299 | .name = try self.addString(gpa, name), | 317 | .name = try self.addString(allocator, name), |
| 300 | .n_sect = @intCast(n_sect), | 318 | .n_sect = @intCast(n_sect), |
| 301 | .off = 0, | 319 | .off = 0, |
| 302 | .size = size, | 320 | .size = size, |
| 303 | .alignment = sect.@"align", | 321 | .alignment = sect.@"align", |
| 304 | }, macho_file); | 322 | }); |
| 305 | try subsections.append(gpa, .{ | 323 | try self.atoms_indexes.append(allocator, atom_index); |
| 324 | try subsections.append(allocator, .{ | ||
| 306 | .atom = atom_index, | 325 | .atom = atom_index, |
| 307 | .off = 0, | 326 | .off = 0, |
| 308 | }); | 327 | }); |
| ... | @@ -325,14 +344,15 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { | ... | @@ -325,14 +344,15 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 325 | @min(@ctz(nlist.nlist.n_value), sect.@"align") | 344 | @min(@ctz(nlist.nlist.n_value), sect.@"align") |
| 326 | else | 345 | else |
| 327 | sect.@"align"; | 346 | sect.@"align"; |
| 328 | const atom_index = try self.addAtom(.{ | 347 | const atom_index = try self.addAtom(allocator, .{ |
| 329 | .name = nlist.nlist.n_strx, | 348 | .name = nlist.nlist.n_strx, |
| 330 | .n_sect = @intCast(n_sect), | 349 | .n_sect = @intCast(n_sect), |
| 331 | .off = nlist.nlist.n_value - sect.addr, | 350 | .off = nlist.nlist.n_value - sect.addr, |
| 332 | .size = size, | 351 | .size = size, |
| 333 | .alignment = alignment, | 352 | .alignment = alignment, |
| 334 | }, macho_file); | 353 | }); |
| 335 | try subsections.append(gpa, .{ | 354 | try self.atoms_indexes.append(allocator, atom_index); |
| 355 | try subsections.append(allocator, .{ | ||
| 336 | .atom = atom_index, | 356 | .atom = atom_index, |
| 337 | .off = nlist.nlist.n_value - sect.addr, | 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,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 | const tracy = trace(@src()); | 368 | const tracy = trace(@src()); |
| 349 | defer tracy.end(); | 369 | defer tracy.end(); |
| 350 | const gpa = macho_file.base.comp.gpa; | ||
| 351 | const slice = self.sections.slice(); | 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 | for (slice.items(.header), 0..) |sect, n_sect| { | 375 | for (slice.items(.header), 0..) |sect, n_sect| { |
| 356 | if (isCstringLiteral(sect)) continue; | 376 | if (isCstringLiteral(sect)) continue; |
| 357 | if (isFixedSizeLiteral(sect)) continue; | 377 | if (isFixedSizeLiteral(sect)) continue; |
| 358 | if (isPtrLiteral(sect)) continue; | 378 | if (isPtrLiteral(sect)) continue; |
| 359 | 379 | ||
| 360 | const name = try std.fmt.allocPrintZ(gpa, "{s}${s}", .{ sect.segName(), sect.sectName() }); | 380 | const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() }); |
| 361 | defer gpa.free(name); | 381 | defer allocator.free(name); |
| 362 | 382 | ||
| 363 | const atom_index = try self.addAtom(.{ | 383 | const atom_index = try self.addAtom(allocator, .{ |
| 364 | .name = try self.addString(gpa, name), | 384 | .name = try self.addString(allocator, name), |
| 365 | .n_sect = @intCast(n_sect), | 385 | .n_sect = @intCast(n_sect), |
| 366 | .off = 0, | 386 | .off = 0, |
| 367 | .size = sect.size, | 387 | .size = sect.size, |
| 368 | .alignment = sect.@"align", | 388 | .alignment = sect.@"align", |
| 369 | }, macho_file); | 389 | }); |
| 370 | try slice.items(.subsections)[n_sect].append(gpa, .{ .atom = atom_index, .off = 0 }); | 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 | const nlist_start = for (nlists, 0..) |nlist, i| { | 393 | const nlist_start = for (nlists, 0..) |nlist, i| { |
| 373 | if (nlist.nlist.n_sect - 1 == n_sect) break i; | 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,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 | const tracy = trace(@src()); | 421 | const tracy = trace(@src()); |
| 401 | defer tracy.end(); | 422 | defer tracy.end(); |
| 402 | 423 | ||
| 403 | const gpa = macho_file.base.comp.gpa; | ||
| 404 | const slice = self.sections.slice(); | 424 | const slice = self.sections.slice(); |
| 405 | 425 | ||
| 406 | for (slice.items(.header), 0..) |sect, n_sect| { | 426 | for (slice.items(.header), 0..) |sect, n_sect| { |
| 407 | if (!isCstringLiteral(sect)) continue; | 427 | if (!isCstringLiteral(sect)) continue; |
| 408 | 428 | ||
| 409 | const data = try self.getSectionData(@intCast(n_sect), macho_file); | 429 | const sect_size = math.cast(usize, sect.size) orelse return error.Overflow; |
| 410 | defer gpa.free(data); | 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 | var start: u32 = 0; | 436 | var start: u32 = 0; |
| 413 | while (start < data.len) { | 437 | while (start < data.len) { |
| 438 | defer count += 1; | ||
| 414 | var end = start; | 439 | var end = start; |
| 415 | while (end < data.len - 1 and data[end] != 0) : (end += 1) {} | 440 | while (end < data.len - 1 and data[end] != 0) : (end += 1) {} |
| 416 | if (data[end] != 0) { | 441 | if (data[end] != 0) { |
| ... | @@ -423,32 +448,52 @@ fn initCstringLiterals(self: *Object, macho_file: *MachO) !void { | ... | @@ -423,32 +448,52 @@ fn initCstringLiterals(self: *Object, macho_file: *MachO) !void { |
| 423 | } | 448 | } |
| 424 | end += 1; | 449 | end += 1; |
| 425 | 450 | ||
| 426 | const atom_index = try self.addAtom(.{ | 451 | const name = try std.fmt.allocPrintZ(allocator, "l._str{d}", .{count}); |
| 427 | .name = 0, | 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 | .n_sect = @intCast(n_sect), | 457 | .n_sect = @intCast(n_sect), |
| 429 | .off = start, | 458 | .off = start, |
| 430 | .size = end - start, | 459 | .size = end - start, |
| 431 | .alignment = sect.@"align", | 460 | .alignment = sect.@"align", |
| 432 | }, macho_file); | 461 | }); |
| 433 | try slice.items(.subsections)[n_sect].append(gpa, .{ | 462 | try self.atoms_indexes.append(allocator, atom_index); |
| 463 | try slice.items(.subsections)[n_sect].append(allocator, .{ | ||
| 434 | .atom = atom_index, | 464 | .atom = atom_index, |
| 435 | .off = start, | 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 | start = end; | 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 | const tracy = trace(@src()); | 489 | const tracy = trace(@src()); |
| 445 | defer tracy.end(); | 490 | defer tracy.end(); |
| 446 | 491 | ||
| 447 | const gpa = macho_file.base.comp.gpa; | ||
| 448 | const slice = self.sections.slice(); | 492 | const slice = self.sections.slice(); |
| 449 | 493 | ||
| 450 | for (slice.items(.header), 0..) |sect, n_sect| { | 494 | for (slice.items(.header), 0..) |sect, n_sect| { |
| 451 | if (!isFixedSizeLiteral(sect)) continue; | 495 | if (!isFixedSizeLiteral(sect)) continue; |
| 496 | |||
| 452 | const rec_size: u8 = switch (sect.type()) { | 497 | const rec_size: u8 = switch (sect.type()) { |
| 453 | macho.S_4BYTE_LITERALS => 4, | 498 | macho.S_4BYTE_LITERALS => 4, |
| 454 | macho.S_8BYTE_LITERALS => 8, | 499 | macho.S_8BYTE_LITERALS => 8, |
| ... | @@ -463,28 +508,52 @@ fn initFixedSizeLiterals(self: *Object, macho_file: *MachO) !void { | ... | @@ -463,28 +508,52 @@ fn initFixedSizeLiterals(self: *Object, macho_file: *MachO) !void { |
| 463 | ); | 508 | ); |
| 464 | return error.MalformedObject; | 509 | return error.MalformedObject; |
| 465 | } | 510 | } |
| 511 | |||
| 466 | var pos: u32 = 0; | 512 | var pos: u32 = 0; |
| 467 | while (pos < sect.size) : (pos += rec_size) { | 513 | var count: u32 = 0; |
| 468 | const atom_index = try self.addAtom(.{ | 514 | while (pos < sect.size) : ({ |
| 469 | .name = 0, | 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 | .n_sect = @intCast(n_sect), | 524 | .n_sect = @intCast(n_sect), |
| 471 | .off = pos, | 525 | .off = pos, |
| 472 | .size = rec_size, | 526 | .size = rec_size, |
| 473 | .alignment = sect.@"align", | 527 | .alignment = sect.@"align", |
| 474 | }, macho_file); | 528 | }); |
| 475 | try slice.items(.subsections)[n_sect].append(gpa, .{ | 529 | try self.atoms_indexes.append(allocator, atom_index); |
| 530 | try slice.items(.subsections)[n_sect].append(allocator, .{ | ||
| 476 | .atom = atom_index, | 531 | .atom = atom_index, |
| 477 | .off = pos, | 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 | const tracy = trace(@src()); | 554 | const tracy = trace(@src()); |
| 485 | defer tracy.end(); | 555 | defer tracy.end(); |
| 486 | 556 | ||
| 487 | const gpa = macho_file.base.comp.gpa; | ||
| 488 | const slice = self.sections.slice(); | 557 | const slice = self.sections.slice(); |
| 489 | 558 | ||
| 490 | for (slice.items(.header), 0..) |sect, n_sect| { | 559 | for (slice.items(.header), 0..) |sect, n_sect| { |
| ... | @@ -503,134 +572,171 @@ fn initPointerLiterals(self: *Object, macho_file: *MachO) !void { | ... | @@ -503,134 +572,171 @@ fn initPointerLiterals(self: *Object, macho_file: *MachO) !void { |
| 503 | 572 | ||
| 504 | for (0..num_ptrs) |i| { | 573 | for (0..num_ptrs) |i| { |
| 505 | const pos: u32 = @as(u32, @intCast(i)) * rec_size; | 574 | const pos: u32 = @as(u32, @intCast(i)) * rec_size; |
| 506 | const atom_index = try self.addAtom(.{ | 575 | |
| 507 | .name = 0, | 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 | .n_sect = @intCast(n_sect), | 582 | .n_sect = @intCast(n_sect), |
| 509 | .off = pos, | 583 | .off = pos, |
| 510 | .size = rec_size, | 584 | .size = rec_size, |
| 511 | .alignment = sect.@"align", | 585 | .alignment = sect.@"align", |
| 512 | }, macho_file); | 586 | }); |
| 513 | try slice.items(.subsections)[n_sect].append(gpa, .{ | 587 | try self.atoms_indexes.append(allocator, atom_index); |
| 588 | try slice.items(.subsections)[n_sect].append(allocator, .{ | ||
| 514 | .atom = atom_index, | 589 | .atom = atom_index, |
| 515 | .off = pos, | 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 | const gpa = macho_file.base.comp.gpa; | 615 | const gpa = macho_file.base.comp.gpa; |
| 616 | const file = macho_file.getFileHandle(self.file_handle); | ||
| 523 | 617 | ||
| 524 | var buffer = std.ArrayList(u8).init(gpa); | 618 | var buffer = std.ArrayList(u8).init(gpa); |
| 525 | defer buffer.deinit(); | 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 | const slice = self.sections.slice(); | 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 | if (isCstringLiteral(header) or isFixedSizeLiteral(header)) { | 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 | defer gpa.free(data); | 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 | for (subs.items) |sub| { | 640 | for (subs.items) |sub| { |
| 534 | const atom = macho_file.getAtom(sub.atom).?; | 641 | const atom = self.getAtom(sub.atom).?; |
| 535 | const atom_off = math.cast(usize, atom.off) orelse return error.Overflow; | 642 | const atom_off = math.cast(usize, atom.off) orelse return error.Overflow; |
| 536 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | 643 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 537 | const atom_data = data[atom_off..][0..atom_size]; | 644 | const atom_data = data[atom_off..][0..atom_size]; |
| 538 | const res = try lp.insert(gpa, header.type(), atom_data); | 645 | const res = try lp.insert(gpa, header.type(), atom_data); |
| 539 | if (!res.found_existing) { | 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; | 654 | atom.addExtra(.{ .literal_pool_index = res.index }, macho_file); |
| 543 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); | ||
| 544 | } | 655 | } |
| 545 | } else if (isPtrLiteral(header)) { | 656 | } else if (isPtrLiteral(header)) { |
| 546 | for (subs.items) |sub| { | 657 | for (subs.items) |sub| { |
| 547 | const atom = macho_file.getAtom(sub.atom).?; | 658 | const atom = self.getAtom(sub.atom).?; |
| 548 | const relocs = atom.getRelocs(macho_file); | 659 | const relocs = atom.getRelocs(macho_file); |
| 549 | assert(relocs.len == 1); | 660 | assert(relocs.len == 1); |
| 550 | const rel = relocs[0]; | 661 | const rel = relocs[0]; |
| 551 | const target = switch (rel.tag) { | 662 | const target = switch (rel.tag) { |
| 552 | .local => rel.target, | 663 | .local => rel.getTargetAtom(atom.*, macho_file), |
| 553 | .@"extern" => rel.getTargetSymbol(macho_file).atom, | 664 | .@"extern" => rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?, |
| 554 | }; | 665 | }; |
| 555 | const addend = math.cast(u32, rel.addend) orelse return error.Overflow; | 666 | const addend = math.cast(u32, rel.addend) orelse return error.Overflow; |
| 556 | const target_atom = macho_file.getAtom(target).?; | 667 | const target_size = math.cast(usize, target.size) orelse return error.Overflow; |
| 557 | const target_atom_size = math.cast(usize, target_atom.size) orelse return error.Overflow; | 668 | try buffer.ensureUnusedCapacity(target_size); |
| 558 | try buffer.ensureUnusedCapacity(target_atom_size); | 669 | buffer.resize(target_size) catch unreachable; |
| 559 | buffer.resize(target_atom_size) catch unreachable; | 670 | const gop = try sections_data.getOrPut(target.n_sect); |
| 560 | try target_atom.getData(macho_file, buffer.items); | 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 | const res = try lp.insert(gpa, header.type(), buffer.items[addend..]); | 682 | const res = try lp.insert(gpa, header.type(), buffer.items[addend..]); |
| 562 | buffer.clearRetainingCapacity(); | 683 | buffer.clearRetainingCapacity(); |
| 563 | if (!res.found_existing) { | 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; | 692 | atom.addExtra(.{ .literal_pool_index = res.index }, macho_file); |
| 567 | try atom.addExtra(.{ .literal_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 { | 698 | pub fn dedupLiterals(self: *Object, lp: MachO.LiteralPool, macho_file: *MachO) void { |
| 574 | for (self.atoms.items) |atom_index| { | 699 | const tracy = trace(@src()); |
| 575 | const atom = macho_file.getAtom(atom_index) orelse continue; | 700 | defer tracy.end(); |
| 701 | |||
| 702 | for (self.getAtoms()) |atom_index| { | ||
| 703 | const atom = self.getAtom(atom_index) orelse continue; | ||
| 576 | if (!atom.flags.alive) continue; | 704 | if (!atom.flags.alive) continue; |
| 577 | if (!atom.flags.relocs) continue; | ||
| 578 | 705 | ||
| 579 | const relocs = blk: { | 706 | const relocs = blk: { |
| 580 | const extra = atom.getExtra(macho_file).?; | 707 | const extra = atom.getExtra(macho_file); |
| 581 | const relocs = self.sections.items(.relocs)[atom.n_sect].items; | 708 | const relocs = self.sections.items(.relocs)[atom.n_sect].items; |
| 582 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; | 709 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; |
| 583 | }; | 710 | }; |
| 584 | for (relocs) |*rel| switch (rel.tag) { | 711 | for (relocs) |*rel| { |
| 585 | .local => { | 712 | if (rel.tag != .@"extern") continue; |
| 586 | const target = macho_file.getAtom(rel.target).?; | 713 | const target_sym_ref = rel.getTargetSymbolRef(atom.*, macho_file); |
| 587 | if (target.getLiteralPoolIndex(macho_file)) |lp_index| { | 714 | const file = target_sym_ref.getFile(macho_file) orelse continue; |
| 588 | const lp_atom = lp.getAtom(lp_index, macho_file); | 715 | if (file.getIndex() != self.index) continue; |
| 589 | if (target.atom_index != lp_atom.atom_index) { | 716 | const target_sym = target_sym_ref.getSymbol(macho_file).?; |
| 590 | lp_atom.alignment = lp_atom.alignment.max(target.alignment); | 717 | const target_atom = target_sym.getAtom(macho_file) orelse continue; |
| 591 | target.flags.alive = false; | 718 | const isec = target_atom.getInputSection(macho_file); |
| 592 | rel.target = lp_atom.atom_index; | 719 | if (!Object.isCstringLiteral(isec) and !Object.isFixedSizeLiteral(isec) and !Object.isPtrLiteral(isec)) continue; |
| 593 | } | 720 | const lp_index = target_atom.getExtra(macho_file).literal_pool_index; |
| 594 | } | 721 | const lp_sym = lp.getSymbol(lp_index, macho_file); |
| 595 | }, | 722 | const lp_atom_ref = lp_sym.atom_ref; |
| 596 | .@"extern" => { | 723 | if (target_atom.atom_index != lp_atom_ref.index or target_atom.file != lp_atom_ref.file) { |
| 597 | const target_sym = rel.getTargetSymbol(macho_file); | 724 | target_sym.atom_ref = lp_atom_ref; |
| 598 | if (target_sym.getAtom(macho_file)) |target_atom| { | 725 | } |
| 599 | if (target_atom.getLiteralPoolIndex(macho_file)) |lp_index| { | 726 | } |
| 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 | }; | ||
| 610 | } | 727 | } |
| 611 | } | ||
| 612 | 728 | ||
| 613 | const AddAtomArgs = struct { | 729 | for (self.symbols.items) |*sym| { |
| 614 | name: u32, | 730 | const atom = sym.getAtom(macho_file) orelse continue; |
| 615 | n_sect: u8, | 731 | const isec = atom.getInputSection(macho_file); |
| 616 | off: u64, | 732 | if (!Object.isCstringLiteral(isec) and !Object.isFixedSizeLiteral(isec) and !Object.isPtrLiteral(isec)) continue; |
| 617 | size: u64, | 733 | const lp_index = atom.getExtra(macho_file).literal_pool_index; |
| 618 | alignment: u32, | 734 | const lp_sym = lp.getSymbol(lp_index, macho_file); |
| 619 | }; | 735 | const lp_atom_ref = lp_sym.atom_ref; |
| 620 | 736 | if (atom.atom_index != lp_atom_ref.index or self.index != lp_atom_ref.file) { | |
| 621 | fn addAtom(self: *Object, args: AddAtomArgs, macho_file: *MachO) !Atom.Index { | 737 | sym.atom_ref = lp_atom_ref; |
| 622 | const gpa = macho_file.base.comp.gpa; | 738 | } |
| 623 | const atom_index = try macho_file.addAtom(); | 739 | } |
| 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; | ||
| 634 | } | 740 | } |
| 635 | 741 | ||
| 636 | pub fn findAtom(self: Object, addr: u64) ?Atom.Index { | 742 | pub fn findAtom(self: Object, addr: u64) ?Atom.Index { |
| ... | @@ -702,55 +808,61 @@ fn linkNlistToAtom(self: *Object, macho_file: *MachO) !void { | ... | @@ -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 | const tracy = trace(@src()); | 812 | const tracy = trace(@src()); |
| 707 | defer tracy.end(); | 813 | defer tracy.end(); |
| 708 | const gpa = macho_file.base.comp.gpa; | 814 | |
| 709 | const slice = self.symtab.slice(); | 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 | for (slice.items(.nlist), slice.items(.atom), 0..) |nlist, atom_index, i| { | 824 | for (slice.items(.nlist), slice.items(.atom), 0..) |nlist, atom_index, i| { |
| 714 | if (nlist.ext()) { | 825 | const index = self.addSymbolAssumeCapacity(); |
| 715 | const name = self.getString(nlist.n_strx); | 826 | const symbol = &self.symbols.items[index]; |
| 716 | const off = try macho_file.strings.insert(gpa, name); | 827 | symbol.value = nlist.n_value; |
| 717 | const gop = try macho_file.getOrCreateGlobal(off); | 828 | symbol.name = nlist.n_strx; |
| 718 | self.symbols.addOneAssumeCapacity().* = gop.index; | 829 | symbol.nlist_idx = @intCast(i); |
| 719 | if (nlist.undf() and nlist.weakRef()) { | 830 | symbol.extra = self.addSymbolExtraAssumeCapacity(.{}); |
| 720 | macho_file.getSymbol(gop.index).flags.weak_ref = true; | 831 | |
| 721 | } | 832 | if (self.getAtom(atom_index)) |atom| { |
| 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| { | ||
| 737 | assert(!nlist.abs()); | 833 | assert(!nlist.abs()); |
| 738 | symbol.value -= atom.getInputAddress(macho_file); | 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 | symbol.flags.abs = nlist.abs(); | 839 | symbol.flags.abs = nlist.abs(); |
| 840 | symbol.flags.tentative = nlist.tentative(); | ||
| 743 | symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip(); | 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 | if (nlist.sect() and | 847 | if (nlist.sect() and |
| 746 | self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES) | 848 | self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES) |
| 747 | { | 849 | { |
| 748 | symbol.flags.tlv = true; | 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 | const tracy = trace(@src()); | 866 | const tracy = trace(@src()); |
| 755 | defer tracy.end(); | 867 | defer tracy.end(); |
| 756 | 868 | ||
| ... | @@ -761,7 +873,7 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { | ... | @@ -761,7 +873,7 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 761 | fn find(fs: @This(), addr: u64) ?Symbol.Index { | 873 | fn find(fs: @This(), addr: u64) ?Symbol.Index { |
| 762 | // TODO binary search since we have the list sorted | 874 | // TODO binary search since we have the list sorted |
| 763 | for (fs.entries) |nlist| { | 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 | return null; | 878 | return null; |
| 767 | } | 879 | } |
| ... | @@ -776,14 +888,13 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { | ... | @@ -776,14 +888,13 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 776 | 888 | ||
| 777 | if (start == end) return; | 889 | if (start == end) return; |
| 778 | 890 | ||
| 779 | const gpa = macho_file.base.comp.gpa; | ||
| 780 | const syms = self.symtab.items(.nlist); | 891 | const syms = self.symtab.items(.nlist); |
| 781 | const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists }; | 892 | const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists }; |
| 782 | 893 | ||
| 783 | // We need to cache nlists by name so that we can properly resolve local N_GSYM stabs. | 894 | // We need to cache nlists by name so that we can properly resolve local N_GSYM stabs. |
| 784 | // What happens is `ld -r` will emit an N_GSYM stab for a symbol that may be either an | 895 | // What happens is `ld -r` will emit an N_GSYM stab for a symbol that may be either an |
| 785 | // external or private external. | 896 | // external or private external. |
| 786 | var addr_lookup = std.StringHashMap(u64).init(gpa); | 897 | var addr_lookup = std.StringHashMap(u64).init(allocator); |
| 787 | defer addr_lookup.deinit(); | 898 | defer addr_lookup.deinit(); |
| 788 | for (syms) |sym| { | 899 | for (syms) |sym| { |
| 789 | if (sym.sect() and (sym.ext() or sym.pext())) { | 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,17 +924,17 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 813 | switch (nlist.n_type) { | 924 | switch (nlist.n_type) { |
| 814 | macho.N_BNSYM => { | 925 | macho.N_BNSYM => { |
| 815 | stab.is_func = true; | 926 | stab.is_func = true; |
| 816 | stab.symbol = sym_lookup.find(nlist.n_value); | 927 | stab.index = sym_lookup.find(nlist.n_value); |
| 817 | // TODO validate | 928 | // TODO validate |
| 818 | i += 3; | 929 | i += 3; |
| 819 | }, | 930 | }, |
| 820 | macho.N_GSYM => { | 931 | macho.N_GSYM => { |
| 821 | stab.is_func = false; | 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 | macho.N_STSYM => { | 935 | macho.N_STSYM => { |
| 825 | stab.is_func = false; | 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 | else => { | 939 | else => { |
| 829 | try macho_file.reportParseError2(self.index, "unhandled symbol stab type 0x{x}", .{ | 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,29 +943,35 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 832 | return error.MalformedObject; | 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 | fn sortAtoms(self: *Object, macho_file: *MachO) !void { | 953 | fn sortAtoms(self: *Object, macho_file: *MachO) !void { |
| 843 | const lessThanAtom = struct { | 954 | const Ctx = struct { |
| 844 | fn lessThanAtom(ctx: *MachO, lhs: Atom.Index, rhs: Atom.Index) bool { | 955 | object: *Object, |
| 845 | return ctx.getAtom(lhs).?.getInputAddress(ctx) < ctx.getAtom(rhs).?.getInputAddress(ctx); | 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; | 962 | }; |
| 848 | mem.sort(Atom.Index, self.atoms.items, macho_file, lessThanAtom); | 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 | const tracy = trace(@src()); | 970 | const tracy = trace(@src()); |
| 853 | defer tracy.end(); | 971 | defer tracy.end(); |
| 854 | const cpu_arch = macho_file.getTarget().cpu.arch; | ||
| 855 | const slice = self.sections.slice(); | 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 | if (sect.nreloc == 0) continue; | 975 | if (sect.nreloc == 0) continue; |
| 859 | // We skip relocs for __DWARF since even in -r mode, the linker is expected to emit | 976 | // We skip relocs for __DWARF since even in -r mode, the linker is expected to emit |
| 860 | // debug symbol stabs in the relocatable. This made me curious why that is. For now, | 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,8 +980,8 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { |
| 863 | !mem.eql(u8, sect.sectName(), "__compact_unwind")) continue; | 980 | !mem.eql(u8, sect.sectName(), "__compact_unwind")) continue; |
| 864 | 981 | ||
| 865 | switch (cpu_arch) { | 982 | switch (cpu_arch) { |
| 866 | .x86_64 => try x86_64.parseRelocs(self, @intCast(n_sect), sect, out, macho_file), | 983 | .x86_64 => try x86_64.parseRelocs(self, sect, out, file, macho_file), |
| 867 | .aarch64 => try aarch64.parseRelocs(self, @intCast(n_sect), sect, out, macho_file), | 984 | .aarch64 => try aarch64.parseRelocs(self, sect, out, file, macho_file), |
| 868 | else => unreachable, | 985 | else => unreachable, |
| 869 | } | 986 | } |
| 870 | 987 | ||
| ... | @@ -876,7 +993,7 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { | ... | @@ -876,7 +993,7 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { |
| 876 | 993 | ||
| 877 | var next_reloc: u32 = 0; | 994 | var next_reloc: u32 = 0; |
| 878 | for (subsections.items) |subsection| { | 995 | for (subsections.items) |subsection| { |
| 879 | const atom = macho_file.getAtom(subsection.atom).?; | 996 | const atom = self.getAtom(subsection.atom).?; |
| 880 | if (!atom.flags.alive) continue; | 997 | if (!atom.flags.alive) continue; |
| 881 | if (next_reloc >= relocs.items.len) break; | 998 | if (next_reloc >= relocs.items.len) break; |
| 882 | const end_addr = atom.off + atom.size; | 999 | const end_addr = atom.off + atom.size; |
| ... | @@ -885,27 +1002,23 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { | ... | @@ -885,27 +1002,23 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { |
| 885 | while (next_reloc < relocs.items.len and relocs.items[next_reloc].offset < end_addr) : (next_reloc += 1) {} | 1002 | while (next_reloc < relocs.items.len and relocs.items[next_reloc].offset < end_addr) : (next_reloc += 1) {} |
| 886 | 1003 | ||
| 887 | const rel_count = next_reloc - rel_index; | 1004 | const rel_count = next_reloc - rel_index; |
| 888 | try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, macho_file); | 1005 | atom.addExtra(.{ .rel_index = @intCast(rel_index), .rel_count = @intCast(rel_count) }, macho_file); |
| 889 | atom.flags.relocs = true; | ||
| 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 | const tracy = trace(@src()); | 1011 | const tracy = trace(@src()); |
| 896 | defer tracy.end(); | 1012 | defer tracy.end(); |
| 897 | const gpa = macho_file.base.comp.gpa; | ||
| 898 | const nlists = self.symtab.items(.nlist); | 1013 | const nlists = self.symtab.items(.nlist); |
| 899 | const slice = self.sections.slice(); | 1014 | const slice = self.sections.slice(); |
| 900 | const sect = slice.items(.header)[sect_id]; | 1015 | const sect = slice.items(.header)[sect_id]; |
| 901 | const relocs = slice.items(.relocs)[sect_id]; | 1016 | const relocs = slice.items(.relocs)[sect_id]; |
| 902 | 1017 | ||
| 903 | // TODO: read into buffer directly | 1018 | const size = math.cast(usize, sect.size) orelse return error.Overflow; |
| 904 | const data = try self.getSectionData(sect_id, macho_file); | 1019 | try self.eh_frame_data.resize(allocator, size); |
| 905 | defer gpa.free(data); | 1020 | const amt = try file.preadAll(self.eh_frame_data.items, sect.offset + self.offset); |
| 906 | 1021 | if (amt != self.eh_frame_data.items.len) return error.InputOutput; | |
| 907 | try self.eh_frame_data.ensureTotalCapacityPrecise(gpa, data.len); | ||
| 908 | self.eh_frame_data.appendSliceAssumeCapacity(data); | ||
| 909 | 1022 | ||
| 910 | // Check for non-personality relocs in FDEs and apply them | 1023 | // Check for non-personality relocs in FDEs and apply them |
| 911 | for (relocs.items, 0..) |rel, i| { | 1024 | for (relocs.items, 0..) |rel, i| { |
| ... | @@ -937,12 +1050,12 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -937,12 +1050,12 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 937 | var it = eh_frame.Iterator{ .data = self.eh_frame_data.items }; | 1050 | var it = eh_frame.Iterator{ .data = self.eh_frame_data.items }; |
| 938 | while (try it.next()) |rec| { | 1051 | while (try it.next()) |rec| { |
| 939 | switch (rec.tag) { | 1052 | switch (rec.tag) { |
| 940 | .cie => try self.cies.append(gpa, .{ | 1053 | .cie => try self.cies.append(allocator, .{ |
| 941 | .offset = rec.offset, | 1054 | .offset = rec.offset, |
| 942 | .size = rec.size, | 1055 | .size = rec.size, |
| 943 | .file = self.index, | 1056 | .file = self.index, |
| 944 | }), | 1057 | }), |
| 945 | .fde => try self.fdes.append(gpa, .{ | 1058 | .fde => try self.fdes.append(allocator, .{ |
| 946 | .offset = rec.offset, | 1059 | .offset = rec.offset, |
| 947 | .size = rec.size, | 1060 | .size = rec.size, |
| 948 | .cie = undefined, | 1061 | .cie = undefined, |
| ... | @@ -987,7 +1100,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -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 | const tracy = trace(@src()); | 1104 | const tracy = trace(@src()); |
| 992 | defer tracy.end(); | 1105 | defer tracy.end(); |
| 993 | 1106 | ||
| ... | @@ -995,27 +1108,31 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -995,27 +1108,31 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 995 | ctx: *const Object, | 1108 | ctx: *const Object, |
| 996 | 1109 | ||
| 997 | fn find(fs: @This(), addr: u64) ?Symbol.Index { | 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 | const nlist = fs.ctx.symtab.items(.nlist)[i]; | 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 | return null; | 1115 | return null; |
| 1003 | } | 1116 | } |
| 1004 | }; | 1117 | }; |
| 1005 | 1118 | ||
| 1006 | const gpa = macho_file.base.comp.gpa; | 1119 | const header = self.sections.items(.header)[sect_id]; |
| 1007 | const data = try self.getSectionData(sect_id, macho_file); | 1120 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 1008 | defer gpa.free(data); | 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 | const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); | 1126 | const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); |
| 1010 | const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs]; | 1127 | const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs]; |
| 1011 | const sym_lookup = SymbolLookup{ .ctx = self }; | 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 | const relocs = self.sections.items(.relocs)[sect_id].items; | 1133 | const relocs = self.sections.items(.relocs)[sect_id].items; |
| 1017 | var reloc_idx: usize = 0; | 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 | const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry); | 1136 | const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry); |
| 1020 | const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry); | 1137 | const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry); |
| 1021 | const reloc_start = reloc_idx; | 1138 | const reloc_start = reloc_idx; |
| ... | @@ -1023,11 +1140,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -1023,11 +1140,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 1023 | relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1) | 1140 | relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1) |
| 1024 | {} | 1141 | {} |
| 1025 | 1142 | ||
| 1026 | out_index.* = try macho_file.addUnwindRecord(); | 1143 | const out_index = self.addUnwindRecordAssumeCapacity(); |
| 1027 | const out = macho_file.getUnwindRecord(out_index.*); | 1144 | self.unwind_records_indexes.appendAssumeCapacity(out_index); |
| 1145 | const out = self.getUnwindRecord(out_index); | ||
| 1028 | out.length = rec.rangeLength; | 1146 | out.length = rec.rangeLength; |
| 1029 | out.enc = .{ .enc = rec.compactUnwindEncoding }; | 1147 | out.enc = .{ .enc = rec.compactUnwindEncoding }; |
| 1030 | out.file = self.index; | ||
| 1031 | 1148 | ||
| 1032 | for (relocs[reloc_start..reloc_idx]) |rel| { | 1149 | for (relocs[reloc_start..reloc_idx]) |rel| { |
| 1033 | if (rel.type != .unsigned or rel.meta.length != 3) { | 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,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 | // Synthesise missing unwind records. | 1211 | // Synthesise missing unwind records. |
| 1095 | // The logic here is as follows: | 1212 | // The logic here is as follows: |
| 1096 | // 1. if an atom has unwind info record that is not DWARF, FDE is marked dead | 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,8 +1217,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1100 | 1217 | ||
| 1101 | const Superposition = struct { atom: Atom.Index, size: u64, cu: ?UnwindInfo.Record.Index = null, fde: ?Fde.Index = null }; | 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; | 1220 | var superposition = std.AutoArrayHashMap(u64, Superposition).init(allocator); |
| 1104 | var superposition = std.AutoArrayHashMap(u64, Superposition).init(gpa); | ||
| 1105 | defer superposition.deinit(); | 1221 | defer superposition.deinit(); |
| 1106 | 1222 | ||
| 1107 | const slice = self.symtab.slice(); | 1223 | const slice = self.symtab.slice(); |
| ... | @@ -1119,8 +1235,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -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| { | 1238 | for (self.unwind_records_indexes.items) |rec_index| { |
| 1123 | const rec = macho_file.getUnwindRecord(rec_index); | 1239 | const rec = self.getUnwindRecord(rec_index); |
| 1124 | const atom = rec.getAtom(macho_file); | 1240 | const atom = rec.getAtom(macho_file); |
| 1125 | const addr = atom.getInputAddress(macho_file) + rec.atom_offset; | 1241 | const addr = atom.getInputAddress(macho_file) + rec.atom_offset; |
| 1126 | superposition.getPtr(addr).?.cu = rec_index; | 1242 | superposition.getPtr(addr).?.cu = rec_index; |
| ... | @@ -1137,7 +1253,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1137,7 +1253,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1137 | const fde = &self.fdes.items[fde_index]; | 1253 | const fde = &self.fdes.items[fde_index]; |
| 1138 | 1254 | ||
| 1139 | if (meta.cu) |rec_index| { | 1255 | if (meta.cu) |rec_index| { |
| 1140 | const rec = macho_file.getUnwindRecord(rec_index); | 1256 | const rec = self.getUnwindRecord(rec_index); |
| 1141 | if (!rec.enc.isDwarf(macho_file)) { | 1257 | if (!rec.enc.isDwarf(macho_file)) { |
| 1142 | // Mark FDE dead | 1258 | // Mark FDE dead |
| 1143 | fde.alive = false; | 1259 | fde.alive = false; |
| ... | @@ -1147,15 +1263,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1147,15 +1263,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1147 | } | 1263 | } |
| 1148 | } else { | 1264 | } else { |
| 1149 | // Synthesise new unwind info record | 1265 | // Synthesise new unwind info record |
| 1150 | const rec_index = try macho_file.addUnwindRecord(); | 1266 | const rec_index = try self.addUnwindRecord(allocator); |
| 1151 | const rec = macho_file.getUnwindRecord(rec_index); | 1267 | const rec = self.getUnwindRecord(rec_index); |
| 1152 | try self.unwind_records.append(gpa, rec_index); | 1268 | try self.unwind_records_indexes.append(allocator, rec_index); |
| 1153 | rec.length = @intCast(meta.size); | 1269 | rec.length = @intCast(meta.size); |
| 1154 | rec.atom = fde.atom; | 1270 | rec.atom = fde.atom; |
| 1155 | rec.atom_offset = fde.atom_offset; | 1271 | rec.atom_offset = fde.atom_offset; |
| 1156 | rec.fde = fde_index; | 1272 | rec.fde = fde_index; |
| 1157 | rec.file = fde.file; | 1273 | switch (cpu_arch) { |
| 1158 | switch (macho_file.getTarget().cpu.arch) { | ||
| 1159 | .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF), | 1274 | .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF), |
| 1160 | .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF), | 1275 | .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF), |
| 1161 | else => unreachable, | 1276 | else => unreachable, |
| ... | @@ -1163,10 +1278,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1163,10 +1278,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1163 | } | 1278 | } |
| 1164 | } else if (meta.cu == null and meta.fde == null) { | 1279 | } else if (meta.cu == null and meta.fde == null) { |
| 1165 | // Create a null record | 1280 | // Create a null record |
| 1166 | const rec_index = try macho_file.addUnwindRecord(); | 1281 | const rec_index = try self.addUnwindRecord(allocator); |
| 1167 | const rec = macho_file.getUnwindRecord(rec_index); | 1282 | const rec = self.getUnwindRecord(rec_index); |
| 1168 | const atom = macho_file.getAtom(meta.atom).?; | 1283 | const atom = self.getAtom(meta.atom).?; |
| 1169 | try self.unwind_records.append(gpa, rec_index); | 1284 | try self.unwind_records_indexes.append(allocator, rec_index); |
| 1170 | rec.length = @intCast(meta.size); | 1285 | rec.length = @intCast(meta.size); |
| 1171 | rec.atom = meta.atom; | 1286 | rec.atom = meta.atom; |
| 1172 | rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file)); | 1287 | rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file)); |
| ... | @@ -1174,30 +1289,35 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1174,30 +1289,35 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1174 | } | 1289 | } |
| 1175 | } | 1290 | } |
| 1176 | 1291 | ||
| 1177 | const sortFn = struct { | 1292 | const SortCtx = struct { |
| 1178 | fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool { | 1293 | object: *Object, |
| 1179 | const lhs = ctx.getUnwindRecord(lhs_index); | 1294 | mfile: *MachO, |
| 1180 | const rhs = ctx.getUnwindRecord(rhs_index); | 1295 | |
| 1181 | const lhsa = lhs.getAtom(ctx); | 1296 | fn sort(ctx: @This(), lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool { |
| 1182 | const rhsa = rhs.getAtom(ctx); | 1297 | const lhs = ctx.object.getUnwindRecord(lhs_index); |
| 1183 | return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset; | 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; | 1303 | }; |
| 1186 | mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn); | 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 | // Associate unwind records to atoms | 1309 | // Associate unwind records to atoms |
| 1189 | var next_cu: u32 = 0; | 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 | const start = next_cu; | 1312 | const start = next_cu; |
| 1192 | const rec_index = self.unwind_records.items[start]; | 1313 | const rec_index = self.unwind_records_indexes.items[start]; |
| 1193 | const rec = macho_file.getUnwindRecord(rec_index); | 1314 | const rec = self.getUnwindRecord(rec_index); |
| 1194 | while (next_cu < self.unwind_records.items.len and | 1315 | while (next_cu < self.unwind_records_indexes.items.len and |
| 1195 | macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1) | 1316 | self.getUnwindRecord(self.unwind_records_indexes.items[next_cu]).atom == rec.atom) : (next_cu += 1) |
| 1196 | {} | 1317 | {} |
| 1197 | 1318 | ||
| 1198 | const atom = rec.getAtom(macho_file); | 1319 | const atom = rec.getAtom(macho_file); |
| 1199 | try atom.addExtra(.{ .unwind_index = start, .unwind_count = next_cu - start }, macho_file); | 1320 | atom.addExtra(.{ .unwind_index = start, .unwind_count = next_cu - start }, macho_file); |
| 1200 | atom.flags.unwind = true; | ||
| 1201 | } | 1321 | } |
| 1202 | } | 1322 | } |
| 1203 | 1323 | ||
| ... | @@ -1205,7 +1325,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -1205,7 +1325,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 1205 | /// and record that so that we can emit symbol stabs. | 1325 | /// and record that so that we can emit symbol stabs. |
| 1206 | /// TODO in the future, we want parse debug info and debug line sections so that | 1326 | /// TODO in the future, we want parse debug info and debug line sections so that |
| 1207 | /// we can provide nice error locations to the user. | 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 | const tracy = trace(@src()); | 1329 | const tracy = trace(@src()); |
| 1210 | defer tracy.end(); | 1330 | defer tracy.end(); |
| 1211 | 1331 | ||
| ... | @@ -1224,11 +1344,34 @@ pub fn parseDebugInfo(self: *Object, macho_file: *MachO) !void { | ... | @@ -1224,11 +1344,34 @@ pub fn parseDebugInfo(self: *Object, macho_file: *MachO) !void { |
| 1224 | 1344 | ||
| 1225 | if (debug_info_index == null or debug_abbrev_index == null) return; | 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 | defer gpa.free(debug_info); | 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 | defer gpa.free(debug_abbrev); | 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 | defer gpa.free(debug_str); | 1375 | defer gpa.free(debug_str); |
| 1233 | 1376 | ||
| 1234 | self.compile_unit = self.findCompileUnit(.{ | 1377 | self.compile_unit = self.findCompileUnit(.{ |
| ... | @@ -1334,87 +1477,55 @@ fn findCompileUnit(self: *Object, args: struct { | ... | @@ -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 | const tracy = trace(@src()); | 1481 | const tracy = trace(@src()); |
| 1339 | defer tracy.end(); | 1482 | defer tracy.end(); |
| 1340 | 1483 | ||
| 1341 | for (self.symbols.items, 0..) |index, i| { | 1484 | const gpa = macho_file.base.comp.gpa; |
| 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]; | ||
| 1345 | 1485 | ||
| 1486 | for (self.symtab.items(.nlist), self.symtab.items(.atom), self.globals.items, 0..) |nlist, atom_index, *global, i| { | ||
| 1346 | if (!nlist.ext()) continue; | 1487 | if (!nlist.ext()) continue; |
| 1347 | if (nlist.undf() and !nlist.tentative()) continue; | ||
| 1348 | if (nlist.sect()) { | 1488 | if (nlist.sect()) { |
| 1349 | const atom = macho_file.getAtom(atom_index).?; | 1489 | const atom = self.getAtom(atom_index).?; |
| 1350 | if (!atom.flags.alive) continue; | 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 | if (self.asFile().getSymbolRank(.{ | 1508 | if (self.asFile().getSymbolRank(.{ |
| 1355 | .archive = !self.alive, | 1509 | .archive = !self.alive, |
| 1356 | .weak = nlist.weakDef(), | 1510 | .weak = nlist.weakDef(), |
| 1357 | .tentative = nlist.tentative(), | 1511 | .tentative = nlist.tentative(), |
| 1358 | }) < symbol.getSymbolRank(macho_file)) { | 1512 | }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) { |
| 1359 | const value = if (nlist.sect()) blk: { | 1513 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; |
| 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; | ||
| 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 | pub fn markLive(self: *Object, macho_file: *MachO) void { | 1518 | pub fn markLive(self: *Object, macho_file: *MachO) void { |
| 1409 | const tracy = trace(@src()); | 1519 | const tracy = trace(@src()); |
| 1410 | defer tracy.end(); | 1520 | defer tracy.end(); |
| 1411 | 1521 | ||
| 1412 | for (self.symbols.items, 0..) |index, nlist_idx| { | 1522 | for (0..self.symbols.items.len) |i| { |
| 1413 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | 1523 | const nlist = self.symtab.items(.nlist)[i]; |
| 1414 | if (!nlist.ext()) continue; | 1524 | if (!nlist.ext()) continue; |
| 1415 | 1525 | ||
| 1416 | const sym = macho_file.getSymbol(index); | 1526 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 1417 | const file = sym.getFile(macho_file) orelse continue; | 1527 | const file = ref.getFile(macho_file) orelse continue; |
| 1528 | const sym = ref.getSymbol(macho_file).?; | ||
| 1418 | const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative); | 1529 | const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative); |
| 1419 | if (should_keep and file == .object and !file.object.alive) { | 1530 | if (should_keep and file == .object and !file.object.alive) { |
| 1420 | file.object.alive = true; | 1531 | file.object.alive = true; |
| ... | @@ -1423,38 +1534,36 @@ pub fn markLive(self: *Object, macho_file: *MachO) void { | ... | @@ -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 { | 1537 | pub fn mergeSymbolVisibility(self: *Object, macho_file: *MachO) void { |
| 1427 | for (self.symbols.items, 0..) |index, nlist_idx| { | 1538 | const tracy = trace(@src()); |
| 1428 | const sym = macho_file.getSymbol(index); | 1539 | defer tracy.end(); |
| 1429 | if (sym.visibility != .global) continue; | ||
| 1430 | const file = sym.getFile(macho_file) orelse continue; | ||
| 1431 | if (file.getIndex() == self.index) continue; | ||
| 1432 | 1540 | ||
| 1433 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | 1541 | for (self.symbols.items, 0..) |sym, i| { |
| 1434 | if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) { | 1542 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 1435 | const gop = try dupes.getOrPut(index); | 1543 | const global = ref.getSymbol(macho_file) orelse continue; |
| 1436 | if (!gop.found_existing) { | 1544 | if (sym.visibility.rank() < global.visibility.rank()) { |
| 1437 | gop.value_ptr.* = .{}; | 1545 | global.visibility = sym.visibility; |
| 1438 | } | 1546 | } |
| 1439 | try gop.value_ptr.append(macho_file.base.comp.gpa, self.index); | 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 | const tracy = trace(@src()); | 1554 | const tracy = trace(@src()); |
| 1446 | defer tracy.end(); | 1555 | defer tracy.end(); |
| 1447 | 1556 | ||
| 1448 | for (self.atoms.items) |atom_index| { | 1557 | for (self.getAtoms()) |atom_index| { |
| 1449 | const atom = macho_file.getAtom(atom_index).?; | 1558 | const atom = self.getAtom(atom_index) orelse continue; |
| 1450 | if (!atom.flags.alive) continue; | 1559 | if (!atom.flags.alive) continue; |
| 1451 | const sect = atom.getInputSection(macho_file); | 1560 | const sect = atom.getInputSection(macho_file); |
| 1452 | if (sect.isZerofill()) continue; | 1561 | if (sect.isZerofill()) continue; |
| 1453 | try atom.scanRelocs(macho_file); | 1562 | try atom.scanRelocs(macho_file); |
| 1454 | } | 1563 | } |
| 1455 | 1564 | ||
| 1456 | for (self.unwind_records.items) |rec_index| { | 1565 | for (self.unwind_records_indexes.items) |rec_index| { |
| 1457 | const rec = macho_file.getUnwindRecord(rec_index); | 1566 | const rec = self.getUnwindRecord(rec_index); |
| 1458 | if (!rec.alive) continue; | 1567 | if (!rec.alive) continue; |
| 1459 | if (rec.getFde(macho_file)) |fde| { | 1568 | if (rec.getFde(macho_file)) |fde| { |
| 1460 | if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| { | 1569 | if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| { |
| ... | @@ -1471,38 +1580,35 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { | ... | @@ -1471,38 +1580,35 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { |
| 1471 | defer tracy.end(); | 1580 | defer tracy.end(); |
| 1472 | const gpa = macho_file.base.comp.gpa; | 1581 | const gpa = macho_file.base.comp.gpa; |
| 1473 | 1582 | ||
| 1474 | for (self.symbols.items, 0..) |index, i| { | 1583 | for (self.symbols.items, self.globals.items, 0..) |*sym, off, i| { |
| 1475 | const sym = macho_file.getSymbol(index); | ||
| 1476 | if (!sym.flags.tentative) continue; | 1584 | if (!sym.flags.tentative) continue; |
| 1477 | const sym_file = sym.getFile(macho_file).?; | 1585 | if (macho_file.resolver.get(off).?.file != self.index) continue; |
| 1478 | if (sym_file.getIndex() != self.index) continue; | ||
| 1479 | 1586 | ||
| 1480 | const nlist_idx = @as(Symbol.Index, @intCast(i)); | 1587 | const nlist_idx = @as(Symbol.Index, @intCast(i)); |
| 1481 | const nlist = &self.symtab.items(.nlist)[nlist_idx]; | 1588 | const nlist = &self.symtab.items(.nlist)[nlist_idx]; |
| 1482 | const nlist_atom = &self.symtab.items(.atom)[nlist_idx]; | 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 | const name = try std.fmt.allocPrintZ(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)}); | 1591 | const name = try std.fmt.allocPrintZ(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)}); |
| 1488 | defer gpa.free(name); | 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 | const n_sect = try self.addSection(gpa, "__DATA", "__common"); | 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 | const sect = &self.sections.items(.header)[n_sect]; | 1605 | const sect = &self.sections.items(.header)[n_sect]; |
| 1498 | sect.flags = macho.S_ZEROFILL; | 1606 | sect.flags = macho.S_ZEROFILL; |
| 1499 | sect.size = atom.size; | 1607 | sect.size = nlist.n_value; |
| 1500 | sect.@"align" = atom.alignment.toLog2Units(); | 1608 | sect.@"align" = alignment; |
| 1501 | atom.n_sect = n_sect; | ||
| 1502 | 1609 | ||
| 1503 | sym.value = 0; | 1610 | sym.value = 0; |
| 1504 | sym.atom = atom_index; | 1611 | sym.atom_ref = .{ .index = atom_index, .file = self.index }; |
| 1505 | sym.flags.global = true; | ||
| 1506 | sym.flags.weak = false; | 1612 | sym.flags.weak = false; |
| 1507 | sym.flags.weak_ref = false; | 1613 | sym.flags.weak_ref = false; |
| 1508 | sym.flags.tentative = false; | 1614 | sym.flags.tentative = false; |
| ... | @@ -1516,8 +1622,8 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { | ... | @@ -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 { | 1625 | fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname: []const u8) !u8 { |
| 1520 | const n_sect = @as(u32, @intCast(try self.sections.addOne(allocator))); | 1626 | const n_sect = @as(u8, @intCast(try self.sections.addOne(allocator))); |
| 1521 | self.sections.set(n_sect, .{ | 1627 | self.sections.set(n_sect, .{ |
| 1522 | .header = .{ | 1628 | .header = .{ |
| 1523 | .sectname = MachO.makeStaticString(sectname), | 1629 | .sectname = MachO.makeStaticString(sectname), |
| ... | @@ -1532,12 +1638,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { | ... | @@ -1532,12 +1638,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1532 | defer tracy.end(); | 1638 | defer tracy.end(); |
| 1533 | 1639 | ||
| 1534 | const gpa = macho_file.base.comp.gpa; | 1640 | const gpa = macho_file.base.comp.gpa; |
| 1535 | const offset = if (self.archive) |ar| ar.offset else 0; | ||
| 1536 | const handle = macho_file.getFileHandle(self.file_handle); | 1641 | const handle = macho_file.getFileHandle(self.file_handle); |
| 1537 | 1642 | ||
| 1538 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; | 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 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; | 1646 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 1542 | } | 1647 | } |
| 1543 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; | 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,7 +1663,7 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1558 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); | 1663 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 1559 | defer gpa.free(lc_buffer); | 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 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; | 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,14 +1676,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1571 | const cmd = lc.cast(macho.symtab_command).?; | 1676 | const cmd = lc.cast(macho.symtab_command).?; |
| 1572 | try self.strtab.resize(gpa, cmd.strsize); | 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 | if (amt != self.strtab.items.len) return error.InputOutput; | 1680 | if (amt != self.strtab.items.len) return error.InputOutput; |
| 1576 | } | 1681 | } |
| 1577 | 1682 | ||
| 1578 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); | 1683 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); |
| 1579 | defer gpa.free(symtab_buffer); | 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 | if (amt != symtab_buffer.len) return error.InputOutput; | 1687 | if (amt != symtab_buffer.len) return error.InputOutput; |
| 1583 | } | 1688 | } |
| 1584 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; | 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,7 +1718,7 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, macho_file: *M |
| 1613 | } | 1718 | } |
| 1614 | 1719 | ||
| 1615 | pub fn updateArSize(self: *Object, macho_file: *MachO) !void { | 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 | const file = macho_file.getFileHandle(self.file_handle); | 1722 | const file = macho_file.getFileHandle(self.file_handle); |
| 1618 | break :size (try file.stat()).size; | 1723 | break :size (try file.stat()).size; |
| 1619 | }; | 1724 | }; |
| ... | @@ -1622,7 +1727,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { | ... | @@ -1622,7 +1727,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { |
| 1622 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { | 1727 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { |
| 1623 | // Header | 1728 | // Header |
| 1624 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; | 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 | try Archive.writeHeader(self.path, size, ar_format, writer); | 1730 | try Archive.writeHeader(self.path, size, ar_format, writer); |
| 1627 | // Data | 1731 | // Data |
| 1628 | const file = macho_file.getFileHandle(self.file_handle); | 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,72 +1734,75 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ |
| 1630 | const gpa = macho_file.base.comp.gpa; | 1734 | const gpa = macho_file.base.comp.gpa; |
| 1631 | const data = try gpa.alloc(u8, size); | 1735 | const data = try gpa.alloc(u8, size); |
| 1632 | defer gpa.free(data); | 1736 | defer gpa.free(data); |
| 1633 | const amt = try file.preadAll(data, offset); | 1737 | const amt = try file.preadAll(data, self.offset); |
| 1634 | if (amt != size) return error.InputOutput; | 1738 | if (amt != size) return error.InputOutput; |
| 1635 | try writer.writeAll(data); | 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 | const tracy = trace(@src()); | 1743 | const tracy = trace(@src()); |
| 1640 | defer tracy.end(); | 1744 | defer tracy.end(); |
| 1641 | 1745 | ||
| 1642 | for (self.symbols.items) |sym_index| { | 1746 | const is_obj = macho_file.base.isObject(); |
| 1643 | const sym = macho_file.getSymbol(sym_index); | 1747 | |
| 1644 | const file = sym.getFile(macho_file) orelse continue; | 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 | if (file.getIndex() != self.index) continue; | 1751 | if (file.getIndex() != self.index) continue; |
| 1646 | if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; | 1752 | if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; |
| 1647 | if (sym.isSymbolStab(macho_file)) continue; | 1753 | if (sym.isSymbolStab(macho_file)) continue; |
| 1648 | const name = sym.getName(macho_file); | 1754 | const name = sym.getName(macho_file); |
| 1755 | if (name.len == 0) continue; | ||
| 1649 | // TODO in -r mode, we actually want to merge symbol names and emit only one | 1756 | // TODO in -r mode, we actually want to merge symbol names and emit only one |
| 1650 | // work it out when emitting relocs | 1757 | // work it out when emitting relocs |
| 1651 | if (name.len > 0 and | 1758 | if ((name[0] == 'L' or name[0] == 'l' or |
| 1652 | (name[0] == 'L' or name[0] == 'l' or | ||
| 1653 | mem.startsWith(u8, name, "_OBJC_SELECTOR_REFERENCES_")) and | 1759 | mem.startsWith(u8, name, "_OBJC_SELECTOR_REFERENCES_")) and |
| 1654 | !macho_file.base.isObject()) continue; | 1760 | !is_obj) |
| 1761 | continue; | ||
| 1655 | sym.flags.output_symtab = true; | 1762 | sym.flags.output_symtab = true; |
| 1656 | if (sym.isLocal()) { | 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 | self.output_symtab_ctx.nlocals += 1; | 1765 | self.output_symtab_ctx.nlocals += 1; |
| 1659 | } else if (sym.flags.@"export") { | 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 | self.output_symtab_ctx.nexports += 1; | 1768 | self.output_symtab_ctx.nexports += 1; |
| 1662 | } else { | 1769 | } else { |
| 1663 | assert(sym.flags.import); | 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 | self.output_symtab_ctx.nimports += 1; | 1772 | self.output_symtab_ctx.nimports += 1; |
| 1666 | } | 1773 | } |
| 1667 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1)); | 1774 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1)); |
| 1668 | } | 1775 | } |
| 1669 | 1776 | ||
| 1670 | if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo()) | 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 | if (self.compile_unit) |cu| { | 1782 | if (self.compile_unit) |cu| { |
| 1676 | const comp_dir = cu.getCompDir(self); | 1783 | const comp_dir = cu.getCompDir(self.*); |
| 1677 | const tu_name = cu.getTuName(self); | 1784 | const tu_name = cu.getTuName(self.*); |
| 1678 | 1785 | ||
| 1679 | self.output_symtab_ctx.nstabs += 4; // N_SO, N_SO, N_OSO, N_SO | 1786 | self.output_symtab_ctx.nstabs += 4; // N_SO, N_SO, N_OSO, N_SO |
| 1680 | self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir | 1787 | self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir |
| 1681 | self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name | 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 | self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1)); | 1791 | self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1)); |
| 1685 | } else { | 1792 | } else { |
| 1686 | self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1)); | 1793 | self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1)); |
| 1687 | } | 1794 | } |
| 1688 | 1795 | ||
| 1689 | for (self.symbols.items) |sym_index| { | 1796 | for (self.symbols.items, 0..) |sym, i| { |
| 1690 | const sym = macho_file.getSymbol(sym_index); | 1797 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 1691 | const file = sym.getFile(macho_file) orelse continue; | 1798 | const file = ref.getFile(macho_file) orelse continue; |
| 1692 | if (file.getIndex() != self.index) continue; | 1799 | if (file.getIndex() != self.index) continue; |
| 1693 | if (!sym.flags.output_symtab) continue; | 1800 | if (!sym.flags.output_symtab) continue; |
| 1694 | if (macho_file.base.isObject()) { | 1801 | if (macho_file.base.isObject()) { |
| 1695 | const name = sym.getName(macho_file); | 1802 | const name = sym.getName(macho_file); |
| 1696 | if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue; | 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 | if (sect.isCode()) { | 1806 | if (sect.isCode()) { |
| 1700 | self.output_symtab_ctx.nstabs += 4; // N_BNSYM, N_FUN, N_FUN, N_ENSYM | 1807 | self.output_symtab_ctx.nstabs += 4; // N_BNSYM, N_FUN, N_FUN, N_ENSYM |
| 1701 | } else if (sym.visibility == .global) { | 1808 | } else if (sym.visibility == .global) { |
| ... | @@ -1709,12 +1816,12 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { | ... | @@ -1709,12 +1816,12 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { |
| 1709 | 1816 | ||
| 1710 | for (self.stab_files.items) |sf| { | 1817 | for (self.stab_files.items) |sf| { |
| 1711 | self.output_symtab_ctx.nstabs += 4; // N_SO, N_SO, N_OSO, N_SO | 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 | 1819 | 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 | 1820 | 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 | 1821 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getOsoPath(self.*).len + 1)); // path |
| 1715 | 1822 | ||
| 1716 | for (sf.stabs.items) |stab| { | 1823 | for (sf.stabs.items) |stab| { |
| 1717 | const sym = stab.getSymbol(macho_file) orelse continue; | 1824 | const sym = stab.getSymbol(self.*) orelse continue; |
| 1718 | const file = sym.getFile(macho_file).?; | 1825 | const file = sym.getFile(macho_file).?; |
| 1719 | if (file.getIndex() != self.index) continue; | 1826 | if (file.getIndex() != self.index) continue; |
| 1720 | if (!sym.flags.output_symtab) continue; | 1827 | if (!sym.flags.output_symtab) continue; |
| ... | @@ -1725,28 +1832,212 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { | ... | @@ -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 | const tracy = trace(@src()); | 1836 | const tracy = trace(@src()); |
| 1730 | defer tracy.end(); | 1837 | defer tracy.end(); |
| 1731 | 1838 | ||
| 1732 | for (self.symbols.items) |sym_index| { | 1839 | const gpa = macho_file.base.comp.gpa; |
| 1733 | const sym = macho_file.getSymbol(sym_index); | 1840 | const headers = self.sections.items(.header); |
| 1734 | const file = sym.getFile(macho_file) orelse continue; | 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 | if (file.getIndex() != self.index) continue; | 2024 | if (file.getIndex() != self.index) continue; |
| 1736 | const idx = sym.getOutputSymtabIndex(macho_file) orelse continue; | 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 | const out_sym = &ctx.symtab.items[idx]; | 2026 | const out_sym = &ctx.symtab.items[idx]; |
| 1741 | out_sym.n_strx = n_strx; | 2027 | out_sym.n_strx = n_strx; |
| 1742 | sym.setOutputSym(macho_file, out_sym); | 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 | if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo()) | 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 | const writeFuncStab = struct { | 2041 | const writeFuncStab = struct { |
| 1751 | inline fn writeFuncStab( | 2042 | inline fn writeFuncStab( |
| 1752 | n_strx: u32, | 2043 | n_strx: u32, |
| ... | @@ -1788,6 +2079,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1788,6 +2079,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1788 | }.writeFuncStab; | 2079 | }.writeFuncStab; |
| 1789 | 2080 | ||
| 1790 | var index = self.output_symtab_ctx.istab; | 2081 | var index = self.output_symtab_ctx.istab; |
| 2082 | var n_strx = stroff; | ||
| 1791 | 2083 | ||
| 1792 | if (self.compile_unit) |cu| { | 2084 | if (self.compile_unit) |cu| { |
| 1793 | const comp_dir = cu.getCompDir(self); | 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,9 +2087,6 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1795 | 2087 | ||
| 1796 | // Open scope | 2088 | // Open scope |
| 1797 | // N_SO comp_dir | 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 | ctx.symtab.items[index] = .{ | 2090 | ctx.symtab.items[index] = .{ |
| 1802 | .n_strx = n_strx, | 2091 | .n_strx = n_strx, |
| 1803 | .n_type = macho.N_SO, | 2092 | .n_type = macho.N_SO, |
| ... | @@ -1806,11 +2095,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1806,11 +2095,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1806 | .n_value = 0, | 2095 | .n_value = 0, |
| 1807 | }; | 2096 | }; |
| 1808 | index += 1; | 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 | // N_SO tu_name | 2102 | // N_SO tu_name |
| 1810 | n_strx = @as(u32, @intCast(ctx.strtab.items.len)); | 2103 | macho_file.symtab.items[index] = .{ |
| 1811 | ctx.strtab.appendSliceAssumeCapacity(tu_name); | ||
| 1812 | ctx.strtab.appendAssumeCapacity(0); | ||
| 1813 | ctx.symtab.items[index] = .{ | ||
| 1814 | .n_strx = n_strx, | 2104 | .n_strx = n_strx, |
| 1815 | .n_type = macho.N_SO, | 2105 | .n_type = macho.N_SO, |
| 1816 | .n_sect = 0, | 2106 | .n_sect = 0, |
| ... | @@ -1818,18 +2108,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1818,18 +2108,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1818 | .n_value = 0, | 2108 | .n_value = 0, |
| 1819 | }; | 2109 | }; |
| 1820 | index += 1; | 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 | // N_OSO path | 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 | ctx.symtab.items[index] = .{ | 2116 | ctx.symtab.items[index] = .{ |
| 1834 | .n_strx = n_strx, | 2117 | .n_strx = n_strx, |
| 1835 | .n_type = macho.N_OSO, | 2118 | .n_type = macho.N_OSO, |
| ... | @@ -1838,23 +2121,40 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1838,23 +2121,40 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1838 | .n_value = self.mtime, | 2121 | .n_value = self.mtime, |
| 1839 | }; | 2122 | }; |
| 1840 | index += 1; | 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| { | 2142 | for (self.symbols.items, 0..) |sym, i| { |
| 1843 | const sym = macho_file.getSymbol(sym_index); | 2143 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 1844 | const file = sym.getFile(macho_file) orelse continue; | 2144 | const file = ref.getFile(macho_file) orelse continue; |
| 1845 | if (file.getIndex() != self.index) continue; | 2145 | if (file.getIndex() != self.index) continue; |
| 1846 | if (!sym.flags.output_symtab) continue; | 2146 | if (!sym.flags.output_symtab) continue; |
| 1847 | if (macho_file.base.isObject()) { | 2147 | if (macho_file.base.isObject()) { |
| 1848 | const name = sym.getName(macho_file); | 2148 | const name = sym.getName(macho_file); |
| 1849 | if (name.len > 0 and (name[0] == 'L' or name[0] == 'l')) continue; | 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 | const sym_n_strx = n_strx: { | 2152 | const sym_n_strx = n_strx: { |
| 1853 | const symtab_index = sym.getOutputSymtabIndex(macho_file).?; | 2153 | const symtab_index = sym.getOutputSymtabIndex(macho_file).?; |
| 1854 | const osym = ctx.symtab.items[symtab_index]; | 2154 | const osym = ctx.symtab.items[symtab_index]; |
| 1855 | break :n_strx osym.n_strx; | 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 | const sym_n_value = sym.getAddress(.{}, macho_file); | 2158 | const sym_n_value = sym.getAddress(.{}, macho_file); |
| 1859 | const sym_size = sym.getSize(macho_file); | 2159 | const sym_size = sym.getSize(macho_file); |
| 1860 | if (sect.isCode()) { | 2160 | if (sect.isCode()) { |
| ... | @@ -1894,11 +2194,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1894,11 +2194,12 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1894 | assert(self.hasSymbolStabs()); | 2194 | assert(self.hasSymbolStabs()); |
| 1895 | 2195 | ||
| 1896 | for (self.stab_files.items) |sf| { | 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 | // Open scope | 2201 | // Open scope |
| 1898 | // N_SO comp_dir | 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 | ctx.symtab.items[index] = .{ | 2203 | ctx.symtab.items[index] = .{ |
| 1903 | .n_strx = n_strx, | 2204 | .n_strx = n_strx, |
| 1904 | .n_type = macho.N_SO, | 2205 | .n_type = macho.N_SO, |
| ... | @@ -1907,10 +2208,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1907,10 +2208,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1907 | .n_value = 0, | 2208 | .n_value = 0, |
| 1908 | }; | 2209 | }; |
| 1909 | index += 1; | 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 | // N_SO tu_name | 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 | ctx.symtab.items[index] = .{ | 2216 | ctx.symtab.items[index] = .{ |
| 1915 | .n_strx = n_strx, | 2217 | .n_strx = n_strx, |
| 1916 | .n_type = macho.N_SO, | 2218 | .n_type = macho.N_SO, |
| ... | @@ -1919,10 +2221,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1919,10 +2221,11 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1919 | .n_value = 0, | 2221 | .n_value = 0, |
| 1920 | }; | 2222 | }; |
| 1921 | index += 1; | 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 | // N_OSO path | 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 | ctx.symtab.items[index] = .{ | 2229 | ctx.symtab.items[index] = .{ |
| 1927 | .n_strx = n_strx, | 2230 | .n_strx = n_strx, |
| 1928 | .n_type = macho.N_OSO, | 2231 | .n_type = macho.N_OSO, |
| ... | @@ -1931,9 +2234,13 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -1931,9 +2234,13 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1931 | .n_value = sf.getOsoModTime(self), | 2234 | .n_value = sf.getOsoModTime(self), |
| 1932 | }; | 2235 | }; |
| 1933 | index += 1; | 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 | for (sf.stabs.items) |stab| { | 2242 | for (sf.stabs.items) |stab| { |
| 1936 | const sym = stab.getSymbol(macho_file) orelse continue; | 2243 | const sym = stab.getSymbol(self) orelse continue; |
| 1937 | const file = sym.getFile(macho_file).?; | 2244 | const file = sym.getFile(macho_file).?; |
| 1938 | if (file.getIndex() != self.index) continue; | 2245 | if (file.getIndex() != self.index) continue; |
| 1939 | if (!sym.flags.output_symtab) continue; | 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,7 +2249,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O |
| 1942 | const osym = ctx.symtab.items[symtab_index]; | 2249 | const osym = ctx.symtab.items[symtab_index]; |
| 1943 | break :n_strx osym.n_strx; | 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 | const sym_n_value = sym.getAddress(.{}, macho_file); | 2253 | const sym_n_value = sym.getAddress(.{}, macho_file); |
| 1947 | const sym_size = sym.getSize(macho_file); | 2254 | const sym_size = sym.getSize(macho_file); |
| 1948 | if (stab.is_func) { | 2255 | if (stab.is_func) { |
| ... | @@ -1983,34 +2290,8 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O | ... | @@ -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 | pub fn getAtomRelocs(self: *const Object, atom: Atom, macho_file: *MachO) []const Relocation { | 2293 | pub fn getAtomRelocs(self: *const Object, atom: Atom, macho_file: *MachO) []const Relocation { |
| 2012 | if (!atom.flags.relocs) return &[0]Relocation{}; | 2294 | const extra = atom.getExtra(macho_file); |
| 2013 | const extra = atom.getExtra(macho_file).?; | ||
| 2014 | const relocs = self.sections.items(.relocs)[atom.n_sect]; | 2295 | const relocs = self.sections.items(.relocs)[atom.n_sect]; |
| 2015 | return relocs.items[extra.rel_index..][0..extra.rel_count]; | 2296 | return relocs.items[extra.rel_index..][0..extra.rel_count]; |
| 2016 | } | 2297 | } |
| ... | @@ -2068,6 +2349,160 @@ pub fn asFile(self: *Object) File { | ... | @@ -2068,6 +2349,160 @@ pub fn asFile(self: *Object) File { |
| 2068 | return .{ .object = self }; | 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 | pub fn format( | 2506 | pub fn format( |
| 2072 | self: *Object, | 2507 | self: *Object, |
| 2073 | comptime unused_fmt_string: []const u8, | 2508 | comptime unused_fmt_string: []const u8, |
| ... | @@ -2102,10 +2537,11 @@ fn formatAtoms( | ... | @@ -2102,10 +2537,11 @@ fn formatAtoms( |
| 2102 | _ = unused_fmt_string; | 2537 | _ = unused_fmt_string; |
| 2103 | _ = options; | 2538 | _ = options; |
| 2104 | const object = ctx.object; | 2539 | const object = ctx.object; |
| 2540 | const macho_file = ctx.macho_file; | ||
| 2105 | try writer.writeAll(" atoms\n"); | 2541 | try writer.writeAll(" atoms\n"); |
| 2106 | for (object.atoms.items) |atom_index| { | 2542 | for (object.getAtoms()) |atom_index| { |
| 2107 | const atom = ctx.macho_file.getAtom(atom_index).?; | 2543 | const atom = object.getAtom(atom_index) orelse continue; |
| 2108 | try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)}); | 2544 | try writer.print(" {}\n", .{atom.fmt(macho_file)}); |
| 2109 | } | 2545 | } |
| 2110 | } | 2546 | } |
| 2111 | 2547 | ||
| ... | @@ -2171,8 +2607,8 @@ fn formatUnwindRecords( | ... | @@ -2171,8 +2607,8 @@ fn formatUnwindRecords( |
| 2171 | const object = ctx.object; | 2607 | const object = ctx.object; |
| 2172 | const macho_file = ctx.macho_file; | 2608 | const macho_file = ctx.macho_file; |
| 2173 | try writer.writeAll(" unwind records\n"); | 2609 | try writer.writeAll(" unwind records\n"); |
| 2174 | for (object.unwind_records.items) |rec| { | 2610 | for (object.unwind_records_indexes.items) |rec| { |
| 2175 | try writer.print(" rec({d}) : {}\n", .{ rec, macho_file.getUnwindRecord(rec).fmt(macho_file) }); | 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,10 +2628,26 @@ fn formatSymtab( |
| 2192 | _ = unused_fmt_string; | 2628 | _ = unused_fmt_string; |
| 2193 | _ = options; | 2629 | _ = options; |
| 2194 | const object = ctx.object; | 2630 | const object = ctx.object; |
| 2631 | const macho_file = ctx.macho_file; | ||
| 2195 | try writer.writeAll(" symbols\n"); | 2632 | try writer.writeAll(" symbols\n"); |
| 2196 | for (object.symbols.items) |index| { | 2633 | for (object.symbols.items, 0..) |sym, i| { |
| 2197 | const sym = ctx.macho_file.getSymbol(index); | 2634 | const ref = object.getSymbolRef(@intCast(i), macho_file); |
| 2198 | try writer.print(" {}\n", .{sym.fmt(ctx.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,7 +2663,7 @@ fn formatPath( |
| 2211 | ) !void { | 2663 | ) !void { |
| 2212 | _ = unused_fmt_string; | 2664 | _ = unused_fmt_string; |
| 2213 | _ = options; | 2665 | _ = options; |
| 2214 | if (object.archive) |ar| { | 2666 | if (object.in_archive) |ar| { |
| 2215 | try writer.writeAll(ar.path); | 2667 | try writer.writeAll(ar.path); |
| 2216 | try writer.writeByte('('); | 2668 | try writer.writeByte('('); |
| 2217 | try writer.writeAll(object.path); | 2669 | try writer.writeAll(object.path); |
| ... | @@ -2240,32 +2692,71 @@ const StabFile = struct { | ... | @@ -2240,32 +2692,71 @@ const StabFile = struct { |
| 2240 | comp_dir: u32, | 2692 | comp_dir: u32, |
| 2241 | stabs: std.ArrayListUnmanaged(Stab) = .{}, | 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 | const nlist = object.symtab.items(.nlist)[sf.comp_dir]; | 2696 | const nlist = object.symtab.items(.nlist)[sf.comp_dir]; |
| 2245 | return object.getString(nlist.n_strx); | 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 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 1]; | 2701 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 1]; |
| 2250 | return object.getString(nlist.n_strx); | 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 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 2]; | 2706 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 2]; |
| 2255 | return object.getString(nlist.n_strx); | 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 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 2]; | 2711 | const nlist = object.symtab.items(.nlist)[sf.comp_dir + 2]; |
| 2260 | return nlist.n_value; | 2712 | return nlist.n_value; |
| 2261 | } | 2713 | } |
| 2262 | 2714 | ||
| 2263 | const Stab = struct { | 2715 | const Stab = struct { |
| 2264 | is_func: bool = true, | 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 { | 2737 | const StabFormatContext = struct { Stab, Object }; |
| 2268 | return if (stab.symbol) |s| macho_file.getSymbol(s) else null; | 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,43 +2765,52 @@ const CompileUnit = struct { |
| 2274 | comp_dir: u32, | 2765 | comp_dir: u32, |
| 2275 | tu_name: u32, | 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 | return object.getString(cu.comp_dir); | 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 | return object.getString(cu.tu_name); | 2773 | return object.getString(cu.tu_name); |
| 2283 | } | 2774 | } |
| 2284 | }; | 2775 | }; |
| 2285 | 2776 | ||
| 2286 | const InArchive = struct { | 2777 | const InArchive = struct { |
| 2287 | path: []const u8, | 2778 | path: []const u8, |
| 2288 | offset: u64, | ||
| 2289 | size: u32, | 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 | const x86_64 = struct { | 2789 | const x86_64 = struct { |
| 2293 | fn parseRelocs( | 2790 | fn parseRelocs( |
| 2294 | self: *const Object, | 2791 | self: *Object, |
| 2295 | n_sect: u8, | ||
| 2296 | sect: macho.section_64, | 2792 | sect: macho.section_64, |
| 2297 | out: *std.ArrayListUnmanaged(Relocation), | 2793 | out: *std.ArrayListUnmanaged(Relocation), |
| 2794 | handle: File.Handle, | ||
| 2298 | macho_file: *MachO, | 2795 | macho_file: *MachO, |
| 2299 | ) !void { | 2796 | ) !void { |
| 2300 | const gpa = macho_file.base.comp.gpa; | 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 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); | 2799 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 2305 | defer gpa.free(relocs_buffer); | 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 | if (amt != relocs_buffer.len) return error.InputOutput; | 2803 | if (amt != relocs_buffer.len) return error.InputOutput; |
| 2309 | } | 2804 | } |
| 2310 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; | 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 | defer gpa.free(code); | 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 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); | 2815 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); |
| 2316 | 2816 | ||
| ... | @@ -2332,8 +2832,9 @@ const x86_64 = struct { | ... | @@ -2332,8 +2832,9 @@ const x86_64 = struct { |
| 2332 | .X86_64_RELOC_SIGNED_4 => 4, | 2832 | .X86_64_RELOC_SIGNED_4 => 4, |
| 2333 | else => 0, | 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 | const nsect = rel.r_symbolnum - 1; | 2838 | const nsect = rel.r_symbolnum - 1; |
| 2338 | const taddr: i64 = if (rel.r_pcrel == 1) | 2839 | const taddr: i64 = if (rel.r_pcrel == 1) |
| 2339 | @as(i64, @intCast(sect.addr)) + rel.r_address + addend + 4 | 2840 | @as(i64, @intCast(sect.addr)) + rel.r_address + addend + 4 |
| ... | @@ -2345,9 +2846,15 @@ const x86_64 = struct { | ... | @@ -2345,9 +2846,15 @@ const x86_64 = struct { |
| 2345 | }); | 2846 | }); |
| 2346 | return error.MalformedObject; | 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 | break :blk target; | 2856 | break :blk target; |
| 2350 | } else self.symbols.items[rel.r_symbolnum]; | 2857 | } else rel.r_symbolnum; |
| 2351 | 2858 | ||
| 2352 | const has_subtractor = if (i > 0 and | 2859 | const has_subtractor = if (i > 0 and |
| 2353 | @as(macho.reloc_type_x86_64, @enumFromInt(relocs[i - 1].r_type)) == .X86_64_RELOC_SUBTRACTOR) | 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,7 +2868,7 @@ const x86_64 = struct { |
| 2361 | break :blk true; | 2868 | break :blk true; |
| 2362 | } else false; | 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 | switch (err) { | 2872 | switch (err) { |
| 2366 | error.Pcrel => try macho_file.reportParseError2( | 2873 | error.Pcrel => try macho_file.reportParseError2( |
| 2367 | self.index, | 2874 | self.index, |
| ... | @@ -2388,7 +2895,7 @@ const x86_64 = struct { | ... | @@ -2388,7 +2895,7 @@ const x86_64 = struct { |
| 2388 | }; | 2895 | }; |
| 2389 | 2896 | ||
| 2390 | out.appendAssumeCapacity(.{ | 2897 | out.appendAssumeCapacity(.{ |
| 2391 | .tag = if (rel.r_extern == 1) .@"extern" else .local, | 2898 | .tag = if (is_extern) .@"extern" else .local, |
| 2392 | .offset = @as(u32, @intCast(rel.r_address)), | 2899 | .offset = @as(u32, @intCast(rel.r_address)), |
| 2393 | .target = target, | 2900 | .target = target, |
| 2394 | .addend = addend, | 2901 | .addend = addend, |
| ... | @@ -2403,7 +2910,7 @@ const x86_64 = struct { | ... | @@ -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 | switch (rel_type) { | 2914 | switch (rel_type) { |
| 2408 | .X86_64_RELOC_UNSIGNED => { | 2915 | .X86_64_RELOC_UNSIGNED => { |
| 2409 | if (rel.r_pcrel == 1) return error.Pcrel; | 2916 | if (rel.r_pcrel == 1) return error.Pcrel; |
| ... | @@ -2423,7 +2930,7 @@ const x86_64 = struct { | ... | @@ -2423,7 +2930,7 @@ const x86_64 = struct { |
| 2423 | => { | 2930 | => { |
| 2424 | if (rel.r_pcrel == 0) return error.NonPcrel; | 2931 | if (rel.r_pcrel == 0) return error.NonPcrel; |
| 2425 | if (rel.r_length != 2) return error.InvalidLength; | 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 | return switch (rel_type) { | 2934 | return switch (rel_type) { |
| 2428 | .X86_64_RELOC_BRANCH => .branch, | 2935 | .X86_64_RELOC_BRANCH => .branch, |
| 2429 | .X86_64_RELOC_GOT_LOAD => .got_load, | 2936 | .X86_64_RELOC_GOT_LOAD => .got_load, |
| ... | @@ -2454,26 +2961,29 @@ const x86_64 = struct { | ... | @@ -2454,26 +2961,29 @@ const x86_64 = struct { |
| 2454 | 2961 | ||
| 2455 | const aarch64 = struct { | 2962 | const aarch64 = struct { |
| 2456 | fn parseRelocs( | 2963 | fn parseRelocs( |
| 2457 | self: *const Object, | 2964 | self: *Object, |
| 2458 | n_sect: u8, | ||
| 2459 | sect: macho.section_64, | 2965 | sect: macho.section_64, |
| 2460 | out: *std.ArrayListUnmanaged(Relocation), | 2966 | out: *std.ArrayListUnmanaged(Relocation), |
| 2967 | handle: File.Handle, | ||
| 2461 | macho_file: *MachO, | 2968 | macho_file: *MachO, |
| 2462 | ) !void { | 2969 | ) !void { |
| 2463 | const gpa = macho_file.base.comp.gpa; | 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 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); | 2972 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 2468 | defer gpa.free(relocs_buffer); | 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 | if (amt != relocs_buffer.len) return error.InputOutput; | 2976 | if (amt != relocs_buffer.len) return error.InputOutput; |
| 2472 | } | 2977 | } |
| 2473 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; | 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 | defer gpa.free(code); | 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 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); | 2988 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); |
| 2479 | 2989 | ||
| ... | @@ -2519,8 +3029,9 @@ const aarch64 = struct { | ... | @@ -2519,8 +3029,9 @@ const aarch64 = struct { |
| 2519 | } | 3029 | } |
| 2520 | 3030 | ||
| 2521 | const rel_type: macho.reloc_type_arm64 = @enumFromInt(rel.r_type); | 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 | const nsect = rel.r_symbolnum - 1; | 3035 | const nsect = rel.r_symbolnum - 1; |
| 2525 | const taddr: i64 = if (rel.r_pcrel == 1) | 3036 | const taddr: i64 = if (rel.r_pcrel == 1) |
| 2526 | @as(i64, @intCast(sect.addr)) + rel.r_address + addend | 3037 | @as(i64, @intCast(sect.addr)) + rel.r_address + addend |
| ... | @@ -2532,9 +3043,15 @@ const aarch64 = struct { | ... | @@ -2532,9 +3043,15 @@ const aarch64 = struct { |
| 2532 | }); | 3043 | }); |
| 2533 | return error.MalformedObject; | 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 | break :blk target; | 3053 | break :blk target; |
| 2537 | } else self.symbols.items[rel.r_symbolnum]; | 3054 | } else rel.r_symbolnum; |
| 2538 | 3055 | ||
| 2539 | const has_subtractor = if (i > 0 and | 3056 | const has_subtractor = if (i > 0 and |
| 2540 | @as(macho.reloc_type_arm64, @enumFromInt(relocs[i - 1].r_type)) == .ARM64_RELOC_SUBTRACTOR) | 3057 | @as(macho.reloc_type_arm64, @enumFromInt(relocs[i - 1].r_type)) == .ARM64_RELOC_SUBTRACTOR) |
| ... | @@ -2548,7 +3065,7 @@ const aarch64 = struct { | ... | @@ -2548,7 +3065,7 @@ const aarch64 = struct { |
| 2548 | break :blk true; | 3065 | break :blk true; |
| 2549 | } else false; | 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 | switch (err) { | 3069 | switch (err) { |
| 2553 | error.Pcrel => try macho_file.reportParseError2( | 3070 | error.Pcrel => try macho_file.reportParseError2( |
| 2554 | self.index, | 3071 | self.index, |
| ... | @@ -2575,7 +3092,7 @@ const aarch64 = struct { | ... | @@ -2575,7 +3092,7 @@ const aarch64 = struct { |
| 2575 | }; | 3092 | }; |
| 2576 | 3093 | ||
| 2577 | out.appendAssumeCapacity(.{ | 3094 | out.appendAssumeCapacity(.{ |
| 2578 | .tag = if (rel.r_extern == 1) .@"extern" else .local, | 3095 | .tag = if (is_extern) .@"extern" else .local, |
| 2579 | .offset = @as(u32, @intCast(rel.r_address)), | 3096 | .offset = @as(u32, @intCast(rel.r_address)), |
| 2580 | .target = target, | 3097 | .target = target, |
| 2581 | .addend = addend, | 3098 | .addend = addend, |
| ... | @@ -2590,7 +3107,7 @@ const aarch64 = struct { | ... | @@ -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 | switch (rel_type) { | 3111 | switch (rel_type) { |
| 2595 | .ARM64_RELOC_UNSIGNED => { | 3112 | .ARM64_RELOC_UNSIGNED => { |
| 2596 | if (rel.r_pcrel == 1) return error.Pcrel; | 3113 | if (rel.r_pcrel == 1) return error.Pcrel; |
| ... | @@ -2611,7 +3128,7 @@ const aarch64 = struct { | ... | @@ -2611,7 +3128,7 @@ const aarch64 = struct { |
| 2611 | => { | 3128 | => { |
| 2612 | if (rel.r_pcrel == 0) return error.NonPcrel; | 3129 | if (rel.r_pcrel == 0) return error.NonPcrel; |
| 2613 | if (rel.r_length != 2) return error.InvalidLength; | 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 | return switch (rel_type) { | 3132 | return switch (rel_type) { |
| 2616 | .ARM64_RELOC_BRANCH26 => .branch, | 3133 | .ARM64_RELOC_BRANCH26 => .branch, |
| 2617 | .ARM64_RELOC_PAGE21 => .page, | 3134 | .ARM64_RELOC_PAGE21 => .page, |
| ... | @@ -2628,7 +3145,7 @@ const aarch64 = struct { | ... | @@ -2628,7 +3145,7 @@ const aarch64 = struct { |
| 2628 | => { | 3145 | => { |
| 2629 | if (rel.r_pcrel == 1) return error.Pcrel; | 3146 | if (rel.r_pcrel == 1) return error.Pcrel; |
| 2630 | if (rel.r_length != 2) return error.InvalidLength; | 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 | return switch (rel_type) { | 3149 | return switch (rel_type) { |
| 2633 | .ARM64_RELOC_PAGEOFF12 => .pageoff, | 3150 | .ARM64_RELOC_PAGEOFF12 => .pageoff, |
| 2634 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => .got_load_pageoff, | 3151 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => .got_load_pageoff, |
src/link/MachO/Relocation.zig+23-11| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | tag: enum { @"extern", local }, | 1 | tag: Tag, |
| 2 | offset: u32, | 2 | offset: u32, |
| 3 | target: u32, | 3 | target: u32, |
| 4 | addend: i64, | 4 | addend: i64, |
| ... | @@ -10,34 +10,44 @@ meta: packed struct { | ... | @@ -10,34 +10,44 @@ meta: packed struct { |
| 10 | symbolnum: u24, | 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 | assert(rel.tag == .@"extern"); | 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 | assert(rel.tag == .local); | 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 | return switch (rel.tag) { | 30 | return switch (rel.tag) { |
| 25 | .local => rel.getTargetAtom(macho_file).getAddress(macho_file), | 31 | .local => rel.getTargetAtom(atom, macho_file).getAddress(macho_file), |
| 26 | .@"extern" => rel.getTargetSymbol(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 | return switch (rel.tag) { | 37 | return switch (rel.tag) { |
| 32 | .local => 0, | 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 | pub fn getZigGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 { | 43 | pub fn getZigGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 { |
| 44 | const zo = macho_file.getZigObject() orelse return 0; | ||
| 38 | return switch (rel.tag) { | 45 | return switch (rel.tag) { |
| 39 | .local => 0, | 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,6 +165,8 @@ pub const Type = enum { |
| 155 | unsigned, | 165 | unsigned, |
| 156 | }; | 166 | }; |
| 157 | 167 | ||
| 168 | const Tag = enum { local, @"extern" }; | ||
| 169 | |||
| 158 | const assert = std.debug.assert; | 170 | const assert = std.debug.assert; |
| 159 | const macho = std.macho; | 171 | const macho = std.macho; |
| 160 | const math = std.math; | 172 | const math = std.math; |
src/link/MachO/Symbol.zig+52-37| ... | @@ -9,17 +9,16 @@ name: u32 = 0, | ... | @@ -9,17 +9,16 @@ name: u32 = 0, |
| 9 | /// File where this symbol is defined. | 9 | /// File where this symbol is defined. |
| 10 | file: File.Index = 0, | 10 | file: File.Index = 0, |
| 11 | 11 | ||
| 12 | /// Atom containing this symbol if any. | 12 | /// Reference to Atom containing this symbol if any. |
| 13 | /// Index of 0 means there is no associated atom with this symbol. | ||
| 14 | /// Use `getAtom` to get the pointer to the atom. | 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 | /// Assigned output section index for this symbol. | 16 | /// Assigned output section index for this symbol. |
| 18 | out_n_sect: u8 = 0, | 17 | out_n_sect: u8 = 0, |
| 19 | 18 | ||
| 20 | /// Index of the source nlist this symbol references. | 19 | /// Index of the source nlist this symbol references. |
| 21 | /// Use `getNlist` to pull the nlist from the relevant file. | 20 | /// Use `getNlist` to pull the nlist from the relevant file. |
| 22 | nlist_idx: Index = 0, | 21 | nlist_idx: u32 = 0, |
| 23 | 22 | ||
| 24 | /// Misc flags for the symbol packaged as packed struct for compression. | 23 | /// Misc flags for the symbol packaged as packed struct for compression. |
| 25 | flags: Flags = .{}, | 24 | flags: Flags = .{}, |
| ... | @@ -55,16 +54,19 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool { | ... | @@ -55,16 +54,19 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool { |
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 { | 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 | return switch (symbol.getFile(macho_file).?) { | 57 | return switch (symbol.getFile(macho_file).?) { |
| 60 | .dylib => unreachable, // There are no local symbols for dylibs | ||
| 61 | .zig_object => |x| x.strtab.getAssumeExists(symbol.name), | 58 | .zig_object => |x| x.strtab.getAssumeExists(symbol.name), |
| 62 | inline else => |x| x.getString(symbol.name), | 59 | inline else => |x| x.getString(symbol.name), |
| 63 | }; | 60 | }; |
| 64 | } | 61 | } |
| 65 | 62 | ||
| 66 | pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom { | 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 | pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { | 72 | pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { |
| ... | @@ -75,8 +77,10 @@ pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { | ... | @@ -75,8 +77,10 @@ pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { |
| 75 | pub fn getNlist(symbol: Symbol, macho_file: *MachO) macho.nlist_64 { | 77 | pub fn getNlist(symbol: Symbol, macho_file: *MachO) macho.nlist_64 { |
| 76 | const file = symbol.getFile(macho_file).?; | 78 | const file = symbol.getFile(macho_file).?; |
| 77 | return switch (file) { | 79 | return switch (file) { |
| 80 | .dylib => unreachable, | ||
| 81 | .zig_object => unreachable, | ||
| 78 | .object => |x| x.symtab.items(.nlist)[symbol.nlist_idx], | 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,33 +128,35 @@ pub fn getAddress(symbol: Symbol, opts: struct { |
| 124 | 128 | ||
| 125 | pub fn getGotAddress(symbol: Symbol, macho_file: *MachO) u64 { | 129 | pub fn getGotAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 126 | if (!symbol.flags.has_got) return 0; | 130 | if (!symbol.flags.has_got) return 0; |
| 127 | const extra = symbol.getExtra(macho_file).?; | 131 | const extra = symbol.getExtra(macho_file); |
| 128 | return macho_file.got.getAddress(extra.got, macho_file); | 132 | return macho_file.got.getAddress(extra.got, macho_file); |
| 129 | } | 133 | } |
| 130 | 134 | ||
| 131 | pub fn getStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { | 135 | pub fn getStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 132 | if (!symbol.flags.stubs) return 0; | 136 | if (!symbol.flags.stubs) return 0; |
| 133 | const extra = symbol.getExtra(macho_file).?; | 137 | const extra = symbol.getExtra(macho_file); |
| 134 | return macho_file.stubs.getAddress(extra.stubs, macho_file); | 138 | return macho_file.stubs.getAddress(extra.stubs, macho_file); |
| 135 | } | 139 | } |
| 136 | 140 | ||
| 137 | pub fn getObjcStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { | 141 | pub fn getObjcStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 138 | if (!symbol.flags.objc_stubs) return 0; | 142 | if (!symbol.flags.objc_stubs) return 0; |
| 139 | const extra = symbol.getExtra(macho_file).?; | 143 | const extra = symbol.getExtra(macho_file); |
| 140 | return macho_file.objc_stubs.getAddress(extra.objc_stubs, macho_file); | 144 | return macho_file.objc_stubs.getAddress(extra.objc_stubs, macho_file); |
| 141 | } | 145 | } |
| 142 | 146 | ||
| 143 | pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { | 147 | pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 144 | if (!symbol.flags.objc_stubs) return 0; | 148 | if (!symbol.flags.objc_stubs) return 0; |
| 145 | const extra = symbol.getExtra(macho_file).?; | 149 | const extra = symbol.getExtra(macho_file); |
| 146 | const atom = macho_file.getAtom(extra.objc_selrefs).?; | 150 | const file = symbol.getFile(macho_file).?; |
| 147 | assert(atom.flags.alive); | 151 | return switch (file) { |
| 148 | return atom.getAddress(macho_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 | pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { | 157 | pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 152 | if (!symbol.flags.tlv_ptr) return 0; | 158 | if (!symbol.flags.tlv_ptr) return 0; |
| 153 | const extra = symbol.getExtra(macho_file).?; | 159 | const extra = symbol.getExtra(macho_file); |
| 154 | return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file); | 160 | return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file); |
| 155 | } | 161 | } |
| 156 | 162 | ||
| ... | @@ -162,14 +168,14 @@ const GetOrCreateZigGotEntryResult = struct { | ... | @@ -162,14 +168,14 @@ const GetOrCreateZigGotEntryResult = struct { |
| 162 | pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult { | 168 | pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult { |
| 163 | assert(!macho_file.base.isRelocatable()); | 169 | assert(!macho_file.base.isRelocatable()); |
| 164 | assert(symbol.flags.needs_zig_got); | 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 | const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file); | 172 | const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file); |
| 167 | return .{ .found_existing = false, .index = index }; | 173 | return .{ .found_existing = false, .index = index }; |
| 168 | } | 174 | } |
| 169 | 175 | ||
| 170 | pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 { | 176 | pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 { |
| 171 | if (!symbol.flags.has_zig_got) return 0; | 177 | if (!symbol.flags.has_zig_got) return 0; |
| 172 | const extras = symbol.getExtra(macho_file).?; | 178 | const extras = symbol.getExtra(macho_file); |
| 173 | return macho_file.zig_got.entryAddress(extras.zig_got, macho_file); | 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,7 +186,7 @@ pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 { |
| 180 | const symtab_ctx = switch (file) { | 186 | const symtab_ctx = switch (file) { |
| 181 | inline else => |x| x.output_symtab_ctx, | 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 | if (symbol.isLocal()) { | 190 | if (symbol.isLocal()) { |
| 185 | idx += symtab_ctx.ilocal; | 191 | idx += symtab_ctx.ilocal; |
| 186 | } else if (symbol.flags.@"export") { | 192 | } else if (symbol.flags.@"export") { |
| ... | @@ -202,11 +208,8 @@ const AddExtraOpts = struct { | ... | @@ -202,11 +208,8 @@ const AddExtraOpts = struct { |
| 202 | symtab: ?u32 = null, | 208 | symtab: ?u32 = null, |
| 203 | }; | 209 | }; |
| 204 | 210 | ||
| 205 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void { | 211 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) void { |
| 206 | if (symbol.getExtra(macho_file) == null) { | 212 | var extra = symbol.getExtra(macho_file); |
| 207 | symbol.extra = try macho_file.addSymbolExtra(.{}); | ||
| 208 | } | ||
| 209 | var extra = symbol.getExtra(macho_file).?; | ||
| 210 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { | 213 | inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { |
| 211 | if (@field(opts, field.name)) |x| { | 214 | if (@field(opts, field.name)) |x| { |
| 212 | @field(extra, field.name) = x; | 215 | @field(extra, field.name) = x; |
| ... | @@ -215,18 +218,22 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void { | ... | @@ -215,18 +218,22 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) !void { |
| 215 | symbol.setExtra(extra, macho_file); | 218 | symbol.setExtra(extra, macho_file); |
| 216 | } | 219 | } |
| 217 | 220 | ||
| 218 | pub inline fn getExtra(symbol: Symbol, macho_file: *MachO) ?Extra { | 221 | pub inline fn getExtra(symbol: Symbol, macho_file: *MachO) Extra { |
| 219 | return macho_file.getSymbolExtra(symbol.extra); | 222 | return switch (symbol.getFile(macho_file).?) { |
| 223 | inline else => |x| x.getSymbolExtra(symbol.extra), | ||
| 224 | }; | ||
| 220 | } | 225 | } |
| 221 | 226 | ||
| 222 | pub inline fn setExtra(symbol: Symbol, extra: Extra, macho_file: *MachO) void { | 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 | pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) void { | 233 | pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) void { |
| 227 | if (symbol.isLocal()) { | 234 | if (symbol.isLocal()) { |
| 228 | out.n_type = if (symbol.flags.abs) macho.N_ABS else macho.N_SECT; | 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 | out.n_desc = 0; | 237 | out.n_desc = 0; |
| 231 | out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file); | 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,7 +245,7 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo |
| 238 | assert(symbol.visibility == .global); | 245 | assert(symbol.visibility == .global); |
| 239 | out.n_type = macho.N_EXT; | 246 | out.n_type = macho.N_EXT; |
| 240 | out.n_type |= if (symbol.flags.abs) macho.N_ABS else macho.N_SECT; | 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 | out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file); | 249 | out.n_value = symbol.getAddress(.{ .stubs = false }, macho_file); |
| 243 | out.n_desc = 0; | 250 | out.n_desc = 0; |
| 244 | 251 | ||
| ... | @@ -318,15 +325,20 @@ fn format2( | ... | @@ -318,15 +325,20 @@ fn format2( |
| 318 | symbol.getAddress(.{}, ctx.macho_file), | 325 | symbol.getAddress(.{}, ctx.macho_file), |
| 319 | }); | 326 | }); |
| 320 | if (symbol.getFile(ctx.macho_file)) |file| { | 327 | if (symbol.getFile(ctx.macho_file)) |file| { |
| 321 | if (symbol.out_n_sect != 0) { | 328 | if (symbol.getOutputSectionIndex(ctx.macho_file) != 0) { |
| 322 | try writer.print(" : sect({d})", .{symbol.out_n_sect}); | 329 | try writer.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)}); |
| 323 | } | 330 | } |
| 324 | if (symbol.getAtom(ctx.macho_file)) |atom| { | 331 | if (symbol.getAtom(ctx.macho_file)) |atom| { |
| 325 | try writer.print(" : atom({d})", .{atom.atom_index}); | 332 | try writer.print(" : atom({d})", .{atom.atom_index}); |
| 326 | } | 333 | } |
| 327 | var buf: [2]u8 = .{'_'} ** 2; | 334 | var buf: [3]u8 = .{'_'} ** 3; |
| 328 | if (symbol.flags.@"export") buf[0] = 'E'; | 335 | if (symbol.flags.@"export") buf[0] = 'E'; |
| 329 | if (symbol.flags.import) buf[1] = 'I'; | 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 | try writer.print(" : {s}", .{&buf}); | 342 | try writer.print(" : {s}", .{&buf}); |
| 331 | if (symbol.flags.weak) try writer.writeAll(" : weak"); | 343 | if (symbol.flags.weak) try writer.writeAll(" : weak"); |
| 332 | if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab"); | 344 | if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab"); |
| ... | @@ -346,11 +358,6 @@ pub const Flags = packed struct { | ... | @@ -346,11 +358,6 @@ pub const Flags = packed struct { |
| 346 | /// Whether the symbol is exported at runtime. | 358 | /// Whether the symbol is exported at runtime. |
| 347 | @"export": bool = false, | 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 | /// Whether this symbol is weak. | 361 | /// Whether this symbol is weak. |
| 355 | weak: bool = false, | 362 | weak: bool = false, |
| 356 | 363 | ||
| ... | @@ -400,6 +407,14 @@ pub const Visibility = enum { | ... | @@ -400,6 +407,14 @@ pub const Visibility = enum { |
| 400 | global, | 407 | global, |
| 401 | hidden, | 408 | hidden, |
| 402 | local, | 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 | pub const Extra = struct { | 420 | pub const Extra = struct { |
src/link/MachO/UnwindInfo.zig+67-45| ... | @@ -1,10 +1,10 @@ | ... | @@ -1,10 +1,10 @@ |
| 1 | /// List of all unwind records gathered from all objects and sorted | 1 | /// List of all unwind records gathered from all objects and sorted |
| 2 | /// by allocated relative function address within the section. | 2 | /// by allocated relative function address within the section. |
| 3 | records: std.ArrayListUnmanaged(Record.Index) = .{}, | 3 | records: std.ArrayListUnmanaged(Record.Ref) = .{}, |
| 4 | 4 | ||
| 5 | /// List of all personalities referenced by either unwind info entries | 5 | /// List of all personalities referenced by either unwind info entries |
| 6 | /// or __eh_frame entries. | 6 | /// or __eh_frame entries. |
| 7 | personalities: [max_personalities]Symbol.Index = undefined, | 7 | personalities: [max_personalities]MachO.Ref = undefined, |
| 8 | personalities_count: u2 = 0, | 8 | personalities_count: u2 = 0, |
| 9 | 9 | ||
| 10 | /// List of common encodings sorted in descending order with the most common first. | 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,10 +25,10 @@ pub fn deinit(info: *UnwindInfo, allocator: Allocator) void { |
| 25 | info.lsdas_lookup.deinit(allocator); | 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 | const cpu_arch = macho_file.getTarget().cpu.arch; | 29 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 30 | const lhs = macho_file.getUnwindRecord(lhs_index); | 30 | const lhs = lhs_ref.getUnwindRecord(macho_file); |
| 31 | const rhs = macho_file.getUnwindRecord(rhs_index); | 31 | const rhs = rhs_ref.getUnwindRecord(macho_file); |
| 32 | if (cpu_arch == .x86_64) { | 32 | if (cpu_arch == .x86_64) { |
| 33 | if (lhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND) or | 33 | if (lhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND) or |
| 34 | rhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND)) return false; | 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,27 +42,31 @@ fn canFold(macho_file: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { | 44 | pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 45 | const tracy = trace(@src()); | ||
| 46 | defer tracy.end(); | ||
| 47 | |||
| 45 | const gpa = macho_file.base.comp.gpa; | 48 | const gpa = macho_file.base.comp.gpa; |
| 46 | 49 | ||
| 47 | log.debug("generating unwind info", .{}); | 50 | log.debug("generating unwind info", .{}); |
| 48 | 51 | ||
| 49 | // Collect all unwind records | 52 | // Collect all unwind records |
| 50 | for (macho_file.sections.items(.atoms)) |atoms| { | 53 | for (macho_file.sections.items(.atoms)) |atoms| { |
| 51 | for (atoms.items) |atom_index| { | 54 | for (atoms.items) |ref| { |
| 52 | const atom = macho_file.getAtom(atom_index) orelse continue; | 55 | const atom = ref.getAtom(macho_file) orelse continue; |
| 53 | if (!atom.flags.alive) continue; | 56 | if (!atom.flags.alive) continue; |
| 54 | const recs = atom.getUnwindRecords(macho_file); | 57 | const recs = atom.getUnwindRecords(macho_file); |
| 58 | const file = atom.getFile(macho_file); | ||
| 55 | try info.records.ensureUnusedCapacity(gpa, recs.len); | 59 | try info.records.ensureUnusedCapacity(gpa, recs.len); |
| 56 | for (recs) |rec| { | 60 | for (recs) |rec| { |
| 57 | if (!macho_file.getUnwindRecord(rec).alive) continue; | 61 | if (!file.object.getUnwindRecord(rec).alive) continue; |
| 58 | info.records.appendAssumeCapacity(rec); | 62 | info.records.appendAssumeCapacity(.{ .record = rec, .file = file.getIndex() }); |
| 59 | } | 63 | } |
| 60 | } | 64 | } |
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | // Encode records | 67 | // Encode records |
| 64 | for (info.records.items) |index| { | 68 | for (info.records.items) |ref| { |
| 65 | const rec = macho_file.getUnwindRecord(index); | 69 | const rec = ref.getUnwindRecord(macho_file); |
| 66 | if (rec.getFde(macho_file)) |fde| { | 70 | if (rec.getFde(macho_file)) |fde| { |
| 67 | rec.enc.setDwarfSectionOffset(@intCast(fde.out_offset)); | 71 | rec.enc.setDwarfSectionOffset(@intCast(fde.out_offset)); |
| 68 | if (fde.getLsdaAtom(macho_file)) |lsda| { | 72 | if (fde.getLsdaAtom(macho_file)) |lsda| { |
| ... | @@ -72,27 +76,31 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { | ... | @@ -72,27 +76,31 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 72 | } | 76 | } |
| 73 | const cie = fde.getCie(macho_file); | 77 | const cie = fde.getCie(macho_file); |
| 74 | if (cie.getPersonality(macho_file)) |_| { | 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 | rec.enc.setPersonalityIndex(personality_index + 1); | 82 | rec.enc.setPersonalityIndex(personality_index + 1); |
| 77 | } | 83 | } |
| 78 | } else if (rec.getPersonality(macho_file)) |_| { | 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 | rec.enc.setPersonalityIndex(personality_index + 1); | 88 | rec.enc.setPersonalityIndex(personality_index + 1); |
| 81 | } | 89 | } |
| 82 | } | 90 | } |
| 83 | 91 | ||
| 84 | // Sort by assigned relative address within each output section | 92 | // Sort by assigned relative address within each output section |
| 85 | const sortFn = struct { | 93 | const sortFn = struct { |
| 86 | fn sortFn(ctx: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) bool { | 94 | fn sortFn(ctx: *MachO, lhs_ref: Record.Ref, rhs_ref: Record.Ref) bool { |
| 87 | const lhs = ctx.getUnwindRecord(lhs_index); | 95 | const lhs = lhs_ref.getUnwindRecord(ctx); |
| 88 | const rhs = ctx.getUnwindRecord(rhs_index); | 96 | const rhs = rhs_ref.getUnwindRecord(ctx); |
| 89 | const lhsa = lhs.getAtom(ctx); | 97 | const lhsa = lhs.getAtom(ctx); |
| 90 | const rhsa = rhs.getAtom(ctx); | 98 | const rhsa = rhs.getAtom(ctx); |
| 91 | if (lhsa.out_n_sect == rhsa.out_n_sect) return lhs.getAtomAddress(ctx) < rhs.getAtomAddress(ctx); | 99 | if (lhsa.out_n_sect == rhsa.out_n_sect) return lhs.getAtomAddress(ctx) < rhs.getAtomAddress(ctx); |
| 92 | return lhsa.out_n_sect < rhsa.out_n_sect; | 100 | return lhsa.out_n_sect < rhsa.out_n_sect; |
| 93 | } | 101 | } |
| 94 | }.sortFn; | 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 | // Fold the records | 105 | // Fold the records |
| 98 | // Any adjacent two records that share encoding can be folded into one. | 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,8 +109,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 101 | var j: usize = 1; | 109 | var j: usize = 1; |
| 102 | while (j < info.records.items.len) : (j += 1) { | 110 | while (j < info.records.items.len) : (j += 1) { |
| 103 | if (canFold(macho_file, info.records.items[i], info.records.items[j])) { | 111 | if (canFold(macho_file, info.records.items[i], info.records.items[j])) { |
| 104 | const rec = macho_file.getUnwindRecord(info.records.items[i]); | 112 | const rec = info.records.items[i].getUnwindRecord(macho_file); |
| 105 | rec.length += macho_file.getUnwindRecord(info.records.items[j]).length + 1; | 113 | rec.length += info.records.items[j].getUnwindRecord(macho_file).length + 1; |
| 106 | } else { | 114 | } else { |
| 107 | i += 1; | 115 | i += 1; |
| 108 | info.records.items[i] = info.records.items[j]; | 116 | info.records.items[i] = info.records.items[j]; |
| ... | @@ -111,14 +119,15 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { | ... | @@ -111,14 +119,15 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 111 | info.records.shrinkAndFree(gpa, i + 1); | 119 | info.records.shrinkAndFree(gpa, i + 1); |
| 112 | } | 120 | } |
| 113 | 121 | ||
| 114 | for (info.records.items) |rec_index| { | 122 | for (info.records.items) |ref| { |
| 115 | const rec = macho_file.getUnwindRecord(rec_index); | 123 | const rec = ref.getUnwindRecord(macho_file); |
| 116 | const atom = rec.getAtom(macho_file); | 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 | rec.getAtomAddress(macho_file), | 126 | rec.getAtomAddress(macho_file), |
| 119 | rec.getAtomAddress(macho_file) + rec.length, | 127 | rec.getAtomAddress(macho_file) + rec.length, |
| 120 | atom.getName(macho_file), | 128 | atom.getName(macho_file), |
| 121 | rec_index, | 129 | ref.record, |
| 130 | ref.file, | ||
| 122 | rec.enc, | 131 | rec.enc, |
| 123 | }); | 132 | }); |
| 124 | } | 133 | } |
| ... | @@ -161,8 +170,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { | ... | @@ -161,8 +170,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 161 | ).init(gpa); | 170 | ).init(gpa); |
| 162 | defer common_encodings_counts.deinit(); | 171 | defer common_encodings_counts.deinit(); |
| 163 | 172 | ||
| 164 | for (info.records.items) |rec_index| { | 173 | for (info.records.items) |ref| { |
| 165 | const rec = macho_file.getUnwindRecord(rec_index); | 174 | const rec = ref.getUnwindRecord(macho_file); |
| 166 | if (rec.enc.isDwarf(macho_file)) continue; | 175 | if (rec.enc.isDwarf(macho_file)) continue; |
| 167 | const gop = try common_encodings_counts.getOrPut(rec.enc); | 176 | const gop = try common_encodings_counts.getOrPut(rec.enc); |
| 168 | if (!gop.found_existing) { | 177 | if (!gop.found_existing) { |
| ... | @@ -190,7 +199,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { | ... | @@ -190,7 +199,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 190 | { | 199 | { |
| 191 | var i: u32 = 0; | 200 | var i: u32 = 0; |
| 192 | while (i < info.records.items.len) { | 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 | const range_start_max: u64 = rec.getAtomAddress(macho_file) + compressed_entry_func_offset_mask; | 203 | const range_start_max: u64 = rec.getAtomAddress(macho_file) + compressed_entry_func_offset_mask; |
| 195 | var encoding_count: u9 = info.common_encodings_count; | 204 | var encoding_count: u9 = info.common_encodings_count; |
| 196 | var space_left: u32 = second_level_page_words - | 205 | var space_left: u32 = second_level_page_words - |
| ... | @@ -202,7 +211,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { | ... | @@ -202,7 +211,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 202 | }; | 211 | }; |
| 203 | 212 | ||
| 204 | while (space_left >= 1 and i < info.records.items.len) { | 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 | const is_dwarf = next.enc.isDwarf(macho_file); | 215 | const is_dwarf = next.enc.isDwarf(macho_file); |
| 207 | 216 | ||
| 208 | if (next.getAtomAddress(macho_file) >= range_start_max) { | 217 | if (next.getAtomAddress(macho_file) >= range_start_max) { |
| ... | @@ -244,8 +253,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { | ... | @@ -244,8 +253,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 244 | // Save records having an LSDA pointer | 253 | // Save records having an LSDA pointer |
| 245 | log.debug("LSDA pointers:", .{}); | 254 | log.debug("LSDA pointers:", .{}); |
| 246 | try info.lsdas_lookup.ensureTotalCapacityPrecise(gpa, info.records.items.len); | 255 | try info.lsdas_lookup.ensureTotalCapacityPrecise(gpa, info.records.items.len); |
| 247 | for (info.records.items, 0..) |index, i| { | 256 | for (info.records.items, 0..) |ref, i| { |
| 248 | const rec = macho_file.getUnwindRecord(index); | 257 | const rec = ref.getUnwindRecord(macho_file); |
| 249 | info.lsdas_lookup.appendAssumeCapacity(@intCast(info.lsdas.items.len)); | 258 | info.lsdas_lookup.appendAssumeCapacity(@intCast(info.lsdas.items.len)); |
| 250 | if (rec.getLsdaAtom(macho_file)) |lsda| { | 259 | if (rec.getLsdaAtom(macho_file)) |lsda| { |
| 251 | log.debug(" @{x} => lsda({d})", .{ rec.getAtomAddress(macho_file), lsda.atom_index }); | 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,6 +264,9 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { |
| 255 | } | 264 | } |
| 256 | 265 | ||
| 257 | pub fn calcSize(info: UnwindInfo) usize { | 266 | pub fn calcSize(info: UnwindInfo) usize { |
| 267 | const tracy = trace(@src()); | ||
| 268 | defer tracy.end(); | ||
| 269 | |||
| 258 | var total_size: usize = 0; | 270 | var total_size: usize = 0; |
| 259 | total_size += @sizeOf(macho.unwind_info_section_header); | 271 | total_size += @sizeOf(macho.unwind_info_section_header); |
| 260 | total_size += | 272 | total_size += |
| ... | @@ -291,8 +303,8 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { | ... | @@ -291,8 +303,8 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 291 | 303 | ||
| 292 | try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count])); | 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| { | 306 | for (info.personalities[0..info.personalities_count]) |ref| { |
| 295 | const sym = macho_file.getSymbol(sym_index); | 307 | const sym = ref.getSymbol(macho_file).?; |
| 296 | try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little); | 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,7 +313,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 301 | (info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry)))); | 313 | (info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry)))); |
| 302 | for (info.pages.items, 0..) |page, i| { | 314 | for (info.pages.items, 0..) |page, i| { |
| 303 | assert(page.count > 0); | 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 | try writer.writeStruct(macho.unwind_info_section_header_index_entry{ | 317 | try writer.writeStruct(macho.unwind_info_section_header_index_entry{ |
| 306 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), | 318 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), |
| 307 | .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)), | 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,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 | const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr)); | 326 | const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr)); |
| 315 | try writer.writeStruct(macho.unwind_info_section_header_index_entry{ | 327 | try writer.writeStruct(macho.unwind_info_section_header_index_entry{ |
| 316 | .functionOffset = sentinel_address, | 328 | .functionOffset = sentinel_address, |
| ... | @@ -320,7 +332,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { | ... | @@ -320,7 +332,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 320 | }); | 332 | }); |
| 321 | 333 | ||
| 322 | for (info.lsdas.items) |index| { | 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 | try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{ | 336 | try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{ |
| 325 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), | 337 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), |
| 326 | .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)), | 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,13 +352,13 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { |
| 340 | @memset(buffer[stream.pos..], 0); | 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 | comptime var index: u2 = 0; | 356 | comptime var index: u2 = 0; |
| 345 | inline while (index < max_personalities) : (index += 1) { | 357 | inline while (index < max_personalities) : (index += 1) { |
| 346 | if (info.personalities[index] == sym_index) { | 358 | if (info.personalities[index].eql(ref)) { |
| 347 | return index; | 359 | return index; |
| 348 | } else if (index == info.personalities_count) { | 360 | } else if (index == info.personalities_count) { |
| 349 | info.personalities[index] = sym_index; | 361 | info.personalities[index] = ref; |
| 350 | info.personalities_count += 1; | 362 | info.personalities_count += 1; |
| 351 | return index; | 363 | return index; |
| 352 | } | 364 | } |
| ... | @@ -461,16 +473,17 @@ pub const Record = struct { | ... | @@ -461,16 +473,17 @@ pub const Record = struct { |
| 461 | } | 473 | } |
| 462 | 474 | ||
| 463 | pub fn getAtom(rec: Record, macho_file: *MachO) *Atom { | 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 | pub fn getLsdaAtom(rec: Record, macho_file: *MachO) ?*Atom { | 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 | pub fn getPersonality(rec: Record, macho_file: *MachO) ?*Symbol { | 483 | pub fn getPersonality(rec: Record, macho_file: *MachO) ?*Symbol { |
| 472 | const personality = rec.personality orelse return null; | 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 | pub fn getFde(rec: Record, macho_file: *MachO) ?Fde { | 489 | pub fn getFde(rec: Record, macho_file: *MachO) ?Fde { |
| ... | @@ -537,6 +550,15 @@ pub const Record = struct { | ... | @@ -537,6 +550,15 @@ pub const Record = struct { |
| 537 | } | 550 | } |
| 538 | 551 | ||
| 539 | pub const Index = u32; | 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 | const max_personalities = 3; | 564 | const max_personalities = 3; |
| ... | @@ -635,8 +657,8 @@ const Page = struct { | ... | @@ -635,8 +657,8 @@ const Page = struct { |
| 635 | .entryCount = page.count, | 657 | .entryCount = page.count, |
| 636 | }); | 658 | }); |
| 637 | 659 | ||
| 638 | for (info.records.items[page.start..][0..page.count]) |index| { | 660 | for (info.records.items[page.start..][0..page.count]) |ref| { |
| 639 | const rec = macho_file.getUnwindRecord(index); | 661 | const rec = ref.getUnwindRecord(macho_file); |
| 640 | try writer.writeStruct(macho.unwind_info_regular_second_level_entry{ | 662 | try writer.writeStruct(macho.unwind_info_regular_second_level_entry{ |
| 641 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), | 663 | .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), |
| 642 | .encoding = rec.enc.enc, | 664 | .encoding = rec.enc.enc, |
| ... | @@ -658,9 +680,9 @@ const Page = struct { | ... | @@ -658,9 +680,9 @@ const Page = struct { |
| 658 | } | 680 | } |
| 659 | 681 | ||
| 660 | assert(page.count > 0); | 682 | assert(page.count > 0); |
| 661 | const first_rec = macho_file.getUnwindRecord(info.records.items[page.start]); | 683 | const first_rec = info.records.items[page.start].getUnwindRecord(macho_file); |
| 662 | for (info.records.items[page.start..][0..page.count]) |index| { | 684 | for (info.records.items[page.start..][0..page.count]) |ref| { |
| 663 | const rec = macho_file.getUnwindRecord(index); | 685 | const rec = ref.getUnwindRecord(macho_file); |
| 664 | const enc_index = blk: { | 686 | const enc_index = blk: { |
| 665 | if (info.getCommonEncoding(rec.enc)) |id| break :blk id; | 687 | if (info.getCommonEncoding(rec.enc)) |id| break :blk id; |
| 666 | const ncommon = info.common_encodings_count; | 688 | const ncommon = info.common_encodings_count; |
src/link/MachO/ZigObject.zig+522-230| ... | @@ -6,9 +6,15 @@ index: File.Index, | ... | @@ -6,9 +6,15 @@ index: File.Index, |
| 6 | symtab: std.MultiArrayList(Nlist) = .{}, | 6 | symtab: std.MultiArrayList(Nlist) = .{}, |
| 7 | strtab: StringTable = .{}, | 7 | strtab: StringTable = .{}, |
| 8 | 8 | ||
| 9 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 9 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, |
| 10 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 10 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 11 | globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{}, | 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 | /// Table of tracked LazySymbols. | 19 | /// Table of tracked LazySymbols. |
| 14 | lazy_syms: LazySymbolTable = .{}, | 20 | lazy_syms: LazySymbolTable = .{}, |
| ... | @@ -48,7 +54,6 @@ relocs: RelocationTable = .{}, | ... | @@ -48,7 +54,6 @@ relocs: RelocationTable = .{}, |
| 48 | 54 | ||
| 49 | dwarf: ?Dwarf = null, | 55 | dwarf: ?Dwarf = null, |
| 50 | 56 | ||
| 51 | dynamic_relocs: MachO.DynamicRelocs = .{}, | ||
| 52 | output_symtab_ctx: MachO.SymtabCtx = .{}, | 57 | output_symtab_ctx: MachO.SymtabCtx = .{}, |
| 53 | output_ar_state: Archive.ArState = .{}, | 58 | output_ar_state: Archive.ArState = .{}, |
| 54 | 59 | ||
| ... | @@ -59,10 +64,13 @@ debug_info_header_dirty: bool = false, | ... | @@ -59,10 +64,13 @@ debug_info_header_dirty: bool = false, |
| 59 | debug_line_header_dirty: bool = false, | 64 | debug_line_header_dirty: bool = false, |
| 60 | 65 | ||
| 61 | pub fn init(self: *ZigObject, macho_file: *MachO) !void { | 66 | pub fn init(self: *ZigObject, macho_file: *MachO) !void { |
| 67 | const tracy = trace(@src()); | ||
| 68 | defer tracy.end(); | ||
| 69 | |||
| 62 | const comp = macho_file.base.comp; | 70 | const comp = macho_file.base.comp; |
| 63 | const gpa = comp.gpa; | 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 | try self.strtab.buffer.append(gpa, 0); | 74 | try self.strtab.buffer.append(gpa, 0); |
| 67 | 75 | ||
| 68 | switch (comp.config.debug_format) { | 76 | switch (comp.config.debug_format) { |
| ... | @@ -85,8 +93,12 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { | ... | @@ -85,8 +93,12 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 85 | self.symtab.deinit(allocator); | 93 | self.symtab.deinit(allocator); |
| 86 | self.strtab.deinit(allocator); | 94 | self.strtab.deinit(allocator); |
| 87 | self.symbols.deinit(allocator); | 95 | self.symbols.deinit(allocator); |
| 88 | self.atoms.deinit(allocator); | 96 | self.symbols_extra.deinit(allocator); |
| 97 | self.globals.deinit(allocator); | ||
| 89 | self.globals_lookup.deinit(allocator); | 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 | var it = self.decls.iterator(); | 104 | var it = self.decls.iterator(); |
| ... | @@ -129,53 +141,73 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { | ... | @@ -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 | try self.symtab.ensureUnusedCapacity(allocator, 1); | 148 | try self.symtab.ensureUnusedCapacity(allocator, 1); |
| 134 | const index = @as(Symbol.Index, @intCast(self.symtab.addOneAssumeCapacity())); | 149 | try self.symbols.ensureUnusedCapacity(allocator, 1); |
| 135 | self.symtab.set(index, .{ | 150 | try self.symbols_extra.ensureUnusedCapacity(allocator, @sizeOf(Symbol.Extra)); |
| 136 | .nlist = MachO.null_sym, | 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 | .size = 0, | 167 | .size = 0, |
| 138 | .atom = 0, | 168 | .atom = 0, |
| 139 | }); | 169 | }); |
| 140 | return index; | 170 | symbol.nlist_idx = nlist_idx; |
| 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); | ||
| 148 | 171 | ||
| 149 | try self.atoms.append(gpa, atom_index); | 172 | self.globals.appendAssumeCapacity(0); |
| 150 | try self.symbols.append(gpa, symbol_index); | ||
| 151 | 173 | ||
| 152 | const atom = macho_file.getAtom(atom_index).?; | 174 | return index; |
| 153 | atom.file = self.index; | 175 | } |
| 154 | atom.atom_index = atom_index; | ||
| 155 | 176 | ||
| 156 | const symbol = macho_file.getSymbol(symbol_index); | 177 | fn newAtom(self: *ZigObject, allocator: Allocator, name: u32, macho_file: *MachO) !Atom.Index { |
| 157 | symbol.file = self.index; | 178 | try self.atoms.ensureUnusedCapacity(allocator, 1); |
| 158 | symbol.atom = atom_index; | 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; | 183 | const index = self.addAtomAssumeCapacity(); |
| 161 | symbol.nlist_idx = nlist_index; | 184 | self.atoms_indexes.appendAssumeCapacity(index); |
| 185 | const atom = self.getAtom(index).?; | ||
| 186 | atom.name = name; | ||
| 162 | 187 | ||
| 163 | const relocs_index = @as(u32, @intCast(self.relocs.items.len)); | 188 | const relocs_index = @as(u32, @intCast(self.relocs.items.len)); |
| 164 | const relocs = try self.relocs.addOne(gpa); | 189 | self.relocs.addOneAssumeCapacity().* = .{}; |
| 165 | relocs.* = .{}; | 190 | atom.addExtra(.{ .rel_index = relocs_index, .rel_count = 0 }, macho_file); |
| 166 | try atom.addExtra(.{ .rel_index = relocs_index, .rel_count = 0 }, macho_file); | ||
| 167 | atom.flags.relocs = true; | ||
| 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 | pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8) !void { | 204 | pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8) !void { |
| 173 | assert(atom.file == self.index); | 205 | assert(atom.file == self.index); |
| 174 | assert(atom.size == buffer.len); | 206 | assert(atom.size == buffer.len); |
| 175 | const sect = macho_file.sections.items(.header)[atom.out_n_sect]; | 207 | const isec = atom.getInputSection(macho_file); |
| 176 | assert(!sect.isZerofill()); | 208 | assert(!isec.isZerofill()); |
| 177 | 209 | ||
| 178 | switch (sect.type()) { | 210 | switch (isec.type()) { |
| 179 | macho.S_THREAD_LOCAL_REGULAR => { | 211 | macho.S_THREAD_LOCAL_REGULAR => { |
| 180 | const tlv = self.tlv_initializers.get(atom.atom_index).?; | 212 | const tlv = self.tlv_initializers.get(atom.atom_index).?; |
| 181 | @memcpy(buffer, tlv.data); | 213 | @memcpy(buffer, tlv.data); |
| ... | @@ -184,6 +216,7 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 | ... | @@ -184,6 +216,7 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 184 | @memset(buffer, 0); | 216 | @memset(buffer, 0); |
| 185 | }, | 217 | }, |
| 186 | else => { | 218 | else => { |
| 219 | const sect = macho_file.sections.items(.header)[atom.out_n_sect]; | ||
| 187 | const file_offset = sect.offset + atom.value; | 220 | const file_offset = sect.offset + atom.value; |
| 188 | const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); | 221 | const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); |
| 189 | if (amt != buffer.len) return error.InputOutput; | 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,102 +225,65 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 192 | } | 225 | } |
| 193 | 226 | ||
| 194 | pub fn getAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) []const Relocation { | 227 | pub fn getAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) []const Relocation { |
| 195 | if (!atom.flags.relocs) return &[0]Relocation{}; | 228 | const extra = atom.getExtra(macho_file); |
| 196 | const extra = atom.getExtra(macho_file).?; | ||
| 197 | const relocs = self.relocs.items[extra.rel_index]; | 229 | const relocs = self.relocs.items[extra.rel_index]; |
| 198 | return relocs.items[0..extra.rel_count]; | 230 | return relocs.items[0..extra.rel_count]; |
| 199 | } | 231 | } |
| 200 | 232 | ||
| 201 | pub fn freeAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) void { | 233 | pub fn freeAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) void { |
| 202 | if (atom.flags.relocs) { | 234 | const extra = atom.getExtra(macho_file); |
| 203 | const extra = atom.getExtra(macho_file).?; | 235 | self.relocs.items[extra.rel_index].clearRetainingCapacity(); |
| 204 | self.relocs.items[extra.rel_index].clearRetainingCapacity(); | ||
| 205 | } | ||
| 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 | const tracy = trace(@src()); | 239 | const tracy = trace(@src()); |
| 210 | defer tracy.end(); | 240 | defer tracy.end(); |
| 211 | 241 | ||
| 212 | for (self.symbols.items, 0..) |index, i| { | 242 | const gpa = macho_file.base.comp.gpa; |
| 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]; | ||
| 216 | 243 | ||
| 244 | for (self.symtab.items(.nlist), self.symtab.items(.atom), self.globals.items, 0..) |nlist, atom_index, *global, i| { | ||
| 217 | if (!nlist.ext()) continue; | 245 | if (!nlist.ext()) continue; |
| 218 | if (nlist.undf() and !nlist.tentative()) continue; | ||
| 219 | if (nlist.sect()) { | 246 | if (nlist.sect()) { |
| 220 | const atom = macho_file.getAtom(atom_index).?; | 247 | const atom = self.getAtom(atom_index).?; |
| 221 | if (!atom.flags.alive) continue; | 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 | if (self.asFile().getSymbolRank(.{ | 266 | if (self.asFile().getSymbolRank(.{ |
| 226 | .archive = false, | 267 | .archive = false, |
| 227 | .weak = nlist.weakDef(), | 268 | .weak = nlist.weakDef(), |
| 228 | .tentative = nlist.tentative(), | 269 | .tentative = nlist.tentative(), |
| 229 | }) < symbol.getSymbolRank(macho_file)) { | 270 | }) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) { |
| 230 | const value = if (nlist.sect()) blk: { | 271 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; |
| 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; | ||
| 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 | pub fn markLive(self: *ZigObject, macho_file: *MachO) void { | 276 | pub fn markLive(self: *ZigObject, macho_file: *MachO) void { |
| 282 | const tracy = trace(@src()); | 277 | const tracy = trace(@src()); |
| 283 | defer tracy.end(); | 278 | defer tracy.end(); |
| 284 | 279 | ||
| 285 | for (self.symbols.items, 0..) |index, nlist_idx| { | 280 | for (0..self.symbols.items.len) |i| { |
| 286 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | 281 | const nlist = self.symtab.items(.nlist)[i]; |
| 287 | if (!nlist.ext()) continue; | 282 | if (!nlist.ext()) continue; |
| 288 | 283 | ||
| 289 | const sym = macho_file.getSymbol(index); | 284 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 290 | const file = sym.getFile(macho_file) orelse continue; | 285 | const file = ref.getFile(macho_file) orelse continue; |
| 286 | const sym = ref.getSymbol(macho_file).?; | ||
| 291 | const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative); | 287 | const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative); |
| 292 | if (should_keep and file == .object and !file.object.alive) { | 288 | if (should_keep and file == .object and !file.object.alive) { |
| 293 | file.object.alive = true; | 289 | file.object.alive = true; |
| ... | @@ -296,20 +292,18 @@ pub fn markLive(self: *ZigObject, macho_file: *MachO) void { | ... | @@ -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 { | 295 | pub fn mergeSymbolVisibility(self: *ZigObject, macho_file: *MachO) void { |
| 300 | for (self.symbols.items, 0..) |index, nlist_idx| { | 296 | const tracy = trace(@src()); |
| 301 | const sym = macho_file.getSymbol(index); | 297 | defer tracy.end(); |
| 302 | if (sym.visibility != .global) continue; | ||
| 303 | const file = sym.getFile(macho_file) orelse continue; | ||
| 304 | if (file.getIndex() == self.index) continue; | ||
| 305 | 298 | ||
| 306 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | 299 | for (self.symbols.items, 0..) |sym, i| { |
| 307 | if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) { | 300 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 308 | const gop = try dupes.getOrPut(index); | 301 | const global = ref.getSymbol(macho_file) orelse continue; |
| 309 | if (!gop.found_existing) { | 302 | if (sym.visibility.rank() < global.visibility.rank()) { |
| 310 | gop.value_ptr.* = .{}; | 303 | global.visibility = sym.visibility; |
| 311 | } | 304 | } |
| 312 | try gop.value_ptr.append(macho_file.base.comp.gpa, self.index); | 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,7 +325,9 @@ pub fn dedupLiterals(self: *ZigObject, lp: MachO.LiteralPool, macho_file: *MachO |
| 331 | /// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer. | 325 | /// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer. |
| 332 | /// We need this so that we can write to an archive. | 326 | /// We need this so that we can write to an archive. |
| 333 | /// TODO implement writing ZigObject data directly to a buffer instead. | 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 | const gpa = macho_file.base.comp.gpa; | 331 | const gpa = macho_file.base.comp.gpa; |
| 336 | try self.data.resize(gpa, size); | 332 | try self.data.resize(gpa, size); |
| 337 | const amt = try macho_file.base.file.?.preadAll(self.data.items, 0); | 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,9 +336,9 @@ pub fn readFileContents(self: *ZigObject, size: usize, macho_file: *MachO) !void |
| 340 | 336 | ||
| 341 | pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, macho_file: *MachO) error{OutOfMemory}!void { | 337 | pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, macho_file: *MachO) error{OutOfMemory}!void { |
| 342 | const gpa = macho_file.base.comp.gpa; | 338 | const gpa = macho_file.base.comp.gpa; |
| 343 | for (self.symbols.items) |sym_index| { | 339 | for (self.symbols.items, 0..) |sym, i| { |
| 344 | const sym = macho_file.getSymbol(sym_index); | 340 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 345 | const file = sym.getFile(macho_file).?; | 341 | const file = ref.getFile(macho_file).?; |
| 346 | assert(file.getIndex() == self.index); | 342 | assert(file.getIndex() == self.index); |
| 347 | if (!sym.flags.@"export") continue; | 343 | if (!sym.flags.@"export") continue; |
| 348 | const off = try ar_symtab.strtab.insert(gpa, sym.getName(macho_file)); | 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,9 +358,39 @@ pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !voi |
| 362 | try writer.writeAll(self.data.items); | 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 | pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void { | 391 | pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void { |
| 366 | for (self.atoms.items) |atom_index| { | 392 | for (self.getAtoms()) |atom_index| { |
| 367 | const atom = macho_file.getAtom(atom_index) orelse continue; | 393 | const atom = self.getAtom(atom_index) orelse continue; |
| 368 | if (!atom.flags.alive) continue; | 394 | if (!atom.flags.alive) continue; |
| 369 | const sect = atom.getInputSection(macho_file); | 395 | const sect = atom.getInputSection(macho_file); |
| 370 | if (sect.isZerofill()) continue; | 396 | if (sect.isZerofill()) continue; |
| ... | @@ -372,25 +398,168 @@ pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void { | ... | @@ -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 | const tracy = trace(@src()); | 545 | const tracy = trace(@src()); |
| 377 | defer tracy.end(); | 546 | defer tracy.end(); |
| 378 | 547 | ||
| 379 | for (self.symbols.items) |sym_index| { | 548 | for (self.symbols.items, 0..) |*sym, i| { |
| 380 | const sym = macho_file.getSymbol(sym_index); | 549 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 381 | const file = sym.getFile(macho_file) orelse continue; | 550 | const file = ref.getFile(macho_file) orelse continue; |
| 382 | if (file.getIndex() != self.index) continue; | 551 | if (file.getIndex() != self.index) continue; |
| 383 | if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; | 552 | if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; |
| 384 | sym.flags.output_symtab = true; | 553 | sym.flags.output_symtab = true; |
| 385 | if (sym.isLocal()) { | 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 | self.output_symtab_ctx.nlocals += 1; | 556 | self.output_symtab_ctx.nlocals += 1; |
| 388 | } else if (sym.flags.@"export") { | 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 | self.output_symtab_ctx.nexports += 1; | 559 | self.output_symtab_ctx.nexports += 1; |
| 391 | } else { | 560 | } else { |
| 392 | assert(sym.flags.import); | 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 | self.output_symtab_ctx.nimports += 1; | 563 | self.output_symtab_ctx.nimports += 1; |
| 395 | } | 564 | } |
| 396 | self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1)); | 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,17 +570,20 @@ pub fn writeSymtab(self: ZigObject, macho_file: *MachO, ctx: anytype) void { |
| 401 | const tracy = trace(@src()); | 570 | const tracy = trace(@src()); |
| 402 | defer tracy.end(); | 571 | defer tracy.end(); |
| 403 | 572 | ||
| 404 | for (self.symbols.items) |sym_index| { | 573 | var n_strx = self.output_symtab_ctx.stroff; |
| 405 | const sym = macho_file.getSymbol(sym_index); | 574 | for (self.symbols.items, 0..) |sym, i| { |
| 406 | const file = sym.getFile(macho_file) orelse continue; | 575 | const ref = self.getSymbolRef(@intCast(i), macho_file); |
| 576 | const file = ref.getFile(macho_file) orelse continue; | ||
| 407 | if (file.getIndex() != self.index) continue; | 577 | if (file.getIndex() != self.index) continue; |
| 408 | const idx = sym.getOutputSymtabIndex(macho_file) orelse continue; | 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 | const out_sym = &ctx.symtab.items[idx]; | 579 | const out_sym = &ctx.symtab.items[idx]; |
| 413 | out_sym.n_strx = n_strx; | 580 | out_sym.n_strx = n_strx; |
| 414 | sym.setOutputSym(macho_file, out_sym); | 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,9 +696,9 @@ pub fn getDeclVAddr( |
| 524 | reloc_info: link.File.RelocInfo, | 696 | reloc_info: link.File.RelocInfo, |
| 525 | ) !u64 { | 697 | ) !u64 { |
| 526 | const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index); | 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 | const vaddr = sym.getAddress(.{}, macho_file); | 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 | try parent_atom.addReloc(macho_file, .{ | 702 | try parent_atom.addReloc(macho_file, .{ |
| 531 | .tag = .@"extern", | 703 | .tag = .@"extern", |
| 532 | .offset = @intCast(reloc_info.offset), | 704 | .offset = @intCast(reloc_info.offset), |
| ... | @@ -550,9 +722,9 @@ pub fn getAnonDeclVAddr( | ... | @@ -550,9 +722,9 @@ pub fn getAnonDeclVAddr( |
| 550 | reloc_info: link.File.RelocInfo, | 722 | reloc_info: link.File.RelocInfo, |
| 551 | ) !u64 { | 723 | ) !u64 { |
| 552 | const sym_index = self.anon_decls.get(decl_val).?.symbol_index; | 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 | const vaddr = sym.getAddress(.{}, macho_file); | 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 | try parent_atom.addReloc(macho_file, .{ | 728 | try parent_atom.addReloc(macho_file, .{ |
| 557 | .tag = .@"extern", | 729 | .tag = .@"extern", |
| 558 | .offset = @intCast(reloc_info.offset), | 730 | .offset = @intCast(reloc_info.offset), |
| ... | @@ -585,7 +757,7 @@ pub fn lowerAnonDecl( | ... | @@ -585,7 +757,7 @@ pub fn lowerAnonDecl( |
| 585 | else => explicit_alignment, | 757 | else => explicit_alignment, |
| 586 | }; | 758 | }; |
| 587 | if (self.anon_decls.get(decl_val)) |metadata| { | 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 | if (decl_alignment.order(existing_alignment).compare(.lte)) | 761 | if (decl_alignment.order(existing_alignment).compare(.lte)) |
| 590 | return .ok; | 762 | return .ok; |
| 591 | } | 763 | } |
| ... | @@ -629,13 +801,10 @@ fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPoo | ... | @@ -629,13 +801,10 @@ fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPoo |
| 629 | } | 801 | } |
| 630 | 802 | ||
| 631 | fn freeDeclMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Index) void { | 803 | fn freeDeclMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Index) void { |
| 632 | _ = self; | 804 | const sym = self.symbols.items[sym_index]; |
| 633 | const gpa = macho_file.base.comp.gpa; | ||
| 634 | const sym = macho_file.getSymbol(sym_index); | ||
| 635 | sym.getAtom(macho_file).?.free(macho_file); | 805 | sym.getAtom(macho_file).?.free(macho_file); |
| 636 | log.debug("adding %{d} to local symbols free list", .{sym_index}); | 806 | log.debug("adding %{d} to local symbols free list", .{sym_index}); |
| 637 | macho_file.symbols_free_list.append(gpa, sym_index) catch {}; | 807 | // TODO redo this |
| 638 | macho_file.symbols.items[sym_index] = .{}; | ||
| 639 | // TODO free GOT entry here | 808 | // TODO free GOT entry here |
| 640 | } | 809 | } |
| 641 | 810 | ||
| ... | @@ -676,7 +845,7 @@ pub fn updateFunc( | ... | @@ -676,7 +845,7 @@ pub fn updateFunc( |
| 676 | 845 | ||
| 677 | const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index); | 846 | const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index); |
| 678 | self.freeUnnamedConsts(macho_file, decl_index); | 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 | var code_buffer = std.ArrayList(u8).init(gpa); | 850 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 682 | defer code_buffer.deinit(); | 851 | defer code_buffer.deinit(); |
| ... | @@ -709,7 +878,7 @@ pub fn updateFunc( | ... | @@ -709,7 +878,7 @@ pub fn updateFunc( |
| 709 | try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code); | 878 | try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code); |
| 710 | 879 | ||
| 711 | if (decl_state) |*ds| { | 880 | if (decl_state) |*ds| { |
| 712 | const sym = macho_file.getSymbol(sym_index); | 881 | const sym = self.symbols.items[sym_index]; |
| 713 | try self.dwarf.?.commitDeclState( | 882 | try self.dwarf.?.commitDeclState( |
| 714 | pt, | 883 | pt, |
| 715 | decl_index, | 884 | decl_index, |
| ... | @@ -744,13 +913,13 @@ pub fn updateDecl( | ... | @@ -744,13 +913,13 @@ pub fn updateDecl( |
| 744 | const name = decl.name.toSlice(&mod.intern_pool); | 913 | const name = decl.name.toSlice(&mod.intern_pool); |
| 745 | const lib_name = variable.lib_name.toSlice(&mod.intern_pool); | 914 | const lib_name = variable.lib_name.toSlice(&mod.intern_pool); |
| 746 | const index = try self.getGlobalSymbol(macho_file, name, lib_name); | 915 | const index = try self.getGlobalSymbol(macho_file, name, lib_name); |
| 747 | const actual_index = self.symbols.items[index]; | 916 | const sym = &self.symbols.items[index]; |
| 748 | macho_file.getSymbol(actual_index).flags.needs_got = true; | 917 | sym.flags.needs_got = true; |
| 749 | return; | 918 | return; |
| 750 | } | 919 | } |
| 751 | 920 | ||
| 752 | const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index); | 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 | const gpa = macho_file.base.comp.gpa; | 924 | const gpa = macho_file.base.comp.gpa; |
| 756 | var code_buffer = std.ArrayList(u8).init(gpa); | 925 | var code_buffer = std.ArrayList(u8).init(gpa); |
| ... | @@ -773,19 +942,16 @@ pub fn updateDecl( | ... | @@ -773,19 +942,16 @@ pub fn updateDecl( |
| 773 | return; | 942 | return; |
| 774 | }, | 943 | }, |
| 775 | }; | 944 | }; |
| 776 | const sect_index = try self.getDeclOutputSection(macho_file, decl, code); | 945 | if (isThreadlocal(macho_file, decl_index)) { |
| 777 | const is_threadlocal = switch (macho_file.sections.items(.header)[sect_index].type()) { | 946 | const sect_index = try self.getDeclOutputSection(macho_file, decl, code); |
| 778 | macho.S_THREAD_LOCAL_ZEROFILL, macho.S_THREAD_LOCAL_REGULAR => true, | ||
| 779 | else => false, | ||
| 780 | }; | ||
| 781 | if (is_threadlocal) { | ||
| 782 | try self.updateTlv(macho_file, pt, decl_index, sym_index, sect_index, code); | 947 | try self.updateTlv(macho_file, pt, decl_index, sym_index, sect_index, code); |
| 783 | } else { | 948 | } else { |
| 949 | const sect_index = try self.getDeclOutputSection(macho_file, decl, code); | ||
| 784 | try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code); | 950 | try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code); |
| 785 | } | 951 | } |
| 786 | 952 | ||
| 787 | if (decl_state) |*ds| { | 953 | if (decl_state) |*ds| { |
| 788 | const sym = macho_file.getSymbol(sym_index); | 954 | const sym = self.symbols.items[sym_index]; |
| 789 | try self.dwarf.?.commitDeclState( | 955 | try self.dwarf.?.commitDeclState( |
| 790 | pt, | 956 | pt, |
| 791 | decl_index, | 957 | decl_index, |
| ... | @@ -817,14 +983,16 @@ fn updateDeclCode( | ... | @@ -817,14 +983,16 @@ fn updateDeclCode( |
| 817 | const required_alignment = decl.getAlignment(pt); | 983 | const required_alignment = decl.getAlignment(pt); |
| 818 | 984 | ||
| 819 | const sect = &macho_file.sections.items(.header)[sect_index]; | 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 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; | 987 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 822 | const atom = sym.getAtom(macho_file).?; | 988 | const atom = sym.getAtom(macho_file).?; |
| 823 | 989 | ||
| 824 | sym.out_n_sect = sect_index; | 990 | sym.out_n_sect = sect_index; |
| 825 | atom.out_n_sect = sect_index; | 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 | atom.flags.alive = true; | 996 | atom.flags.alive = true; |
| 829 | atom.name = sym.name; | 997 | atom.name = sym.name; |
| 830 | nlist.n_strx = sym.name; | 998 | nlist.n_strx = sym.name; |
| ... | @@ -851,13 +1019,13 @@ fn updateDeclCode( | ... | @@ -851,13 +1019,13 @@ fn updateDeclCode( |
| 851 | if (!macho_file.base.isRelocatable()) { | 1019 | if (!macho_file.base.isRelocatable()) { |
| 852 | log.debug(" (updating offset table entry)", .{}); | 1020 | log.debug(" (updating offset table entry)", .{}); |
| 853 | assert(sym.flags.has_zig_got); | 1021 | assert(sym.flags.has_zig_got); |
| 854 | const extra = sym.getExtra(macho_file).?; | 1022 | const extra = sym.getExtra(macho_file); |
| 855 | try macho_file.zig_got.writeOne(macho_file, extra.zig_got); | 1023 | try macho_file.zig_got.writeOne(macho_file, extra.zig_got); |
| 856 | } | 1024 | } |
| 857 | } | 1025 | } |
| 858 | } else if (code.len < old_size) { | 1026 | } else if (code.len < old_size) { |
| 859 | atom.shrink(macho_file); | 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 | const needed_size = atom.value + code.len; | 1029 | const needed_size = atom.value + code.len; |
| 862 | sect.size = needed_size; | 1030 | sect.size = needed_size; |
| 863 | } | 1031 | } |
| ... | @@ -922,31 +1090,22 @@ fn createTlvInitializer( | ... | @@ -922,31 +1090,22 @@ fn createTlvInitializer( |
| 922 | const gpa = macho_file.base.comp.gpa; | 1090 | const gpa = macho_file.base.comp.gpa; |
| 923 | const sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{name}); | 1091 | const sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{name}); |
| 924 | defer gpa.free(sym_name); | 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); | 1095 | const sym_index = try self.newSymbolWithAtom(gpa, off, macho_file); |
| 927 | const sym = macho_file.getSymbol(sym_index); | 1096 | const sym = &self.symbols.items[sym_index]; |
| 928 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; | 1097 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 929 | const atom = sym.getAtom(macho_file).?; | 1098 | const atom = sym.getAtom(macho_file).?; |
| 930 | |||
| 931 | sym.out_n_sect = sect_index; | 1099 | sym.out_n_sect = sect_index; |
| 932 | atom.out_n_sect = sect_index; | 1100 | atom.out_n_sect = sect_index; |
| 933 | |||
| 934 | sym.value = 0; | ||
| 935 | sym.name = try self.strtab.insert(gpa, sym_name); | ||
| 936 | atom.flags.alive = true; | 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 | atom.alignment = alignment; | 1102 | atom.alignment = alignment; |
| 945 | atom.size = code.len; | 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 | const slice = macho_file.sections.slice(); | 1107 | const slice = macho_file.sections.slice(); |
| 948 | const header = slice.items(.header)[sect_index]; | 1108 | const header = slice.items(.header)[sect_index]; |
| 949 | const atoms = &slice.items(.atoms)[sect_index]; | ||
| 950 | 1109 | ||
| 951 | const gop = try self.tlv_initializers.getOrPut(gpa, atom.atom_index); | 1110 | const gop = try self.tlv_initializers.getOrPut(gpa, atom.atom_index); |
| 952 | assert(!gop.found_existing); // TODO incremental updates | 1111 | assert(!gop.found_existing); // TODO incremental updates |
| ... | @@ -957,8 +1116,6 @@ fn createTlvInitializer( | ... | @@ -957,8 +1116,6 @@ fn createTlvInitializer( |
| 957 | gop.value_ptr.data = try gpa.dupe(u8, code); | 1116 | gop.value_ptr.data = try gpa.dupe(u8, code); |
| 958 | } | 1117 | } |
| 959 | 1118 | ||
| 960 | try atoms.append(gpa, atom.atom_index); | ||
| 961 | |||
| 962 | return sym_index; | 1119 | return sym_index; |
| 963 | } | 1120 | } |
| 964 | 1121 | ||
| ... | @@ -971,7 +1128,7 @@ fn createTlvDescriptor( | ... | @@ -971,7 +1128,7 @@ fn createTlvDescriptor( |
| 971 | ) !void { | 1128 | ) !void { |
| 972 | const gpa = macho_file.base.comp.gpa; | 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 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; | 1132 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 976 | const atom = sym.getAtom(macho_file).?; | 1133 | const atom = sym.getAtom(macho_file).?; |
| 977 | const alignment = Atom.Alignment.fromNonzeroByteUnits(@alignOf(u64)); | 1134 | const alignment = Atom.Alignment.fromNonzeroByteUnits(@alignOf(u64)); |
| ... | @@ -1001,7 +1158,7 @@ fn createTlvDescriptor( | ... | @@ -1001,7 +1158,7 @@ fn createTlvDescriptor( |
| 1001 | try atom.addReloc(macho_file, .{ | 1158 | try atom.addReloc(macho_file, .{ |
| 1002 | .tag = .@"extern", | 1159 | .tag = .@"extern", |
| 1003 | .offset = 0, | 1160 | .offset = 0, |
| 1004 | .target = self.symbols.items[tlv_bootstrap_index], | 1161 | .target = tlv_bootstrap_index, |
| 1005 | .addend = 0, | 1162 | .addend = 0, |
| 1006 | .type = .unsigned, | 1163 | .type = .unsigned, |
| 1007 | .meta = .{ | 1164 | .meta = .{ |
| ... | @@ -1021,11 +1178,9 @@ fn createTlvDescriptor( | ... | @@ -1021,11 +1178,9 @@ fn createTlvDescriptor( |
| 1021 | .pcrel = false, | 1178 | .pcrel = false, |
| 1022 | .has_subtractor = false, | 1179 | .has_subtractor = false, |
| 1023 | .length = 3, | 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 | fn getDeclOutputSection( | 1186 | fn getDeclOutputSection( |
| ... | @@ -1116,8 +1271,8 @@ pub fn lowerUnnamedConst( | ... | @@ -1116,8 +1271,8 @@ pub fn lowerUnnamedConst( |
| 1116 | return error.CodegenFail; | 1271 | return error.CodegenFail; |
| 1117 | }, | 1272 | }, |
| 1118 | }; | 1273 | }; |
| 1119 | const sym = macho_file.getSymbol(sym_index); | 1274 | const sym = self.symbols.items[sym_index]; |
| 1120 | try unnamed_consts.append(gpa, sym.atom); | 1275 | try unnamed_consts.append(gpa, sym.atom_ref.index); |
| 1121 | return sym_index; | 1276 | return sym_index; |
| 1122 | } | 1277 | } |
| 1123 | 1278 | ||
| ... | @@ -1141,7 +1296,8 @@ fn lowerConst( | ... | @@ -1141,7 +1296,8 @@ fn lowerConst( |
| 1141 | var code_buffer = std.ArrayList(u8).init(gpa); | 1296 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1142 | defer code_buffer.deinit(); | 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 | const res = try codegen.generateSymbol(&macho_file.base, pt, src_loc, val, &code_buffer, .{ | 1302 | const res = try codegen.generateSymbol(&macho_file.base, pt, src_loc, val, &code_buffer, .{ |
| 1147 | .none = {}, | 1303 | .none = {}, |
| ... | @@ -1153,20 +1309,15 @@ fn lowerConst( | ... | @@ -1153,20 +1309,15 @@ fn lowerConst( |
| 1153 | .fail => |em| return .{ .fail = em }, | 1309 | .fail => |em| return .{ .fail = em }, |
| 1154 | }; | 1310 | }; |
| 1155 | 1311 | ||
| 1156 | const sym = macho_file.getSymbol(sym_index); | 1312 | const sym = &self.symbols.items[sym_index]; |
| 1157 | const name_str_index = try self.strtab.insert(gpa, name); | ||
| 1158 | sym.name = name_str_index; | ||
| 1159 | sym.out_n_sect = output_section_index; | 1313 | sym.out_n_sect = output_section_index; |
| 1160 | 1314 | ||
| 1161 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; | 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 | nlist.n_sect = output_section_index + 1; | 1316 | nlist.n_sect = output_section_index + 1; |
| 1165 | self.symtab.items(.size)[sym.nlist_idx] = code.len; | 1317 | self.symtab.items(.size)[sym.nlist_idx] = code.len; |
| 1166 | 1318 | ||
| 1167 | const atom = sym.getAtom(macho_file).?; | 1319 | const atom = sym.getAtom(macho_file).?; |
| 1168 | atom.flags.alive = true; | 1320 | atom.flags.alive = true; |
| 1169 | atom.name = name_str_index; | ||
| 1170 | atom.alignment = required_alignment; | 1321 | atom.alignment = required_alignment; |
| 1171 | atom.size = code.len; | 1322 | atom.size = code.len; |
| 1172 | atom.out_n_sect = output_section_index; | 1323 | atom.out_n_sect = output_section_index; |
| ... | @@ -1175,9 +1326,6 @@ fn lowerConst( | ... | @@ -1175,9 +1326,6 @@ fn lowerConst( |
| 1175 | // TODO rename and re-audit this method | 1326 | // TODO rename and re-audit this method |
| 1176 | errdefer self.freeDeclMetadata(macho_file, sym_index); | 1327 | errdefer self.freeDeclMetadata(macho_file, sym_index); |
| 1177 | 1328 | ||
| 1178 | sym.value = 0; | ||
| 1179 | nlist.n_value = 0; | ||
| 1180 | |||
| 1181 | const sect = macho_file.sections.items(.header)[output_section_index]; | 1329 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 1182 | const file_offset = sect.offset + atom.value; | 1330 | const file_offset = sect.offset + atom.value; |
| 1183 | try macho_file.base.file.?.pwriteAll(code, file_offset); | 1331 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| ... | @@ -1219,7 +1367,7 @@ pub fn updateExports( | ... | @@ -1219,7 +1367,7 @@ pub fn updateExports( |
| 1219 | }, | 1367 | }, |
| 1220 | }; | 1368 | }; |
| 1221 | const sym_index = metadata.symbol_index; | 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 | const nlist = self.symtab.items(.nlist)[nlist_idx]; | 1371 | const nlist = self.symtab.items(.nlist)[nlist_idx]; |
| 1224 | 1372 | ||
| 1225 | for (export_indices) |export_idx| { | 1373 | for (export_indices) |export_idx| { |
| ... | @@ -1255,22 +1403,30 @@ pub fn updateExports( | ... | @@ -1255,22 +1403,30 @@ pub fn updateExports( |
| 1255 | break :blk global_nlist_index; | 1403 | break :blk global_nlist_index; |
| 1256 | }; | 1404 | }; |
| 1257 | const global_nlist = &self.symtab.items(.nlist)[global_nlist_index]; | 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 | global_nlist.n_value = nlist.n_value; | 1408 | global_nlist.n_value = nlist.n_value; |
| 1259 | global_nlist.n_sect = nlist.n_sect; | 1409 | global_nlist.n_sect = nlist.n_sect; |
| 1260 | global_nlist.n_type = macho.N_EXT | macho.N_SECT; | 1410 | global_nlist.n_type = macho.N_EXT | macho.N_SECT; |
| 1261 | self.symtab.items(.size)[global_nlist_index] = self.symtab.items(.size)[nlist_idx]; | 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 | switch (exp.opts.linkage) { | 1415 | switch (exp.opts.linkage) { |
| 1265 | .internal => { | 1416 | .internal => { |
| 1266 | // Symbol should be hidden, or in MachO lingo, private extern. | 1417 | // Symbol should be hidden, or in MachO lingo, private extern. |
| 1267 | global_nlist.n_type |= macho.N_PEXT; | 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 | .weak => { | 1424 | .weak => { |
| 1271 | // Weak linkage is specified as part of n_desc field. | 1425 | // Weak linkage is specified as part of n_desc field. |
| 1272 | // Symbol's n_type is like for a symbol with strong linkage. | 1426 | // Symbol's n_type is like for a symbol with strong linkage. |
| 1273 | global_nlist.n_desc |= macho.N_WEAK_DEF; | 1427 | global_nlist.n_desc |= macho.N_WEAK_DEF; |
| 1428 | global_sym.visibility = .global; | ||
| 1429 | global_sym.flags.weak = true; | ||
| 1274 | }, | 1430 | }, |
| 1275 | else => unreachable, | 1431 | else => unreachable, |
| 1276 | } | 1432 | } |
| ... | @@ -1323,7 +1479,7 @@ fn updateLazySymbol( | ... | @@ -1323,7 +1479,7 @@ fn updateLazySymbol( |
| 1323 | .code => macho_file.zig_text_sect_index.?, | 1479 | .code => macho_file.zig_text_sect_index.?, |
| 1324 | .const_data => macho_file.zig_const_sect_index.?, | 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 | sym.name = name_str_index; | 1483 | sym.name = name_str_index; |
| 1328 | sym.out_n_sect = output_section_index; | 1484 | sym.out_n_sect = output_section_index; |
| 1329 | 1485 | ||
| ... | @@ -1383,12 +1539,12 @@ pub fn deleteExport( | ... | @@ -1383,12 +1539,12 @@ pub fn deleteExport( |
| 1383 | const nlist = &self.symtab.items(.nlist)[nlist_index.*]; | 1539 | const nlist = &self.symtab.items(.nlist)[nlist_index.*]; |
| 1384 | self.symtab.items(.size)[nlist_index.*] = 0; | 1540 | self.symtab.items(.size)[nlist_index.*] = 0; |
| 1385 | _ = self.globals_lookup.remove(nlist.n_strx); | 1541 | _ = self.globals_lookup.remove(nlist.n_strx); |
| 1386 | const sym_index = macho_file.globals.get(nlist.n_strx).?; | 1542 | // TODO actually remove the export |
| 1387 | const sym = macho_file.getSymbol(sym_index); | 1543 | // const sym_index = macho_file.globals.get(nlist.n_strx).?; |
| 1388 | if (sym.file == self.index) { | 1544 | // const sym = &self.symbols.items[sym_index]; |
| 1389 | _ = macho_file.globals.swapRemove(nlist.n_strx); | 1545 | // if (sym.file == self.index) { |
| 1390 | sym.* = .{}; | 1546 | // sym.* = .{}; |
| 1391 | } | 1547 | // } |
| 1392 | nlist.* = MachO.null_sym; | 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,14 +1556,9 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l |
| 1400 | const off = try self.strtab.insert(gpa, sym_name); | 1556 | const off = try self.strtab.insert(gpa, sym_name); |
| 1401 | const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); | 1557 | const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); |
| 1402 | if (!lookup_gop.found_existing) { | 1558 | if (!lookup_gop.found_existing) { |
| 1403 | const nlist_index = try self.addNlist(gpa); | 1559 | const sym_index = try self.newSymbol(gpa, off, .{}); |
| 1404 | const nlist = &self.symtab.items(.nlist)[nlist_index]; | 1560 | const sym = &self.symbols.items[sym_index]; |
| 1405 | nlist.n_strx = off; | 1561 | lookup_gop.value_ptr.* = sym.nlist_idx; |
| 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); | ||
| 1411 | } | 1562 | } |
| 1412 | return lookup_gop.value_ptr.*; | 1563 | return lookup_gop.value_ptr.*; |
| 1413 | } | 1564 | } |
| ... | @@ -1420,17 +1571,11 @@ pub fn getOrCreateMetadataForDecl( | ... | @@ -1420,17 +1571,11 @@ pub fn getOrCreateMetadataForDecl( |
| 1420 | const gpa = macho_file.base.comp.gpa; | 1571 | const gpa = macho_file.base.comp.gpa; |
| 1421 | const gop = try self.decls.getOrPut(gpa, decl_index); | 1572 | const gop = try self.decls.getOrPut(gpa, decl_index); |
| 1422 | if (!gop.found_existing) { | 1573 | if (!gop.found_existing) { |
| 1423 | const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded; | 1574 | const sym_index = try self.newSymbolWithAtom(gpa, 0, macho_file); |
| 1424 | const sym_index = try self.addAtom(macho_file); | 1575 | const sym = &self.symbols.items[sym_index]; |
| 1425 | const mod = macho_file.base.comp.module.?; | 1576 | if (isThreadlocal(macho_file, decl_index)) { |
| 1426 | const decl = mod.declPtr(decl_index); | 1577 | sym.flags.tlv = true; |
| 1427 | const sym = macho_file.getSymbol(sym_index); | 1578 | } else { |
| 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) { | ||
| 1434 | sym.flags.needs_zig_got = true; | 1579 | sym.flags.needs_zig_got = true; |
| 1435 | } | 1580 | } |
| 1436 | gop.value_ptr.* = .{ .symbol_index = sym_index }; | 1581 | gop.value_ptr.* = .{ .symbol_index = sym_index }; |
| ... | @@ -1464,8 +1609,8 @@ pub fn getOrCreateMetadataForLazySymbol( | ... | @@ -1464,8 +1609,8 @@ pub fn getOrCreateMetadataForLazySymbol( |
| 1464 | }; | 1609 | }; |
| 1465 | switch (metadata.state.*) { | 1610 | switch (metadata.state.*) { |
| 1466 | .unused => { | 1611 | .unused => { |
| 1467 | const symbol_index = try self.addAtom(macho_file); | 1612 | const symbol_index = try self.newSymbolWithAtom(gpa, 0, macho_file); |
| 1468 | const sym = macho_file.getSymbol(symbol_index); | 1613 | const sym = &self.symbols.items[symbol_index]; |
| 1469 | sym.flags.needs_zig_got = true; | 1614 | sym.flags.needs_zig_got = true; |
| 1470 | metadata.symbol_index.* = symbol_index; | 1615 | metadata.symbol_index.* = symbol_index; |
| 1471 | }, | 1616 | }, |
| ... | @@ -1479,6 +1624,144 @@ pub fn getOrCreateMetadataForLazySymbol( | ... | @@ -1479,6 +1624,144 @@ pub fn getOrCreateMetadataForLazySymbol( |
| 1479 | return symbol_index; | 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 | pub fn asFile(self: *ZigObject) File { | 1765 | pub fn asFile(self: *ZigObject) File { |
| 1483 | return .{ .zig_object = self }; | 1766 | return .{ .zig_object = self }; |
| 1484 | } | 1767 | } |
| ... | @@ -1504,9 +1787,16 @@ fn formatSymtab( | ... | @@ -1504,9 +1787,16 @@ fn formatSymtab( |
| 1504 | _ = unused_fmt_string; | 1787 | _ = unused_fmt_string; |
| 1505 | _ = options; | 1788 | _ = options; |
| 1506 | try writer.writeAll(" symbols\n"); | 1789 | try writer.writeAll(" symbols\n"); |
| 1507 | for (ctx.self.symbols.items) |index| { | 1790 | const self = ctx.self; |
| 1508 | const sym = ctx.macho_file.getSymbol(index); | 1791 | const macho_file = ctx.macho_file; |
| 1509 | try writer.print(" {}\n", .{sym.fmt(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,10 +1815,12 @@ fn formatAtoms( |
| 1525 | ) !void { | 1815 | ) !void { |
| 1526 | _ = unused_fmt_string; | 1816 | _ = unused_fmt_string; |
| 1527 | _ = options; | 1817 | _ = options; |
| 1818 | const self = ctx.self; | ||
| 1819 | const macho_file = ctx.macho_file; | ||
| 1528 | try writer.writeAll(" atoms\n"); | 1820 | try writer.writeAll(" atoms\n"); |
| 1529 | for (ctx.self.atoms.items) |atom_index| { | 1821 | for (self.getAtoms()) |atom_index| { |
| 1530 | const atom = ctx.macho_file.getAtom(atom_index) orelse continue; | 1822 | const atom = self.getAtom(atom_index) orelse continue; |
| 1531 | try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)}); | 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,16 +17,16 @@ pub fn gcAtoms(macho_file: *MachO) !void { |
| 17 | fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho_file: *MachO) !void { | 17 | fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho_file: *MachO) !void { |
| 18 | for (objects) |index| { | 18 | for (objects) |index| { |
| 19 | const object = macho_file.getFile(index).?; | 19 | const object = macho_file.getFile(index).?; |
| 20 | for (object.getSymbols()) |sym_index| { | 20 | for (object.getSymbols(), 0..) |*sym, i| { |
| 21 | const sym = macho_file.getSymbol(sym_index); | 21 | const ref = object.getSymbolRef(@intCast(i), macho_file); |
| 22 | const file = sym.getFile(macho_file) orelse continue; | 22 | const file = ref.getFile(macho_file) orelse continue; |
| 23 | if (file.getIndex() != index) continue; | 23 | if (file.getIndex() != index) continue; |
| 24 | if (sym.flags.no_dead_strip or (macho_file.base.isDynLib() and sym.visibility == .global)) | 24 | if (sym.flags.no_dead_strip or (macho_file.base.isDynLib() and sym.visibility == .global)) |
| 25 | try markSymbol(sym, roots, macho_file); | 25 | try markSymbol(sym, roots, macho_file); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | for (object.getAtoms()) |atom_index| { | 28 | for (object.getAtoms()) |atom_index| { |
| 29 | const atom = macho_file.getAtom(atom_index).?; | 29 | const atom = object.getAtom(atom_index) orelse continue; |
| 30 | const isec = atom.getInputSection(macho_file); | 30 | const isec = atom.getInputSection(macho_file); |
| 31 | switch (isec.type()) { | 31 | switch (isec.type()) { |
| 32 | macho.S_MOD_INIT_FUNC_POINTERS, | 32 | macho.S_MOD_INIT_FUNC_POINTERS, |
| ... | @@ -41,8 +41,9 @@ fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho | ... | @@ -41,8 +41,9 @@ fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | for (macho_file.objects.items) |index| { | 43 | for (macho_file.objects.items) |index| { |
| 44 | for (macho_file.getFile(index).?.object.unwind_records.items) |cu_index| { | 44 | const object = macho_file.getFile(index).?.object; |
| 45 | const cu = macho_file.getUnwindRecord(cu_index); | 45 | for (object.unwind_records_indexes.items) |cu_index| { |
| 46 | const cu = object.getUnwindRecord(cu_index); | ||
| 46 | if (!cu.alive) continue; | 47 | if (!cu.alive) continue; |
| 47 | if (cu.getFde(macho_file)) |fde| { | 48 | if (cu.getFde(macho_file)) |fde| { |
| 48 | if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| try markSymbol(sym, roots, macho_file); | 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,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 | if (macho_file.getInternalObject()) |obj| { |
| 54 | const sym = macho_file.getSymbol(sym_index); | 55 | for (obj.force_undefined.items) |sym_index| { |
| 55 | try markSymbol(sym, roots, macho_file); | 56 | const ref = obj.getSymbolRef(sym_index, macho_file); |
| 56 | } | 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{ | 63 | for (&[_]?Symbol.Index{ |
| 59 | macho_file.entry_index, | 64 | obj.entry_index, |
| 60 | macho_file.dyld_stub_binder_index, | 65 | obj.dyld_stub_binder_index, |
| 61 | macho_file.objc_msg_send_index, | 66 | obj.objc_msg_send_index, |
| 62 | }) |index| { | 67 | }) |index| { |
| 63 | if (index) |idx| { | 68 | if (index) |idx| { |
| 64 | const sym = macho_file.getSymbol(idx); | 69 | const ref = obj.getSymbolRef(idx, macho_file); |
| 65 | try markSymbol(sym, roots, 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,8 +97,9 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void { |
| 88 | loop = false; | 97 | loop = false; |
| 89 | 98 | ||
| 90 | for (objects) |index| { | 99 | for (objects) |index| { |
| 91 | for (macho_file.getFile(index).?.getAtoms()) |atom_index| { | 100 | const file = macho_file.getFile(index).?; |
| 92 | const atom = macho_file.getAtom(atom_index).?; | 101 | for (file.getAtoms()) |atom_index| { |
| 102 | const atom = file.getAtom(atom_index) orelse continue; | ||
| 93 | const isec = atom.getInputSection(macho_file); | 103 | const isec = atom.getInputSection(macho_file); |
| 94 | if (isec.isDontDeadStripIfReferencesLive() and | 104 | if (isec.isDontDeadStripIfReferencesLive() and |
| 95 | !(mem.eql(u8, isec.sectName(), "__eh_frame") or | 105 | !(mem.eql(u8, isec.sectName(), "__eh_frame") or |
| ... | @@ -119,16 +129,20 @@ fn markLive(atom: *Atom, macho_file: *MachO) void { | ... | @@ -119,16 +129,20 @@ fn markLive(atom: *Atom, macho_file: *MachO) void { |
| 119 | 129 | ||
| 120 | for (atom.getRelocs(macho_file)) |rel| { | 130 | for (atom.getRelocs(macho_file)) |rel| { |
| 121 | const target_atom = switch (rel.tag) { | 131 | const target_atom = switch (rel.tag) { |
| 122 | .local => rel.getTargetAtom(macho_file), | 132 | .local => rel.getTargetAtom(atom.*, macho_file), |
| 123 | .@"extern" => rel.getTargetSymbol(macho_file).getAtom(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 | if (target_atom) |ta| { | 138 | if (target_atom) |ta| { |
| 126 | if (markAtom(ta)) markLive(ta, macho_file); | 139 | if (markAtom(ta)) markLive(ta, macho_file); |
| 127 | } | 140 | } |
| 128 | } | 141 | } |
| 129 | 142 | ||
| 143 | const file = atom.getFile(macho_file); | ||
| 130 | for (atom.getUnwindRecords(macho_file)) |cu_index| { | 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 | const cu_atom = cu.getAtom(macho_file); | 146 | const cu_atom = cu.getAtom(macho_file); |
| 133 | if (markAtom(cu_atom)) markLive(cu_atom, macho_file); | 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,8 +163,11 @@ fn markLive(atom: *Atom, macho_file: *MachO) void { |
| 149 | fn refersLive(atom: *Atom, macho_file: *MachO) bool { | 163 | fn refersLive(atom: *Atom, macho_file: *MachO) bool { |
| 150 | for (atom.getRelocs(macho_file)) |rel| { | 164 | for (atom.getRelocs(macho_file)) |rel| { |
| 151 | const target_atom = switch (rel.tag) { | 165 | const target_atom = switch (rel.tag) { |
| 152 | .local => rel.getTargetAtom(macho_file), | 166 | .local => rel.getTargetAtom(atom.*, macho_file), |
| 153 | .@"extern" => rel.getTargetSymbol(macho_file).getAtom(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 | if (target_atom) |ta| { | 172 | if (target_atom) |ta| { |
| 156 | if (ta.flags.alive) return true; | 173 | if (ta.flags.alive) return true; |
| ... | @@ -161,8 +178,9 @@ fn refersLive(atom: *Atom, macho_file: *MachO) bool { | ... | @@ -161,8 +178,9 @@ fn refersLive(atom: *Atom, macho_file: *MachO) bool { |
| 161 | 178 | ||
| 162 | fn prune(objects: []const File.Index, macho_file: *MachO) void { | 179 | fn prune(objects: []const File.Index, macho_file: *MachO) void { |
| 163 | for (objects) |index| { | 180 | for (objects) |index| { |
| 164 | for (macho_file.getFile(index).?.getAtoms()) |atom_index| { | 181 | const file = macho_file.getFile(index).?; |
| 165 | const atom = macho_file.getAtom(atom_index).?; | 182 | for (file.getAtoms()) |atom_index| { |
| 183 | const atom = file.getAtom(atom_index) orelse continue; | ||
| 166 | if (atom.flags.alive and !atom.flags.visited) { | 184 | if (atom.flags.alive and !atom.flags.visited) { |
| 167 | atom.flags.alive = false; | 185 | atom.flags.alive = false; |
| 168 | atom.markUnwindRecordsDead(macho_file); | 186 | atom.markUnwindRecordsDead(macho_file); |
src/link/MachO/dyld_info/Rebase.zig+113-15| ... | @@ -1,14 +1,3 @@ | ... | @@ -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 | entries: std.ArrayListUnmanaged(Entry) = .{}, | 1 | entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 13 | buffer: std.ArrayListUnmanaged(u8) = .{}, | 2 | buffer: std.ArrayListUnmanaged(u8) = .{}, |
| 14 | 3 | ||
| ... | @@ -30,11 +19,107 @@ pub fn deinit(rebase: *Rebase, gpa: Allocator) void { | ... | @@ -30,11 +19,107 @@ pub fn deinit(rebase: *Rebase, gpa: Allocator) void { |
| 30 | rebase.buffer.deinit(gpa); | 19 | rebase.buffer.deinit(gpa); |
| 31 | } | 20 | } |
| 32 | 21 | ||
| 33 | pub fn size(rebase: Rebase) u64 { | 22 | pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void { |
| 34 | return @as(u64, @intCast(rebase.buffer.items.len)); | 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 | if (rebase.entries.items.len == 0) return; | 123 | if (rebase.entries.items.len == 0) return; |
| 39 | 124 | ||
| 40 | const writer = rebase.buffer.writer(gpa); | 125 | const writer = rebase.buffer.writer(gpa); |
| ... | @@ -198,7 +283,6 @@ fn done(writer: anytype) !void { | ... | @@ -198,7 +283,6 @@ fn done(writer: anytype) !void { |
| 198 | } | 283 | } |
| 199 | 284 | ||
| 200 | pub fn write(rebase: Rebase, writer: anytype) !void { | 285 | pub fn write(rebase: Rebase, writer: anytype) !void { |
| 201 | if (rebase.size() == 0) return; | ||
| 202 | try writer.writeAll(rebase.buffer.items); | 286 | try writer.writeAll(rebase.buffer.items); |
| 203 | } | 287 | } |
| 204 | 288 | ||
| ... | @@ -574,3 +658,17 @@ test "rebase - composite" { | ... | @@ -574,3 +658,17 @@ test "rebase - composite" { |
| 574 | macho.REBASE_OPCODE_DONE, | 658 | macho.REBASE_OPCODE_DONE, |
| 575 | }, rebase.buffer.items); | 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,463 +28,310 @@ |
| 28 | //! After the optional exported symbol information is a byte of how many edges (0-255) that | 28 | //! After the optional exported symbol information is a byte of how many edges (0-255) that |
| 29 | //! this node has leaving it, followed by each edge. Each edge is a zero terminated UTF8 of | 29 | //! this node has leaving it, followed by each edge. Each edge is a zero terminated UTF8 of |
| 30 | //! the addition chars in the symbol, followed by a uleb128 offset for the node that edge points to. | 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, .{ | 32 | /// The root node of the trie. |
| 120 | .from = self, | 33 | root: ?Node.Index = null, |
| 121 | .to = node, | 34 | buffer: std.ArrayListUnmanaged(u8) = .{}, |
| 122 | .label = try allocator.dupe(u8, label), | 35 | nodes: std.MultiArrayList(Node) = .{}, |
| 123 | }); | 36 | edges: std.ArrayListUnmanaged(Edge) = .{}, |
| 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 | } | ||
| 188 | 37 | ||
| 189 | return nread; | 38 | /// Insert a symbol into the trie, updating the prefixes in the process. |
| 190 | } | 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. | 52 | /// Inserts a new node starting at `node_index`. |
| 193 | /// The children of this node *are* not written to the byte stream | 53 | fn putNode(self: *Trie, node_index: Node.Index, allocator: Allocator, label: []const u8) !Node.Index { |
| 194 | /// recursively. To write all nodes to a byte stream in sequence, | 54 | // Check for match with edges from this node. |
| 195 | /// iterate over `Trie.ordered_nodes` and call this method on each node. | 55 | for (self.nodes.items(.edges)[node_index].items) |edge_index| { |
| 196 | /// This is one of the requirements of the MachO. | 56 | const edge = &self.edges.items[edge_index]; |
| 197 | /// Panics if `finalize` was not called before calling this method. | 57 | const match = mem.indexOfDiff(u8, edge.label, label) orelse return edge.node; |
| 198 | fn write(self: Node, writer: anytype) !void { | 58 | if (match == 0) continue; |
| 199 | assert(!self.node_dirty); | 59 | if (match == edge.label.len) return self.putNode(edge.node, allocator, label[match..]); |
| 200 | if (self.terminal_info) |info| { | 60 | |
| 201 | // Terminal node info: encode export flags and vmaddr offset of this symbol. | 61 | // Found a match, need to splice up nodes. |
| 202 | var info_buf: [@sizeOf(u64) * 2]u8 = undefined; | 62 | // From: A -> B |
| 203 | var info_stream = std.io.fixedBufferStream(&info_buf); | 63 | // To: A -> C -> B |
| 204 | // TODO Implement for special flags. | 64 | const mid_index = try self.addNode(allocator); |
| 205 | assert(info.export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and | 65 | const to_label = edge.label[match..]; |
| 206 | info.export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0); | 66 | const to_node = edge.node; |
| 207 | try leb.writeUleb128(info_stream.writer(), info.export_flags); | 67 | edge.node = mid_index; |
| 208 | try leb.writeUleb128(info_stream.writer(), info.vmaddr_offset); | 68 | edge.label = label[0..match]; |
| 209 | 69 | ||
| 210 | // Encode the size of the terminal node info. | 70 | const new_edge_index = try self.addEdge(allocator); |
| 211 | var size_buf: [@sizeOf(u64)]u8 = undefined; | 71 | const new_edge = &self.edges.items[new_edge_index]; |
| 212 | var size_stream = std.io.fixedBufferStream(&size_buf); | 72 | new_edge.node = to_node; |
| 213 | try leb.writeUleb128(size_stream.writer(), info_stream.pos); | 73 | new_edge.label = to_label; |
| 214 | 74 | try self.nodes.items(.edges)[mid_index].append(allocator, new_edge_index); | |
| 215 | // Now, write them to the output stream. | 75 | |
| 216 | try writer.writeAll(size_buf[0..size_stream.pos]); | 76 | return if (match == label.len) mid_index else self.putNode(mid_index, allocator, label[match..]); |
| 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 | } | ||
| 231 | } | 77 | } |
| 232 | 78 | ||
| 233 | const FinalizeResult = struct { | 79 | // Add a new node. |
| 234 | /// Current size of this node in bytes. | 80 | const new_node_index = try self.addNode(allocator); |
| 235 | node_size: u64, | 81 | const new_edge_index = try self.addEdge(allocator); |
| 236 | 82 | const new_edge = &self.edges.items[new_edge_index]; | |
| 237 | /// True if the trie offset of this node in the output byte stream | 83 | new_edge.node = new_node_index; |
| 238 | /// would need updating; false otherwise. | 84 | new_edge.label = label; |
| 239 | updated: bool, | 85 | try self.nodes.items(.edges)[node_index].append(allocator, new_edge_index); |
| 240 | }; | ||
| 241 | 86 | ||
| 242 | /// Updates offset of this node in the output byte stream. | 87 | return new_node_index; |
| 243 | fn finalize(self: *Node, offset_in_trie: u64) !FinalizeResult { | 88 | } |
| 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 | ||
| 256 | 89 | ||
| 257 | for (self.edges.items) |edge| { | 90 | pub fn updateSize(self: *Trie, macho_file: *MachO) !void { |
| 258 | const next_node_offset = edge.to.trie_offset orelse 0; | 91 | const tracy = trace(@src()); |
| 259 | node_size += edge.label.len + 1; | 92 | defer tracy.end(); |
| 260 | try leb.writeUleb128(writer, next_node_offset); | 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 | 117 | try self.put(gpa, .{ | |
| 263 | const trie_offset = self.trie_offset orelse 0; | 118 | .name = sym.getName(macho_file), |
| 264 | const updated = offset_in_trie != trie_offset; | 119 | .vmaddr_offset = sym.getAddress(.{ .stubs = false }, macho_file) - seg.vmaddr, |
| 265 | self.trie_offset = offset_in_trie; | 120 | .export_flags = flags, |
| 266 | self.node_dirty = false; | 121 | }); |
| 267 | node_size += stream.bytes_written; | ||
| 268 | |||
| 269 | return FinalizeResult{ .node_size = node_size, .updated = updated }; | ||
| 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, | 124 | try self.finalize(gpa); |
| 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) = .{}, | ||
| 282 | 125 | ||
| 283 | /// The size of the trie in bytes. | 126 | macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); |
| 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; | ||
| 318 | } | 127 | } |
| 319 | 128 | ||
| 320 | /// Finalizes this trie for writing to a byte stream. | 129 | /// Finalizes this trie for writing to a byte stream. |
| 321 | /// This step performs multiple passes through the trie ensuring | 130 | /// This step performs multiple passes through the trie ensuring |
| 322 | /// there are no gaps after every `Node` is ULEB128 encoded. | 131 | /// there are no gaps after every `Node` is ULEB128 encoded. |
| 323 | /// Call this method before trying to `write` the trie to a byte stream. | 132 | /// Call this method before trying to `write` the trie to a byte stream. |
| 324 | pub fn finalize(self: *Trie, allocator: Allocator) !void { | 133 | fn finalize(self: *Trie, allocator: Allocator) !void { |
| 325 | if (!self.trie_dirty) return; | 134 | const tracy = trace(@src()); |
| 135 | defer tracy.end(); | ||
| 326 | 136 | ||
| 327 | self.ordered_nodes.shrinkRetainingCapacity(0); | 137 | var ordered_nodes = std.ArrayList(Node.Index).init(allocator); |
| 328 | try self.ordered_nodes.ensureTotalCapacity(allocator, self.node_count); | 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 | defer fifo.deinit(); | 142 | defer fifo.deinit(); |
| 332 | 143 | ||
| 333 | try fifo.writeItem(self.root.?); | 144 | try fifo.writeItem(self.root.?); |
| 334 | 145 | ||
| 335 | while (fifo.readItem()) |next| { | 146 | while (fifo.readItem()) |next_index| { |
| 336 | for (next.edges.items) |*edge| { | 147 | const edges = &self.nodes.items(.edges)[next_index]; |
| 337 | try fifo.writeItem(edge.to); | 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 | var more: bool = true; | 155 | var more: bool = true; |
| 156 | var size: u32 = 0; | ||
| 343 | while (more) { | 157 | while (more) { |
| 344 | self.size = 0; | 158 | size = 0; |
| 345 | more = false; | 159 | more = false; |
| 346 | for (self.ordered_nodes.items) |node| { | 160 | for (ordered_nodes.items) |node_index| { |
| 347 | const res = try node.finalize(self.size); | 161 | const res = try self.finalizeNode(node_index, size); |
| 348 | self.size += res.node_size; | 162 | size += res.node_size; |
| 349 | if (res.updated) more = true; | 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{ | 173 | const FinalizeNodeResult = struct { |
| 357 | OutOfMemory, | 174 | /// Current size of this node in bytes. |
| 358 | EndOfStream, | 175 | node_size: u32, |
| 359 | Overflow, | 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. | 182 | /// Updates offset of this node in the output byte stream. |
| 363 | pub fn read(self: *Trie, allocator: Allocator, reader: anytype) ReadError!usize { | 183 | fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult { |
| 364 | return self.root.?.read(allocator, reader); | 184 | var stream = std.io.countingWriter(std.io.null_writer); |
| 365 | } | 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. | 200 | for (slice.items(.edges)[node_index].items) |edge_index| { |
| 368 | /// Panics if the trie was not finalized using `finalize` before calling this method. | 201 | const edge = &self.edges.items[edge_index]; |
| 369 | pub fn write(self: Trie, writer: anytype) !void { | 202 | const next_node_offset = slice.items(.trie_offset)[edge.node]; |
| 370 | assert(!self.trie_dirty); | 203 | node_size += @intCast(edge.label.len + 1); |
| 371 | for (self.ordered_nodes.items) |node| { | 204 | try leb.writeULEB128(writer, next_node_offset); |
| 372 | try node.write(writer); | ||
| 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 | assert(self.root == null); | 216 | assert(self.root == null); |
| 378 | const root = try allocator.create(Node); | 217 | self.root = try self.addNode(allocator); |
| 379 | root.* = .{ .base = self }; | ||
| 380 | self.root = root; | ||
| 381 | self.node_count += 1; | ||
| 382 | } | 218 | } |
| 383 | 219 | ||
| 384 | pub fn deinit(self: *Trie, allocator: Allocator) void { | 220 | pub fn deinit(self: *Trie, allocator: Allocator) void { |
| 385 | if (self.root) |root| { | 221 | for (self.nodes.items(.edges)) |*edges| { |
| 386 | root.deinit(allocator); | 222 | edges.deinit(allocator); |
| 387 | allocator.destroy(root); | ||
| 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" { | 229 | pub fn write(self: Trie, writer: anytype) !void { |
| 393 | const gpa = testing.allocator; | 230 | if (self.buffer.items.len == 0) return; |
| 394 | var trie: Trie = .{}; | 231 | try writer.writeAll(self.buffer.items); |
| 395 | defer trie.deinit(gpa); | 232 | } |
| 396 | try trie.init(gpa); | ||
| 397 | 233 | ||
| 398 | try testing.expectEqual(@as(usize, 1), trie.node_count); | 234 | /// Writes this node to a byte stream. |
| 399 | try testing.expect(trie.root != null); | 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, .{ | 281 | fn addNode(self: *Trie, allocator: Allocator) !Node.Index { |
| 402 | .name = "_main", | 282 | const index: Node.Index = @intCast(try self.nodes.addOne(allocator)); |
| 403 | .vmaddr_offset = 0, | 283 | self.nodes.set(index, .{}); |
| 404 | .export_flags = 0, | 284 | return index; |
| 405 | }); | 285 | } |
| 406 | try testing.expectEqual(@as(usize, 2), trie.node_count); | ||
| 407 | 286 | ||
| 408 | // Inserting the same node shouldn't update the trie. | 287 | fn addEdge(self: *Trie, allocator: Allocator) !Edge.Index { |
| 409 | try trie.put(gpa, .{ | 288 | const index: Edge.Index = @intCast(self.edges.items.len); |
| 410 | .name = "_main", | 289 | const edge = try self.edges.addOne(allocator); |
| 411 | .vmaddr_offset = 0, | 290 | edge.* = .{}; |
| 412 | .export_flags = 0, | 291 | return index; |
| 413 | }); | 292 | } |
| 414 | try testing.expectEqual(@as(usize, 2), trie.node_count); | ||
| 415 | 293 | ||
| 416 | try trie.put(gpa, .{ | 294 | /// Export symbol that is to be placed in the trie. |
| 417 | .name = "__mh_execute_header", | 295 | pub const ExportSymbol = struct { |
| 418 | .vmaddr_offset = 0x1000, | 296 | /// Name of the symbol. |
| 419 | .export_flags = 0, | 297 | name: []const u8, |
| 420 | }); | ||
| 421 | try testing.expectEqual(@as(usize, 4), trie.node_count); | ||
| 422 | 298 | ||
| 423 | // Inserting the same node shouldn't update the trie. | 299 | /// Offset of this symbol's virtual memory address from the beginning |
| 424 | try trie.put(gpa, .{ | 300 | /// of the __TEXT segment. |
| 425 | .name = "__mh_execute_header", | 301 | vmaddr_offset: u64, |
| 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 | } | ||
| 437 | 302 | ||
| 438 | test "Trie basic" { | 303 | /// Export flags of this exported symbol. |
| 439 | const gpa = testing.allocator; | 304 | export_flags: u64, |
| 440 | var trie: Trie = .{}; | 305 | }; |
| 441 | defer trie.deinit(gpa); | ||
| 442 | try trie.init(gpa); | ||
| 443 | 306 | ||
| 444 | // root --- _st ---> node | 307 | const Node = struct { |
| 445 | try trie.put(gpa, .{ | 308 | is_terminal: bool = false, |
| 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); | ||
| 461 | 309 | ||
| 462 | const nextEdge = &trie.root.?.edges.items[0]; | 310 | /// Export flags associated with this exported symbol. |
| 463 | try testing.expect(mem.eql(u8, nextEdge.label, "_st")); | 311 | export_flags: u64 = 0, |
| 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); | ||
| 477 | 312 | ||
| 478 | const nextEdge = &trie.root.?.edges.items[0]; | 313 | /// VM address offset wrt to the section this symbol is defined against. |
| 479 | try testing.expect(mem.eql(u8, nextEdge.label, "_")); | 314 | vmaddr_offset: u64 = 0, |
| 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")); | ||
| 483 | 315 | ||
| 484 | const nextNextEdge = &nextEdge.to.edges.items[0]; | 316 | /// Offset of this node in the trie output byte stream. |
| 485 | try testing.expect(mem.eql(u8, nextNextEdge.to.edges.items[0].label, "art")); | 317 | trie_offset: u32 = 0, |
| 486 | } | 318 | |
| 487 | } | 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 | fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void { | 336 | fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void { |
| 490 | assert(expected.len > 0); | 337 | assert(expected.len > 0); |
| ... | @@ -502,7 +349,7 @@ fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void { | ... | @@ -502,7 +349,7 @@ fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void { |
| 502 | } | 349 | } |
| 503 | 350 | ||
| 504 | test "write Trie to a byte stream" { | 351 | test "write Trie to a byte stream" { |
| 505 | var gpa = testing.allocator; | 352 | const gpa = testing.allocator; |
| 506 | var trie: Trie = .{}; | 353 | var trie: Trie = .{}; |
| 507 | defer trie.deinit(gpa); | 354 | defer trie.deinit(gpa); |
| 508 | try trie.init(gpa); | 355 | try trie.init(gpa); |
| ... | @@ -519,7 +366,6 @@ test "write Trie to a byte stream" { | ... | @@ -519,7 +366,6 @@ test "write Trie to a byte stream" { |
| 519 | }); | 366 | }); |
| 520 | 367 | ||
| 521 | try trie.finalize(gpa); | 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 | const exp_buffer = [_]u8{ | 370 | const exp_buffer = [_]u8{ |
| 525 | 0x0, 0x1, // node root | 371 | 0x0, 0x1, // node root |
| ... | @@ -531,51 +377,7 @@ test "write Trie to a byte stream" { | ... | @@ -531,51 +377,7 @@ test "write Trie to a byte stream" { |
| 531 | 0x2, 0x0, 0x0, 0x0, // terminal node | 377 | 0x2, 0x0, 0x0, 0x0, // terminal node |
| 532 | 0x3, 0x0, 0x80, 0x20, 0x0, // terminal node | 378 | 0x3, 0x0, 0x80, 0x20, 0x0, // terminal node |
| 533 | }; | 379 | }; |
| 534 | 380 | try expectEqualHexStrings(&exp_buffer, trie.buffer.items); | |
| 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); | ||
| 579 | } | 381 | } |
| 580 | 382 | ||
| 581 | test "ordering bug" { | 383 | test "ordering bug" { |
| ... | @@ -602,11 +404,18 @@ test "ordering bug" { | ... | @@ -602,11 +404,18 @@ test "ordering bug" { |
| 602 | 0x88, 0x80, 0x02, 0x01, 0x73, 0x53, 0x74, 0x72, | 404 | 0x88, 0x80, 0x02, 0x01, 0x73, 0x53, 0x74, 0x72, |
| 603 | 0x00, 0x12, 0x03, 0x00, 0xD8, 0x0A, 0x00, | 405 | 0x00, 0x12, 0x03, 0x00, 0xD8, 0x0A, 0x00, |
| 604 | }; | 406 | }; |
| 605 | 407 | try expectEqualHexStrings(&exp_buffer, trie.buffer.items); | |
| 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); | ||
| 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,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 | pub const Entry = struct { | 1 | pub const Entry = struct { |
| 13 | target: Symbol.Index, | 2 | target: MachO.Ref, |
| 14 | offset: u64, | 3 | offset: u64, |
| 15 | segment_id: u8, | 4 | segment_id: u8, |
| 16 | addend: i64, | 5 | addend: i64, |
| 17 | 6 | ||
| 18 | pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool { | 7 | pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool { |
| 8 | _ = ctx; | ||
| 19 | if (entry.segment_id == other.segment_id) { | 9 | if (entry.segment_id == other.segment_id) { |
| 20 | if (entry.target == other.target) { | 10 | if (entry.target.eql(other.target)) { |
| 21 | return entry.offset < other.offset; | 11 | return entry.offset < other.offset; |
| 22 | } | 12 | } |
| 23 | const entry_name = ctx.getSymbol(entry.target).getName(ctx); | 13 | if (entry.target.file == other.target.file) { |
| 24 | const other_name = ctx.getSymbol(other.target).getName(ctx); | 14 | return entry.target.index < other.target.index; |
| 25 | return std.mem.lessThan(u8, entry_name, other_name); | 15 | } |
| 16 | return entry.target.file < other.target.file; | ||
| 26 | } | 17 | } |
| 27 | return entry.segment_id < other.segment_id; | 18 | return entry.segment_id < other.segment_id; |
| 28 | } | 19 | } |
| ... | @@ -39,11 +30,109 @@ pub const Bind = struct { | ... | @@ -39,11 +30,109 @@ pub const Bind = struct { |
| 39 | self.buffer.deinit(gpa); | 30 | self.buffer.deinit(gpa); |
| 40 | } | 31 | } |
| 41 | 32 | ||
| 42 | pub fn size(self: Self) u64 { | 33 | pub fn updateSize(self: *Self, macho_file: *MachO) !void { |
| 43 | return @intCast(self.buffer.items.len); | 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 | if (self.entries.items.len == 0) return; | 136 | if (self.entries.items.len == 0) return; |
| 48 | 137 | ||
| 49 | const writer = self.buffer.writer(gpa); | 138 | const writer = self.buffer.writer(gpa); |
| ... | @@ -75,7 +164,7 @@ pub const Bind = struct { | ... | @@ -75,7 +164,7 @@ pub const Bind = struct { |
| 75 | var addend: i64 = 0; | 164 | var addend: i64 = 0; |
| 76 | var count: usize = 0; | 165 | var count: usize = 0; |
| 77 | var skip: u64 = 0; | 166 | var skip: u64 = 0; |
| 78 | var target: ?Symbol.Index = null; | 167 | var target: ?MachO.Ref = null; |
| 79 | 168 | ||
| 80 | var state: enum { | 169 | var state: enum { |
| 81 | start, | 170 | start, |
| ... | @@ -86,7 +175,7 @@ pub const Bind = struct { | ... | @@ -86,7 +175,7 @@ pub const Bind = struct { |
| 86 | var i: usize = 0; | 175 | var i: usize = 0; |
| 87 | while (i < entries.len) : (i += 1) { | 176 | while (i < entries.len) : (i += 1) { |
| 88 | const current = entries[i]; | 177 | const current = entries[i]; |
| 89 | if (target == null or target.? != current.target) { | 178 | if (target == null or !target.?.eql(current.target)) { |
| 90 | switch (state) { | 179 | switch (state) { |
| 91 | .start => {}, | 180 | .start => {}, |
| 92 | .bind_single => try doBind(writer), | 181 | .bind_single => try doBind(writer), |
| ... | @@ -95,7 +184,7 @@ pub const Bind = struct { | ... | @@ -95,7 +184,7 @@ pub const Bind = struct { |
| 95 | state = .start; | 184 | state = .start; |
| 96 | target = current.target; | 185 | target = current.target; |
| 97 | 186 | ||
| 98 | const sym = ctx.getSymbol(current.target); | 187 | const sym = current.target.getSymbol(ctx).?; |
| 99 | const name = sym.getName(ctx); | 188 | const name = sym.getName(ctx); |
| 100 | const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; | 189 | const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; |
| 101 | const ordinal: i16 = ord: { | 190 | const ordinal: i16 = ord: { |
| ... | @@ -178,7 +267,6 @@ pub const Bind = struct { | ... | @@ -178,7 +267,6 @@ pub const Bind = struct { |
| 178 | } | 267 | } |
| 179 | 268 | ||
| 180 | pub fn write(self: Self, writer: anytype) !void { | 269 | pub fn write(self: Self, writer: anytype) !void { |
| 181 | if (self.size() == 0) return; | ||
| 182 | try writer.writeAll(self.buffer.items); | 270 | try writer.writeAll(self.buffer.items); |
| 183 | } | 271 | } |
| 184 | }; | 272 | }; |
| ... | @@ -194,11 +282,110 @@ pub const WeakBind = struct { | ... | @@ -194,11 +282,110 @@ pub const WeakBind = struct { |
| 194 | self.buffer.deinit(gpa); | 282 | self.buffer.deinit(gpa); |
| 195 | } | 283 | } |
| 196 | 284 | ||
| 197 | pub fn size(self: Self) u64 { | 285 | pub fn updateSize(self: *Self, macho_file: *MachO) !void { |
| 198 | return @intCast(self.buffer.items.len); | 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 | if (self.entries.items.len == 0) return; | 389 | if (self.entries.items.len == 0) return; |
| 203 | 390 | ||
| 204 | const writer = self.buffer.writer(gpa); | 391 | const writer = self.buffer.writer(gpa); |
| ... | @@ -230,7 +417,7 @@ pub const WeakBind = struct { | ... | @@ -230,7 +417,7 @@ pub const WeakBind = struct { |
| 230 | var addend: i64 = 0; | 417 | var addend: i64 = 0; |
| 231 | var count: usize = 0; | 418 | var count: usize = 0; |
| 232 | var skip: u64 = 0; | 419 | var skip: u64 = 0; |
| 233 | var target: ?Symbol.Index = null; | 420 | var target: ?MachO.Ref = null; |
| 234 | 421 | ||
| 235 | var state: enum { | 422 | var state: enum { |
| 236 | start, | 423 | start, |
| ... | @@ -241,7 +428,7 @@ pub const WeakBind = struct { | ... | @@ -241,7 +428,7 @@ pub const WeakBind = struct { |
| 241 | var i: usize = 0; | 428 | var i: usize = 0; |
| 242 | while (i < entries.len) : (i += 1) { | 429 | while (i < entries.len) : (i += 1) { |
| 243 | const current = entries[i]; | 430 | const current = entries[i]; |
| 244 | if (target == null or target.? != current.target) { | 431 | if (target == null or !target.?.eql(current.target)) { |
| 245 | switch (state) { | 432 | switch (state) { |
| 246 | .start => {}, | 433 | .start => {}, |
| 247 | .bind_single => try doBind(writer), | 434 | .bind_single => try doBind(writer), |
| ... | @@ -250,7 +437,7 @@ pub const WeakBind = struct { | ... | @@ -250,7 +437,7 @@ pub const WeakBind = struct { |
| 250 | state = .start; | 437 | state = .start; |
| 251 | target = current.target; | 438 | target = current.target; |
| 252 | 439 | ||
| 253 | const sym = ctx.getSymbol(current.target); | 440 | const sym = current.target.getSymbol(ctx).?; |
| 254 | const name = sym.getName(ctx); | 441 | const name = sym.getName(ctx); |
| 255 | const flags: u8 = 0; // TODO NON_WEAK_DEFINITION | 442 | const flags: u8 = 0; // TODO NON_WEAK_DEFINITION |
| 256 | 443 | ||
| ... | @@ -322,7 +509,6 @@ pub const WeakBind = struct { | ... | @@ -322,7 +509,6 @@ pub const WeakBind = struct { |
| 322 | } | 509 | } |
| 323 | 510 | ||
| 324 | pub fn write(self: Self, writer: anytype) !void { | 511 | pub fn write(self: Self, writer: anytype) !void { |
| 325 | if (self.size() == 0) return; | ||
| 326 | try writer.writeAll(self.buffer.items); | 512 | try writer.writeAll(self.buffer.items); |
| 327 | } | 513 | } |
| 328 | }; | 514 | }; |
| ... | @@ -340,11 +526,36 @@ pub const LazyBind = struct { | ... | @@ -340,11 +526,36 @@ pub const LazyBind = struct { |
| 340 | self.offsets.deinit(gpa); | 526 | self.offsets.deinit(gpa); |
| 341 | } | 527 | } |
| 342 | 528 | ||
| 343 | pub fn size(self: Self) u64 { | 529 | pub fn updateSize(self: *Self, macho_file: *MachO) !void { |
| 344 | return @intCast(self.buffer.items.len); | 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 | try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len); | 559 | try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len); |
| 349 | 560 | ||
| 350 | const writer = self.buffer.writer(gpa); | 561 | const writer = self.buffer.writer(gpa); |
| ... | @@ -356,7 +567,7 @@ pub const LazyBind = struct { | ... | @@ -356,7 +567,7 @@ pub const LazyBind = struct { |
| 356 | for (self.entries.items) |entry| { | 567 | for (self.entries.items) |entry| { |
| 357 | self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len)); | 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 | const name = sym.getName(ctx); | 571 | const name = sym.getName(ctx); |
| 361 | const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; | 572 | const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; |
| 362 | const ordinal: i16 = ord: { | 573 | const ordinal: i16 = ord: { |
| ... | @@ -474,3 +685,17 @@ fn done(writer: anytype) !void { | ... | @@ -474,3 +685,17 @@ fn done(writer: anytype) !void { |
| 474 | log.debug(">>> done", .{}); | 685 | log.debug(">>> done", .{}); |
| 475 | try writer.writeByte(macho.BIND_OPCODE_DONE); | 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,7 +68,8 @@ pub const Cie = struct { |
| 68 | 68 | ||
| 69 | pub fn getPersonality(cie: Cie, macho_file: *MachO) ?*Symbol { | 69 | pub fn getPersonality(cie: Cie, macho_file: *MachO) ?*Symbol { |
| 70 | const personality = cie.personality orelse return null; | 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 | pub fn eql(cie: Cie, other: Cie, macho_file: *MachO) bool { | 75 | pub fn eql(cie: Cie, other: Cie, macho_file: *MachO) bool { |
| ... | @@ -223,11 +224,11 @@ pub const Fde = struct { | ... | @@ -223,11 +224,11 @@ pub const Fde = struct { |
| 223 | } | 224 | } |
| 224 | 225 | ||
| 225 | pub fn getAtom(fde: Fde, macho_file: *MachO) *Atom { | 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 | pub fn getLsdaAtom(fde: Fde, macho_file: *MachO) ?*Atom { | 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 | pub fn format( | 234 | pub fn format( |
| ... | @@ -448,7 +449,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { | ... | @@ -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 | const tracy = trace(@src()); | 453 | const tracy = trace(@src()); |
| 453 | defer tracy.end(); | 454 | defer tracy.end(); |
| 454 | 455 | ||
| ... | @@ -459,6 +460,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. | ... | @@ -459,6 +460,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 459 | else => 0, | 460 | else => 0, |
| 460 | }; | 461 | }; |
| 461 | 462 | ||
| 463 | var i: usize = 0; | ||
| 462 | for (macho_file.objects.items) |index| { | 464 | for (macho_file.objects.items) |index| { |
| 463 | const object = macho_file.getFile(index).?.object; | 465 | const object = macho_file.getFile(index).?.object; |
| 464 | for (object.cies.items) |cie| { | 466 | for (object.cies.items) |cie| { |
| ... | @@ -469,7 +471,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. | ... | @@ -469,7 +471,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 469 | if (cie.getPersonality(macho_file)) |sym| { | 471 | if (cie.getPersonality(macho_file)) |sym| { |
| 470 | const r_address = math.cast(i32, cie.out_offset + cie.personality.?.offset) orelse return error.Overflow; | 472 | const r_address = math.cast(i32, cie.out_offset + cie.personality.?.offset) orelse return error.Overflow; |
| 471 | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; | 473 | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; |
| 472 | relocs.appendAssumeCapacity(.{ | 474 | relocs[i] = .{ |
| 473 | .r_address = r_address, | 475 | .r_address = r_address, |
| 474 | .r_symbolnum = r_symbolnum, | 476 | .r_symbolnum = r_symbolnum, |
| 475 | .r_length = 2, | 477 | .r_length = 2, |
| ... | @@ -480,7 +482,8 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. | ... | @@ -480,7 +482,8 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: *std.ArrayList(macho. |
| 480 | .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_GOT), | 482 | .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_GOT), |
| 481 | else => unreachable, | 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,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 | pub const EH_PE = struct { | 541 | pub const EH_PE = struct { |
src/link/MachO/file.zig+224-97| ... | @@ -24,41 +24,194 @@ pub const File = union(enum) { | ... | @@ -24,41 +24,194 @@ pub const File = union(enum) { |
| 24 | _ = options; | 24 | _ = options; |
| 25 | switch (file) { | 25 | switch (file) { |
| 26 | .zig_object => |x| try writer.writeAll(x.path), | 26 | .zig_object => |x| try writer.writeAll(x.path), |
| 27 | .internal => try writer.writeAll(""), | 27 | .internal => try writer.writeAll("internal"), |
| 28 | .object => |x| try writer.print("{}", .{x.fmtPath()}), | 28 | .object => |x| try writer.print("{}", .{x.fmtPath()}), |
| 29 | .dylib => |x| try writer.writeAll(x.path), | 29 | .dylib => |x| try writer.writeAll(x.path), |
| 30 | } | 30 | } |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | pub fn resolveSymbols(file: File, macho_file: *MachO) void { | 33 | pub fn resolveSymbols(file: File, macho_file: *MachO) !void { |
| 34 | switch (file) { | 34 | return switch (file) { |
| 35 | .internal => unreachable, | ||
| 36 | inline else => |x| x.resolveSymbols(macho_file), | 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 | switch (file) { | 40 | switch (file) { |
| 42 | .internal => unreachable, | 41 | .dylib => unreachable, |
| 43 | inline else => |x| x.resetGlobals(macho_file), | 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 | assert(file == .object or file == .zig_object); | 162 | assert(file == .object or file == .zig_object); |
| 49 | 163 | ||
| 50 | for (file.getSymbols(), 0..) |sym_index, i| { | 164 | for (file.getSymbols(), 0..) |*sym, i| { |
| 51 | const nlist_idx = @as(Symbol.Index, @intCast(i)); | 165 | const ref = file.getSymbolRef(@intCast(i), macho_file); |
| 52 | const nlist = switch (file) { | 166 | const other_file = ref.getFile(macho_file) orelse continue; |
| 53 | .object => |x| x.symtab.items(.nlist)[nlist_idx], | 167 | if (other_file.getIndex() != file.getIndex()) continue; |
| 54 | .zig_object => |x| x.symtab.items(.nlist)[nlist_idx], | 168 | if (sym.visibility != .global) continue; |
| 55 | else => unreachable, | 169 | sym.flags.@"export" = true; |
| 56 | }; | 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 | if (!nlist.ext()) continue; | 211 | if (!nlist.ext()) continue; |
| 58 | if (!nlist.undf()) continue; | 212 | if (!nlist.undf()) continue; |
| 59 | 213 | ||
| 60 | const sym = macho_file.getSymbol(sym_index); | 214 | if (file.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue; |
| 61 | if (sym.getFile(macho_file) != null) continue; | ||
| 62 | 215 | ||
| 63 | const is_import = switch (macho_file.undefined_treatment) { | 216 | const is_import = switch (macho_file.undefined_treatment) { |
| 64 | .@"error" => false, | 217 | .@"error" => false, |
| ... | @@ -67,111 +220,95 @@ pub const File = union(enum) { | ... | @@ -67,111 +220,95 @@ pub const File = union(enum) { |
| 67 | }; | 220 | }; |
| 68 | if (is_import) { | 221 | if (is_import) { |
| 69 | sym.value = 0; | 222 | sym.value = 0; |
| 70 | sym.atom = 0; | 223 | sym.atom_ref = .{ .index = 0, .file = 0 }; |
| 71 | sym.nlist_idx = 0; | ||
| 72 | sym.file = macho_file.internal_object.?; | ||
| 73 | sym.flags.weak = false; | 224 | sym.flags.weak = false; |
| 74 | sym.flags.weak_ref = nlist.weakRef(); | 225 | sym.flags.weak_ref = nlist.weakRef(); |
| 75 | sym.flags.import = is_import; | 226 | sym.flags.import = is_import; |
| 76 | sym.visibility = .global; | 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 | pub fn claimUnresolvedRelocatable(file: File, macho_file: *MachO) void { | 235 | pub fn claimUnresolvedRelocatable(file: File, macho_file: *MachO) void { |
| 236 | const tracy = trace(@src()); | ||
| 237 | defer tracy.end(); | ||
| 238 | |||
| 83 | assert(file == .object or file == .zig_object); | 239 | assert(file == .object or file == .zig_object); |
| 84 | 240 | ||
| 85 | for (file.getSymbols(), 0..) |sym_index, i| { | 241 | for (file.getSymbols(), file.getNlists(), 0..) |*sym, nlist, 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 | }; | ||
| 92 | if (!nlist.ext()) continue; | 242 | if (!nlist.ext()) continue; |
| 93 | if (!nlist.undf()) continue; | 243 | if (!nlist.undf()) continue; |
| 94 | 244 | if (file.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue; | |
| 95 | const sym = macho_file.getSymbol(sym_index); | ||
| 96 | if (sym.getFile(macho_file) != null) continue; | ||
| 97 | 245 | ||
| 98 | sym.value = 0; | 246 | sym.value = 0; |
| 99 | sym.atom = 0; | 247 | sym.atom_ref = .{ .index = 0, .file = 0 }; |
| 100 | sym.nlist_idx = nlist_idx; | ||
| 101 | sym.file = file.getIndex(); | ||
| 102 | sym.flags.weak_ref = nlist.weakRef(); | 248 | sym.flags.weak_ref = nlist.weakRef(); |
| 103 | sym.flags.import = true; | 249 | sym.flags.import = true; |
| 104 | sym.visibility = .global; | 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 { | 257 | pub fn checkDuplicates(file: File, macho_file: *MachO) !void { |
| 109 | assert(file == .object or file == .zig_object); | 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| { | 263 | for (file.getSymbols(), file.getNlists(), 0..) |sym, nlist, i| { |
| 112 | const sym = macho_file.getSymbol(sym_index); | ||
| 113 | const other_file = sym.getFile(macho_file) orelse continue; | ||
| 114 | if (sym.visibility != .global) continue; | 264 | if (sym.visibility != .global) continue; |
| 115 | if (other_file == .dylib and !sym.flags.abs) { | 265 | if (sym.flags.weak) continue; |
| 116 | sym.flags.import = true; | 266 | if (nlist.undf()) continue; |
| 117 | continue; | 267 | const ref = file.getSymbolRef(@intCast(i), macho_file); |
| 118 | } | 268 | const ref_file = ref.getFile(macho_file) orelse continue; |
| 119 | if (other_file.getIndex() == file.getIndex()) { | 269 | if (ref_file.getIndex() == file.getIndex()) continue; |
| 120 | sym.flags.@"export" = true; | 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 { | 279 | pub fn initOutputSections(file: File, macho_file: *MachO) !void { |
| 126 | assert(file == .object or file == .zig_object); | 280 | const tracy = trace(@src()); |
| 127 | 281 | defer tracy.end(); | |
| 128 | for (file.getSymbols()) |sym_index| { | 282 | for (file.getAtoms()) |atom_index| { |
| 129 | const sym = macho_file.getSymbol(sym_index); | 283 | const atom = file.getAtom(atom_index) orelse continue; |
| 130 | const other_file = sym.getFile(macho_file) orelse continue; | 284 | if (!atom.flags.alive) continue; |
| 131 | if (sym.visibility != .global) continue; | 285 | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file); |
| 132 | if (other_file.getIndex() == file.getIndex()) { | ||
| 133 | sym.flags.@"export" = true; | ||
| 134 | } | ||
| 135 | } | 286 | } |
| 136 | } | 287 | } |
| 137 | 288 | ||
| 138 | /// Encodes symbol rank so that the following ordering applies: | 289 | pub fn dedupLiterals(file: File, lp: MachO.LiteralPool, macho_file: *MachO) void { |
| 139 | /// * strong in object | 290 | return switch (file) { |
| 140 | /// * weak in object | 291 | .dylib => unreachable, |
| 141 | /// * tentative in object | 292 | inline else => |x| x.dedupLiterals(lp, macho_file), |
| 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; | ||
| 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 | return switch (file) { | 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 | return switch (file) { | 304 | return switch (file) { |
| 173 | .dylib => unreachable, | 305 | inline else => |x| x.calcSymtabSize(macho_file), |
| 174 | inline else => |x| x.atoms.items, | 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,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 | pub const Index = u32; | 338 | pub const Index = u32; |
| 214 | 339 | ||
| 215 | pub const Entry = union(enum) { | 340 | pub const Entry = union(enum) { |
| ... | @@ -225,8 +350,10 @@ pub const File = union(enum) { | ... | @@ -225,8 +350,10 @@ pub const File = union(enum) { |
| 225 | }; | 350 | }; |
| 226 | 351 | ||
| 227 | const assert = std.debug.assert; | 352 | const assert = std.debug.assert; |
| 353 | const log = std.log.scoped(.link); | ||
| 228 | const macho = std.macho; | 354 | const macho = std.macho; |
| 229 | const std = @import("std"); | 355 | const std = @import("std"); |
| 356 | const trace = @import("../../tracy.zig").trace; | ||
| 230 | 357 | ||
| 231 | const Allocator = std.mem.Allocator; | 358 | const Allocator = std.mem.Allocator; |
| 232 | const Archive = @import("Archive.zig"); | 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,9 +44,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c |
| 44 | 44 | ||
| 45 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | 45 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 46 | 46 | ||
| 47 | try macho_file.addUndefinedGlobals(); | ||
| 48 | try macho_file.resolveSymbols(); | 47 | try macho_file.resolveSymbols(); |
| 49 | try macho_file.parseDebugInfo(); | ||
| 50 | try macho_file.dedupLiterals(); | 48 | try macho_file.dedupLiterals(); |
| 51 | markExports(macho_file); | 49 | markExports(macho_file); |
| 52 | claimUnresolved(macho_file); | 50 | claimUnresolved(macho_file); |
| ... | @@ -59,28 +57,13 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c | ... | @@ -59,28 +57,13 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c |
| 59 | try allocateSections(macho_file); | 57 | try allocateSections(macho_file); |
| 60 | allocateSegment(macho_file); | 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 | if (build_options.enable_logging) { | 60 | if (build_options.enable_logging) { |
| 70 | state_log.debug("{}", .{macho_file.dumpState()}); | 61 | state_log.debug("{}", .{macho_file.dumpState()}); |
| 71 | } | 62 | } |
| 72 | 63 | ||
| 73 | try macho_file.calcSymtabSize(); | 64 | try writeSections(macho_file); |
| 74 | try writeAtoms(macho_file); | 65 | sortRelocs(macho_file); |
| 75 | try writeCompactUnwind(macho_file); | 66 | try writeSectionsToFile(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); | ||
| 84 | 67 | ||
| 85 | // In order to please Apple ld (and possibly other MachO linkers in the wild), | 68 | // In order to please Apple ld (and possibly other MachO linkers in the wild), |
| 86 | // we will now sanitize segment names of Zig-specific segments. | 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,7 +112,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 129 | 112 | ||
| 130 | // First, we flush relocatable object file generated with our backends. | 113 | // First, we flush relocatable object file generated with our backends. |
| 131 | if (macho_file.getZigObject()) |zo| { | 114 | if (macho_file.getZigObject()) |zo| { |
| 132 | zo.resolveSymbols(macho_file); | 115 | try zo.resolveSymbols(macho_file); |
| 133 | zo.asFile().markExportsRelocatable(macho_file); | 116 | zo.asFile().markExportsRelocatable(macho_file); |
| 134 | zo.asFile().claimUnresolvedRelocatable(macho_file); | 117 | zo.asFile().claimUnresolvedRelocatable(macho_file); |
| 135 | try macho_file.sortSections(); | 118 | try macho_file.sortSections(); |
| ... | @@ -139,26 +122,13 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? | ... | @@ -139,26 +122,13 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 139 | try allocateSections(macho_file); | 122 | try allocateSections(macho_file); |
| 140 | allocateSegment(macho_file); | 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 | if (build_options.enable_logging) { | 125 | if (build_options.enable_logging) { |
| 150 | state_log.debug("{}", .{macho_file.dumpState()}); | 126 | state_log.debug("{}", .{macho_file.dumpState()}); |
| 151 | } | 127 | } |
| 152 | 128 | ||
| 153 | try macho_file.calcSymtabSize(); | 129 | try writeSections(macho_file); |
| 154 | try writeAtoms(macho_file); | 130 | sortRelocs(macho_file); |
| 155 | 131 | try writeSectionsToFile(macho_file); | |
| 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); | ||
| 162 | 132 | ||
| 163 | // In order to please Apple ld (and possibly other MachO linkers in the wild), | 133 | // In order to please Apple ld (and possibly other MachO linkers in the wild), |
| 164 | // we will now sanitize segment names of Zig-specific segments. | 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,7 +139,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 169 | 139 | ||
| 170 | // TODO we can avoid reading in the file contents we just wrote if we give the linker | 140 | // TODO we can avoid reading in the file contents we just wrote if we give the linker |
| 171 | // ability to write directly to a buffer. | 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 | var files = std.ArrayList(File.Index).init(gpa); | 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,12 +256,15 @@ fn parseObject(macho_file: *MachO, path: []const u8) MachO.ParseError!void { |
| 286 | break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); | 256 | break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); |
| 287 | }; | 257 | }; |
| 288 | const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa))); | 258 | const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa))); |
| 289 | macho_file.files.set(index, .{ .object = .{ | 259 | macho_file.files.set(index, .{ |
| 290 | .path = try gpa.dupe(u8, path), | 260 | .object = .{ |
| 291 | .file_handle = handle, | 261 | .offset = 0, // TODO FAT objects |
| 292 | .mtime = mtime, | 262 | .path = try gpa.dupe(u8, path), |
| 293 | .index = index, | 263 | .file_handle = handle, |
| 294 | } }); | 264 | .mtime = mtime, |
| 265 | .index = index, | ||
| 266 | }, | ||
| 267 | }); | ||
| 295 | try macho_file.objects.append(gpa, index); | 268 | try macho_file.objects.append(gpa, index); |
| 296 | 269 | ||
| 297 | const object = macho_file.getFile(index).?.object; | 270 | const object = macho_file.getFile(index).?.object; |
| ... | @@ -347,9 +320,9 @@ pub fn claimUnresolved(macho_file: *MachO) void { | ... | @@ -347,9 +320,9 @@ pub fn claimUnresolved(macho_file: *MachO) void { |
| 347 | 320 | ||
| 348 | fn initOutputSections(macho_file: *MachO) !void { | 321 | fn initOutputSections(macho_file: *MachO) !void { |
| 349 | for (macho_file.objects.items) |index| { | 322 | for (macho_file.objects.items) |index| { |
| 350 | const object = macho_file.getFile(index).?.object; | 323 | const file = macho_file.getFile(index).?; |
| 351 | for (object.atoms.items) |atom_index| { | 324 | for (file.getAtoms()) |atom_index| { |
| 352 | const atom = macho_file.getAtom(atom_index) orelse continue; | 325 | const atom = file.getAtom(atom_index) orelse continue; |
| 353 | if (!atom.flags.alive) continue; | 326 | if (!atom.flags.alive) continue; |
| 354 | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file); | 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,69 +350,147 @@ fn calcSectionSizes(macho_file: *MachO) !void { |
| 377 | const tracy = trace(@src()); | 350 | const tracy = trace(@src()); |
| 378 | defer tracy.end(); | 351 | defer tracy.end(); |
| 379 | 352 | ||
| 380 | const slice = macho_file.sections.slice(); | 353 | for (macho_file.sections.items(.atoms), 0..) |atoms, i| { |
| 381 | for (slice.items(.header), slice.items(.atoms)) |*header, atoms| { | ||
| 382 | if (atoms.items.len == 0) continue; | 354 | if (atoms.items.len == 0) continue; |
| 383 | for (atoms.items) |atom_index| { | 355 | calcSectionSize(macho_file, @intCast(i)); |
| 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 | } | ||
| 393 | } | 356 | } |
| 394 | 357 | ||
| 395 | if (macho_file.unwind_info_sect_index) |index| { | 358 | if (macho_file.getZigObject()) |zo| { |
| 396 | calcCompactUnwindSize(macho_file, index); | 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| { | 364 | if (macho_file.eh_frame_sect_index) |_| { |
| 400 | const sect = &macho_file.sections.items(.header)[index]; | 365 | try calcEhFrameSize(macho_file); |
| 401 | sect.size = try eh_frame.calcSize(macho_file); | ||
| 402 | sect.@"align" = 3; | ||
| 403 | sect.nreloc = eh_frame.calcNumRelocs(macho_file); | ||
| 404 | } | 366 | } |
| 405 | 367 | ||
| 406 | if (macho_file.getZigObject()) |zo| { | 368 | for (macho_file.objects.items) |index| { |
| 407 | for (zo.atoms.items) |atom_index| { | 369 | if (macho_file.unwind_info_sect_index) |_| { |
| 408 | const atom = macho_file.getAtom(atom_index) orelse continue; | 370 | macho_file.getFile(index).?.object.calcCompactUnwindSizeRelocatable(macho_file); |
| 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); | ||
| 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 { | 414 | fn calcCompactUnwindSize(macho_file: *MachO) void { |
| 418 | var size: u32 = 0; | 415 | const tracy = trace(@src()); |
| 416 | defer tracy.end(); | ||
| 417 | |||
| 418 | var nrec: u32 = 0; | ||
| 419 | var nreloc: u32 = 0; | 419 | var nreloc: u32 = 0; |
| 420 | 420 | ||
| 421 | for (macho_file.objects.items) |index| { | 421 | for (macho_file.objects.items) |index| { |
| 422 | const object = macho_file.getFile(index).?.object; | 422 | const ctx = &macho_file.getFile(index).?.object.compact_unwind_ctx; |
| 423 | for (object.unwind_records.items) |irec| { | 423 | ctx.rec_index = nrec; |
| 424 | const rec = macho_file.getUnwindRecord(irec); | 424 | ctx.reloc_index = nreloc; |
| 425 | if (!rec.alive) continue; | 425 | nrec += ctx.rec_count; |
| 426 | size += @sizeOf(macho.compact_unwind_entry); | 426 | nreloc += ctx.reloc_count; |
| 427 | nreloc += 1; | ||
| 428 | if (rec.getPersonality(macho_file)) |_| { | ||
| 429 | nreloc += 1; | ||
| 430 | } | ||
| 431 | if (rec.getLsdaAtom(macho_file)) |_| { | ||
| 432 | nreloc += 1; | ||
| 433 | } | ||
| 434 | } | ||
| 435 | } | 427 | } |
| 436 | 428 | ||
| 437 | const sect = &macho_file.sections.items(.header)[sect_index]; | 429 | const sect = &macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?]; |
| 438 | sect.size = size; | 430 | sect.size = nrec * @sizeOf(macho.compact_unwind_entry); |
| 439 | sect.nreloc = nreloc; | 431 | sect.nreloc = nreloc; |
| 440 | sect.@"align" = 3; | 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 | fn allocateSections(macho_file: *MachO) !void { | 494 | fn allocateSections(macho_file: *MachO) !void { |
| 444 | const slice = macho_file.sections.slice(); | 495 | const slice = macho_file.sections.slice(); |
| 445 | for (slice.items(.header)) |*header| { | 496 | for (slice.items(.header)) |*header| { |
| ... | @@ -457,6 +508,37 @@ fn allocateSections(macho_file: *MachO) !void { | ... | @@ -457,6 +508,37 @@ fn allocateSections(macho_file: *MachO) !void { |
| 457 | } | 508 | } |
| 458 | header.size = needed_size; | 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 | /// Renames segment names in Zig sections to standard MachO segment names such as | 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,232 +601,86 @@ fn allocateSegment(macho_file: *MachO) void { |
| 519 | seg.filesize = fileoff - seg.fileoff; | 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 | // We need to sort relocations in descending order to be compatible with Apple's linker. | 604 | // We need to sort relocations in descending order to be compatible with Apple's linker. |
| 534 | fn sortReloc(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation_info) bool { | 605 | fn sortReloc(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation_info) bool { |
| 535 | _ = ctx; | 606 | _ = ctx; |
| 536 | return lhs.r_address > rhs.r_address; | 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 | const tracy = trace(@src()); | 620 | const tracy = trace(@src()); |
| 541 | defer tracy.end(); | 621 | defer tracy.end(); |
| 542 | 622 | ||
| 543 | const gpa = macho_file.base.comp.gpa; | 623 | const gpa = macho_file.base.comp.gpa; |
| 544 | const cpu_arch = macho_file.getTarget().cpu.arch; | 624 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 545 | const slice = macho_file.sections.slice(); | 625 | const slice = macho_file.sections.slice(); |
| 546 | 626 | for (slice.items(.header), slice.items(.out), slice.items(.relocs), 0..) |header, *out, *relocs, n_sect| { | |
| 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; | ||
| 552 | if (header.isZerofill()) continue; | 627 | if (header.isZerofill()) continue; |
| 553 | if (macho_file.isZigSection(@intCast(i)) or macho_file.isDebugSection(@intCast(i))) continue; | 628 | if (!macho_file.isZigSection(@intCast(n_sect))) { // TODO this is wrong; what about debug sections? |
| 554 | 629 | const size = math.cast(usize, header.size) orelse return error.Overflow; | |
| 555 | const size = math.cast(usize, header.size) orelse return error.Overflow; | 630 | try out.resize(gpa, size); |
| 556 | const code = try gpa.alloc(u8, size); | 631 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; |
| 557 | defer gpa.free(code); | 632 | @memset(out.items, padding_byte); |
| 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); | ||
| 570 | } | 633 | } |
| 634 | try relocs.resize(gpa, header.nreloc); | ||
| 635 | } | ||
| 571 | 636 | ||
| 572 | assert(relocs.items.len == header.nreloc); | 637 | const cmd = macho_file.symtab_cmd; |
| 573 | 638 | try macho_file.symtab.resize(gpa, cmd.nsyms); | |
| 574 | mem.sort(macho.relocation_info, relocs.items, {}, sortReloc); | 639 | try macho_file.strtab.resize(gpa, cmd.strsize); |
| 575 | 640 | macho_file.strtab.items[0] = 0; | |
| 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); | ||
| 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 | if (macho_file.getZigObject()) |zo| { | 647 | if (macho_file.getZigObject()) |zo| { |
| 584 | // TODO: this is ugly; perhaps we should aggregrate before? | 648 | try zo.writeRelocs(macho_file); |
| 585 | var zo_relocs = std.AutoArrayHashMap(u8, std.ArrayList(macho.relocation_info)).init(gpa); | 649 | try zo.writeAtomsRelocatable(macho_file); |
| 586 | defer { | 650 | zo.writeSymtab(macho_file, macho_file); |
| 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 | } | ||
| 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 | 653 | if (macho_file.eh_frame_sect_index) |_| { |
| 696 | if (rec.getPersonality(macho_file)) |sym| { | 654 | try writeEhFrame(macho_file); |
| 697 | const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow; | 655 | } |
| 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 | } | ||
| 712 | 656 | ||
| 713 | entries.appendAssumeCapacity(out); | 657 | if (macho_file.unwind_info_sect_index) |_| { |
| 714 | offset += @sizeOf(macho.compact_unwind_entry); | 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 | fn writeEhFrame(macho_file: *MachO) !void { | 664 | fn writeEhFrame(macho_file: *MachO) !void { |
| 729 | const sect_index = macho_file.eh_frame_sect_index orelse return; | 665 | const sect_index = macho_file.eh_frame_sect_index.?; |
| 730 | const gpa = macho_file.base.comp.gpa; | 666 | const buffer = macho_file.sections.items(.out)[sect_index]; |
| 731 | const header = macho_file.sections.items(.header)[sect_index]; | 667 | const relocs = macho_file.sections.items(.relocs)[sect_index]; |
| 732 | const size = math.cast(usize, header.size) orelse return error.Overflow; | 668 | try eh_frame.writeRelocs(macho_file, buffer.items, relocs.items); |
| 733 | 669 | } | |
| 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(); | ||
| 739 | 670 | ||
| 740 | try eh_frame.writeRelocs(macho_file, code, &relocs); | 671 | fn writeSectionsToFile(macho_file: *MachO) !void { |
| 741 | assert(relocs.items.len == header.nreloc); | 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? | 681 | try macho_file.writeDataInCode(); |
| 746 | try macho_file.base.file.?.pwriteAll(code, header.offset); | 682 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff); |
| 747 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | 683 | try macho_file.base.file.?.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff); |
| 748 | } | 684 | } |
| 749 | 685 | ||
| 750 | fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { | 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,15 +18,15 @@ pub const ZigGotSection = struct { |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, macho_file: *MachO) !Index { | 20 | pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, macho_file: *MachO) !Index { |
| 21 | const comp = macho_file.base.comp; | 21 | const gpa = macho_file.base.comp.gpa; |
| 22 | const gpa = comp.gpa; | 22 | const zo = macho_file.getZigObject().?; |
| 23 | const index = try zig_got.allocateEntry(gpa); | 23 | const index = try zig_got.allocateEntry(gpa); |
| 24 | const entry = &zig_got.entries.items[index]; | 24 | const entry = &zig_got.entries.items[index]; |
| 25 | entry.* = sym_index; | 25 | entry.* = sym_index; |
| 26 | const symbol = macho_file.getSymbol(sym_index); | 26 | const symbol = &zo.symbols.items[sym_index]; |
| 27 | assert(symbol.flags.needs_zig_got); | 27 | assert(symbol.flags.needs_zig_got); |
| 28 | symbol.flags.has_zig_got = true; | 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 | return index; | 30 | return index; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| ... | @@ -53,9 +53,10 @@ pub const ZigGotSection = struct { | ... | @@ -53,9 +53,10 @@ pub const ZigGotSection = struct { |
| 53 | try macho_file.growSection(macho_file.zig_got_sect_index.?, needed_size); | 53 | try macho_file.growSection(macho_file.zig_got_sect_index.?, needed_size); |
| 54 | zig_got.dirty = false; | 54 | zig_got.dirty = false; |
| 55 | } | 55 | } |
| 56 | const zo = macho_file.getZigObject().?; | ||
| 56 | const off = zig_got.entryOffset(index, macho_file); | 57 | const off = zig_got.entryOffset(index, macho_file); |
| 57 | const entry = zig_got.entries.items[index]; | 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 | var buf: [8]u8 = undefined; | 61 | var buf: [8]u8 = undefined; |
| 61 | std.mem.writeInt(u64, &buf, value, .little); | 62 | std.mem.writeInt(u64, &buf, value, .little); |
| ... | @@ -63,29 +64,14 @@ pub const ZigGotSection = struct { | ... | @@ -63,29 +64,14 @@ pub const ZigGotSection = struct { |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | pub fn writeAll(zig_got: ZigGotSection, macho_file: *MachO, writer: anytype) !void { | 66 | pub fn writeAll(zig_got: ZigGotSection, macho_file: *MachO, writer: anytype) !void { |
| 67 | const zo = macho_file.getZigObject().?; | ||
| 66 | for (zig_got.entries.items) |entry| { | 68 | for (zig_got.entries.items) |entry| { |
| 67 | const symbol = macho_file.getSymbol(entry); | 69 | const symbol = zo.symbols.items[entry]; |
| 68 | const value = symbol.address(.{ .stubs = false }, macho_file); | 70 | const value = symbol.address(.{ .stubs = false }, macho_file); |
| 69 | try writer.writeInt(u64, value, .little); | 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 | const FormatCtx = struct { | 75 | const FormatCtx = struct { |
| 90 | zig_got: ZigGotSection, | 76 | zig_got: ZigGotSection, |
| 91 | macho_file: *MachO, | 77 | macho_file: *MachO, |
| ... | @@ -103,22 +89,25 @@ pub const ZigGotSection = struct { | ... | @@ -103,22 +89,25 @@ pub const ZigGotSection = struct { |
| 103 | ) !void { | 89 | ) !void { |
| 104 | _ = options; | 90 | _ = options; |
| 105 | _ = unused_fmt_string; | 91 | _ = unused_fmt_string; |
| 92 | const zig_got = ctx.zig_got; | ||
| 93 | const macho_file = ctx.macho_file; | ||
| 106 | try writer.writeAll("__zig_got\n"); | 94 | try writer.writeAll("__zig_got\n"); |
| 107 | for (ctx.zig_got.entries.items, 0..) |entry, index| { | 95 | for (zig_got.entries.items, 0..) |entry, index| { |
| 108 | const symbol = ctx.macho_file.getSymbol(entry); | 96 | const zo = macho_file.getZigObject().?; |
| 97 | const symbol = zo.symbols.items[entry]; | ||
| 109 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ | 98 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 110 | index, | 99 | index, |
| 111 | ctx.zig_got.entryAddress(@intCast(index), ctx.macho_file), | 100 | zig_got.entryAddress(@intCast(index), macho_file), |
| 112 | entry, | 101 | entry, |
| 113 | symbol.getAddress(.{}, ctx.macho_file), | 102 | symbol.getAddress(.{}, macho_file), |
| 114 | symbol.getName(ctx.macho_file), | 103 | symbol.getName(macho_file), |
| 115 | }); | 104 | }); |
| 116 | } | 105 | } |
| 117 | } | 106 | } |
| 118 | }; | 107 | }; |
| 119 | 108 | ||
| 120 | pub const GotSection = struct { | 109 | pub const GotSection = struct { |
| 121 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 110 | symbols: std.ArrayListUnmanaged(MachO.Ref) = .{}, |
| 122 | 111 | ||
| 123 | pub const Index = u32; | 112 | pub const Index = u32; |
| 124 | 113 | ||
| ... | @@ -126,14 +115,14 @@ pub const GotSection = struct { | ... | @@ -126,14 +115,14 @@ pub const GotSection = struct { |
| 126 | got.symbols.deinit(allocator); | 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 | const gpa = macho_file.base.comp.gpa; | 119 | const gpa = macho_file.base.comp.gpa; |
| 131 | const index = @as(Index, @intCast(got.symbols.items.len)); | 120 | const index = @as(Index, @intCast(got.symbols.items.len)); |
| 132 | const entry = try got.symbols.addOne(gpa); | 121 | const entry = try got.symbols.addOne(gpa); |
| 133 | entry.* = sym_index; | 122 | entry.* = ref; |
| 134 | const symbol = macho_file.getSymbol(sym_index); | 123 | const symbol = ref.getSymbol(macho_file).?; |
| 135 | symbol.flags.has_got = true; | 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 | pub fn getAddress(got: GotSection, index: Index, macho_file: *MachO) u64 { | 128 | pub fn getAddress(got: GotSection, index: Index, macho_file: *MachO) u64 { |
| ... | @@ -146,46 +135,11 @@ pub const GotSection = struct { | ... | @@ -146,46 +135,11 @@ pub const GotSection = struct { |
| 146 | return got.symbols.items.len * @sizeOf(u64); | 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 | pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void { | 138 | pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void { |
| 185 | const tracy = trace(@src()); | 139 | const tracy = trace(@src()); |
| 186 | defer tracy.end(); | 140 | defer tracy.end(); |
| 187 | for (got.symbols.items) |sym_index| { | 141 | for (got.symbols.items) |ref| { |
| 188 | const sym = macho_file.getSymbol(sym_index); | 142 | const sym = ref.getSymbol(macho_file).?; |
| 189 | const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file); | 143 | const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file); |
| 190 | try writer.writeInt(u64, value, .little); | 144 | try writer.writeInt(u64, value, .little); |
| 191 | } | 145 | } |
| ... | @@ -208,12 +162,12 @@ pub const GotSection = struct { | ... | @@ -208,12 +162,12 @@ pub const GotSection = struct { |
| 208 | ) !void { | 162 | ) !void { |
| 209 | _ = options; | 163 | _ = options; |
| 210 | _ = unused_fmt_string; | 164 | _ = unused_fmt_string; |
| 211 | for (ctx.got.symbols.items, 0..) |entry, i| { | 165 | for (ctx.got.symbols.items, 0..) |ref, i| { |
| 212 | const symbol = ctx.macho_file.getSymbol(entry); | 166 | const symbol = ref.getSymbol(ctx.macho_file).?; |
| 213 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ | 167 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 214 | i, | 168 | i, |
| 215 | symbol.getGotAddress(ctx.macho_file), | 169 | symbol.getGotAddress(ctx.macho_file), |
| 216 | entry, | 170 | ref, |
| 217 | symbol.getAddress(.{}, ctx.macho_file), | 171 | symbol.getAddress(.{}, ctx.macho_file), |
| 218 | symbol.getName(ctx.macho_file), | 172 | symbol.getName(ctx.macho_file), |
| 219 | }); | 173 | }); |
| ... | @@ -222,7 +176,7 @@ pub const GotSection = struct { | ... | @@ -222,7 +176,7 @@ pub const GotSection = struct { |
| 222 | }; | 176 | }; |
| 223 | 177 | ||
| 224 | pub const StubsSection = struct { | 178 | pub const StubsSection = struct { |
| 225 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 179 | symbols: std.ArrayListUnmanaged(MachO.Ref) = .{}, |
| 226 | 180 | ||
| 227 | pub const Index = u32; | 181 | pub const Index = u32; |
| 228 | 182 | ||
| ... | @@ -230,13 +184,13 @@ pub const StubsSection = struct { | ... | @@ -230,13 +184,13 @@ pub const StubsSection = struct { |
| 230 | stubs.symbols.deinit(allocator); | 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 | const gpa = macho_file.base.comp.gpa; | 188 | const gpa = macho_file.base.comp.gpa; |
| 235 | const index = @as(Index, @intCast(stubs.symbols.items.len)); | 189 | const index = @as(Index, @intCast(stubs.symbols.items.len)); |
| 236 | const entry = try stubs.symbols.addOne(gpa); | 190 | const entry = try stubs.symbols.addOne(gpa); |
| 237 | entry.* = sym_index; | 191 | entry.* = ref; |
| 238 | const symbol = macho_file.getSymbol(sym_index); | 192 | const symbol = ref.getSymbol(macho_file).?; |
| 239 | try symbol.addExtra(.{ .stubs = index }, macho_file); | 193 | symbol.addExtra(.{ .stubs = index }, macho_file); |
| 240 | } | 194 | } |
| 241 | 195 | ||
| 242 | pub fn getAddress(stubs: StubsSection, index: Index, macho_file: *MachO) u64 { | 196 | pub fn getAddress(stubs: StubsSection, index: Index, macho_file: *MachO) u64 { |
| ... | @@ -256,8 +210,8 @@ pub const StubsSection = struct { | ... | @@ -256,8 +210,8 @@ pub const StubsSection = struct { |
| 256 | const cpu_arch = macho_file.getTarget().cpu.arch; | 210 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 257 | const laptr_sect = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_sect_index.?]; | 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| { | 213 | for (stubs.symbols.items, 0..) |ref, idx| { |
| 260 | const sym = macho_file.getSymbol(sym_index); | 214 | const sym = ref.getSymbol(macho_file).?; |
| 261 | const source = sym.getAddress(.{ .stubs = true }, macho_file); | 215 | const source = sym.getAddress(.{ .stubs = true }, macho_file); |
| 262 | const target = laptr_sect.addr + idx * @sizeOf(u64); | 216 | const target = laptr_sect.addr + idx * @sizeOf(u64); |
| 263 | switch (cpu_arch) { | 217 | switch (cpu_arch) { |
| ... | @@ -299,12 +253,12 @@ pub const StubsSection = struct { | ... | @@ -299,12 +253,12 @@ pub const StubsSection = struct { |
| 299 | ) !void { | 253 | ) !void { |
| 300 | _ = options; | 254 | _ = options; |
| 301 | _ = unused_fmt_string; | 255 | _ = unused_fmt_string; |
| 302 | for (ctx.stubs.symbols.items, 0..) |entry, i| { | 256 | for (ctx.stubs.symbols.items, 0..) |ref, i| { |
| 303 | const symbol = ctx.macho_file.getSymbol(entry); | 257 | const symbol = ref.getSymbol(ctx.macho_file).?; |
| 304 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ | 258 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 305 | i, | 259 | i, |
| 306 | symbol.getStubsAddress(ctx.macho_file), | 260 | symbol.getStubsAddress(ctx.macho_file), |
| 307 | entry, | 261 | ref, |
| 308 | symbol.getAddress(.{}, ctx.macho_file), | 262 | symbol.getAddress(.{}, ctx.macho_file), |
| 309 | symbol.getName(ctx.macho_file), | 263 | symbol.getName(ctx.macho_file), |
| 310 | }); | 264 | }); |
| ... | @@ -335,8 +289,8 @@ pub const StubsHelperSection = struct { | ... | @@ -335,8 +289,8 @@ pub const StubsHelperSection = struct { |
| 335 | _ = stubs_helper; | 289 | _ = stubs_helper; |
| 336 | const cpu_arch = macho_file.getTarget().cpu.arch; | 290 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 337 | var s: usize = preambleSize(cpu_arch); | 291 | var s: usize = preambleSize(cpu_arch); |
| 338 | for (macho_file.stubs.symbols.items) |sym_index| { | 292 | for (macho_file.stubs.symbols.items) |ref| { |
| 339 | const sym = macho_file.getSymbol(sym_index); | 293 | const sym = ref.getSymbol(macho_file).?; |
| 340 | if (sym.flags.weak) continue; | 294 | if (sym.flags.weak) continue; |
| 341 | s += entrySize(cpu_arch); | 295 | s += entrySize(cpu_arch); |
| 342 | } | 296 | } |
| ... | @@ -355,8 +309,8 @@ pub const StubsHelperSection = struct { | ... | @@ -355,8 +309,8 @@ pub const StubsHelperSection = struct { |
| 355 | const entry_size = entrySize(cpu_arch); | 309 | const entry_size = entrySize(cpu_arch); |
| 356 | 310 | ||
| 357 | var idx: usize = 0; | 311 | var idx: usize = 0; |
| 358 | for (macho_file.stubs.symbols.items) |sym_index| { | 312 | for (macho_file.stubs.symbols.items) |ref| { |
| 359 | const sym = macho_file.getSymbol(sym_index); | 313 | const sym = ref.getSymbol(macho_file).?; |
| 360 | if (sym.flags.weak) continue; | 314 | if (sym.flags.weak) continue; |
| 361 | const offset = macho_file.lazy_bind.offsets.items[idx]; | 315 | const offset = macho_file.lazy_bind.offsets.items[idx]; |
| 362 | const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx); | 316 | const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx); |
| ... | @@ -390,14 +344,15 @@ pub const StubsHelperSection = struct { | ... | @@ -390,14 +344,15 @@ pub const StubsHelperSection = struct { |
| 390 | 344 | ||
| 391 | fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void { | 345 | fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void { |
| 392 | _ = stubs_helper; | 346 | _ = stubs_helper; |
| 347 | const obj = macho_file.getInternalObject().?; | ||
| 393 | const cpu_arch = macho_file.getTarget().cpu.arch; | 348 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 394 | const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?]; | 349 | const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?]; |
| 395 | const dyld_private_addr = target: { | 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 | break :target sym.getAddress(.{}, macho_file); | 352 | break :target sym.getAddress(.{}, macho_file); |
| 398 | }; | 353 | }; |
| 399 | const dyld_stub_binder_addr = target: { | 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 | break :target sym.getGotAddress(macho_file); | 356 | break :target sym.getGotAddress(macho_file); |
| 402 | }; | 357 | }; |
| 403 | switch (cpu_arch) { | 358 | switch (cpu_arch) { |
| ... | @@ -446,49 +401,6 @@ pub const LaSymbolPtrSection = struct { | ... | @@ -446,49 +401,6 @@ pub const LaSymbolPtrSection = struct { |
| 446 | return macho_file.stubs.symbols.items.len * @sizeOf(u64); | 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 | pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void { | 404 | pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void { |
| 493 | const tracy = trace(@src()); | 405 | const tracy = trace(@src()); |
| 494 | defer tracy.end(); | 406 | defer tracy.end(); |
| ... | @@ -496,8 +408,8 @@ pub const LaSymbolPtrSection = struct { | ... | @@ -496,8 +408,8 @@ pub const LaSymbolPtrSection = struct { |
| 496 | const cpu_arch = macho_file.getTarget().cpu.arch; | 408 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 497 | const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?]; | 409 | const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?]; |
| 498 | var stub_helper_idx: u32 = 0; | 410 | var stub_helper_idx: u32 = 0; |
| 499 | for (macho_file.stubs.symbols.items) |sym_index| { | 411 | for (macho_file.stubs.symbols.items) |ref| { |
| 500 | const sym = macho_file.getSymbol(sym_index); | 412 | const sym = ref.getSymbol(macho_file).?; |
| 501 | if (sym.flags.weak) { | 413 | if (sym.flags.weak) { |
| 502 | const value = sym.getAddress(.{ .stubs = false }, macho_file); | 414 | const value = sym.getAddress(.{ .stubs = false }, macho_file); |
| 503 | try writer.writeInt(u64, @intCast(value), .little); | 415 | try writer.writeInt(u64, @intCast(value), .little); |
| ... | @@ -512,7 +424,7 @@ pub const LaSymbolPtrSection = struct { | ... | @@ -512,7 +424,7 @@ pub const LaSymbolPtrSection = struct { |
| 512 | }; | 424 | }; |
| 513 | 425 | ||
| 514 | pub const TlvPtrSection = struct { | 426 | pub const TlvPtrSection = struct { |
| 515 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 427 | symbols: std.ArrayListUnmanaged(MachO.Ref) = .{}, |
| 516 | 428 | ||
| 517 | pub const Index = u32; | 429 | pub const Index = u32; |
| 518 | 430 | ||
| ... | @@ -520,13 +432,13 @@ pub const TlvPtrSection = struct { | ... | @@ -520,13 +432,13 @@ pub const TlvPtrSection = struct { |
| 520 | tlv.symbols.deinit(allocator); | 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 | const gpa = macho_file.base.comp.gpa; | 436 | const gpa = macho_file.base.comp.gpa; |
| 525 | const index = @as(Index, @intCast(tlv.symbols.items.len)); | 437 | const index = @as(Index, @intCast(tlv.symbols.items.len)); |
| 526 | const entry = try tlv.symbols.addOne(gpa); | 438 | const entry = try tlv.symbols.addOne(gpa); |
| 527 | entry.* = sym_index; | 439 | entry.* = ref; |
| 528 | const symbol = macho_file.getSymbol(sym_index); | 440 | const symbol = ref.getSymbol(macho_file).?; |
| 529 | try symbol.addExtra(.{ .tlv_ptr = index }, macho_file); | 441 | symbol.addExtra(.{ .tlv_ptr = index }, macho_file); |
| 530 | } | 442 | } |
| 531 | 443 | ||
| 532 | pub fn getAddress(tlv: TlvPtrSection, index: Index, macho_file: *MachO) u64 { | 444 | pub fn getAddress(tlv: TlvPtrSection, index: Index, macho_file: *MachO) u64 { |
| ... | @@ -539,47 +451,12 @@ pub const TlvPtrSection = struct { | ... | @@ -539,47 +451,12 @@ pub const TlvPtrSection = struct { |
| 539 | return tlv.symbols.items.len * @sizeOf(u64); | 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 | pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void { | 454 | pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void { |
| 578 | const tracy = trace(@src()); | 455 | const tracy = trace(@src()); |
| 579 | defer tracy.end(); | 456 | defer tracy.end(); |
| 580 | 457 | ||
| 581 | for (tlv.symbols.items) |sym_index| { | 458 | for (tlv.symbols.items) |ref| { |
| 582 | const sym = macho_file.getSymbol(sym_index); | 459 | const sym = ref.getSymbol(macho_file).?; |
| 583 | if (sym.flags.import) { | 460 | if (sym.flags.import) { |
| 584 | try writer.writeInt(u64, 0, .little); | 461 | try writer.writeInt(u64, 0, .little); |
| 585 | } else { | 462 | } else { |
| ... | @@ -605,12 +482,12 @@ pub const TlvPtrSection = struct { | ... | @@ -605,12 +482,12 @@ pub const TlvPtrSection = struct { |
| 605 | ) !void { | 482 | ) !void { |
| 606 | _ = options; | 483 | _ = options; |
| 607 | _ = unused_fmt_string; | 484 | _ = unused_fmt_string; |
| 608 | for (ctx.tlv.symbols.items, 0..) |entry, i| { | 485 | for (ctx.tlv.symbols.items, 0..) |ref, i| { |
| 609 | const symbol = ctx.macho_file.getSymbol(entry); | 486 | const symbol = ref.getSymbol(ctx.macho_file).?; |
| 610 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ | 487 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 611 | i, | 488 | i, |
| 612 | symbol.getTlvPtrAddress(ctx.macho_file), | 489 | symbol.getTlvPtrAddress(ctx.macho_file), |
| 613 | entry, | 490 | ref, |
| 614 | symbol.getAddress(.{}, ctx.macho_file), | 491 | symbol.getAddress(.{}, ctx.macho_file), |
| 615 | symbol.getName(ctx.macho_file), | 492 | symbol.getName(ctx.macho_file), |
| 616 | }); | 493 | }); |
| ... | @@ -619,7 +496,7 @@ pub const TlvPtrSection = struct { | ... | @@ -619,7 +496,7 @@ pub const TlvPtrSection = struct { |
| 619 | }; | 496 | }; |
| 620 | 497 | ||
| 621 | pub const ObjcStubsSection = struct { | 498 | pub const ObjcStubsSection = struct { |
| 622 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 499 | symbols: std.ArrayListUnmanaged(MachO.Ref) = .{}, |
| 623 | 500 | ||
| 624 | pub fn deinit(objc: *ObjcStubsSection, allocator: Allocator) void { | 501 | pub fn deinit(objc: *ObjcStubsSection, allocator: Allocator) void { |
| 625 | objc.symbols.deinit(allocator); | 502 | objc.symbols.deinit(allocator); |
| ... | @@ -633,13 +510,13 @@ pub const ObjcStubsSection = struct { | ... | @@ -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 | const gpa = macho_file.base.comp.gpa; | 514 | const gpa = macho_file.base.comp.gpa; |
| 638 | const index = @as(Index, @intCast(objc.symbols.items.len)); | 515 | const index = @as(Index, @intCast(objc.symbols.items.len)); |
| 639 | const entry = try objc.symbols.addOne(gpa); | 516 | const entry = try objc.symbols.addOne(gpa); |
| 640 | entry.* = sym_index; | 517 | entry.* = ref; |
| 641 | const symbol = macho_file.getSymbol(sym_index); | 518 | const symbol = ref.getSymbol(macho_file).?; |
| 642 | try symbol.addExtra(.{ .objc_stubs = index }, macho_file); | 519 | symbol.addExtra(.{ .objc_stubs = index }, macho_file); |
| 643 | } | 520 | } |
| 644 | 521 | ||
| 645 | pub fn getAddress(objc: ObjcStubsSection, index: Index, macho_file: *MachO) u64 { | 522 | pub fn getAddress(objc: ObjcStubsSection, index: Index, macho_file: *MachO) u64 { |
| ... | @@ -656,8 +533,10 @@ pub const ObjcStubsSection = struct { | ... | @@ -656,8 +533,10 @@ pub const ObjcStubsSection = struct { |
| 656 | const tracy = trace(@src()); | 533 | const tracy = trace(@src()); |
| 657 | defer tracy.end(); | 534 | defer tracy.end(); |
| 658 | 535 | ||
| 659 | for (objc.symbols.items, 0..) |sym_index, idx| { | 536 | const obj = macho_file.getInternalObject().?; |
| 660 | const sym = macho_file.getSymbol(sym_index); | 537 | |
| 538 | for (objc.symbols.items, 0..) |ref, idx| { | ||
| 539 | const sym = ref.getSymbol(macho_file).?; | ||
| 661 | const addr = objc.getAddress(@intCast(idx), macho_file); | 540 | const addr = objc.getAddress(@intCast(idx), macho_file); |
| 662 | switch (macho_file.getTarget().cpu.arch) { | 541 | switch (macho_file.getTarget().cpu.arch) { |
| 663 | .x86_64 => { | 542 | .x86_64 => { |
| ... | @@ -669,7 +548,7 @@ pub const ObjcStubsSection = struct { | ... | @@ -669,7 +548,7 @@ pub const ObjcStubsSection = struct { |
| 669 | } | 548 | } |
| 670 | try writer.writeAll(&.{ 0xff, 0x25 }); | 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 | const target = target_sym.getGotAddress(macho_file); | 552 | const target = target_sym.getGotAddress(macho_file); |
| 674 | const source = addr + 7; | 553 | const source = addr + 7; |
| 675 | try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); | 554 | try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); |
| ... | @@ -689,7 +568,7 @@ pub const ObjcStubsSection = struct { | ... | @@ -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 | const target = target_sym.getGotAddress(macho_file); | 572 | const target = target_sym.getGotAddress(macho_file); |
| 694 | const source = addr + 2 * @sizeOf(u32); | 573 | const source = addr + 2 * @sizeOf(u32); |
| 695 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); | 574 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| ... | @@ -728,12 +607,12 @@ pub const ObjcStubsSection = struct { | ... | @@ -728,12 +607,12 @@ pub const ObjcStubsSection = struct { |
| 728 | ) !void { | 607 | ) !void { |
| 729 | _ = options; | 608 | _ = options; |
| 730 | _ = unused_fmt_string; | 609 | _ = unused_fmt_string; |
| 731 | for (ctx.objc.symbols.items, 0..) |entry, i| { | 610 | for (ctx.objc.symbols.items, 0..) |ref, i| { |
| 732 | const symbol = ctx.macho_file.getSymbol(entry); | 611 | const symbol = ref.getSymbol(ctx.macho_file).?; |
| 733 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ | 612 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ |
| 734 | i, | 613 | i, |
| 735 | symbol.getObjcStubsAddress(ctx.macho_file), | 614 | symbol.getObjcStubsAddress(ctx.macho_file), |
| 736 | entry, | 615 | ref, |
| 737 | symbol.getAddress(.{}, ctx.macho_file), | 616 | symbol.getAddress(.{}, ctx.macho_file), |
| 738 | symbol.getName(ctx.macho_file), | 617 | symbol.getName(ctx.macho_file), |
| 739 | }); | 618 | }); |
| ... | @@ -749,44 +628,112 @@ pub const Indsymtab = struct { | ... | @@ -749,44 +628,112 @@ pub const Indsymtab = struct { |
| 749 | return @intCast(macho_file.stubs.symbols.items.len * 2 + macho_file.got.symbols.items.len); | 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 | pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void { | 635 | pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void { |
| 753 | const tracy = trace(@src()); | 636 | const tracy = trace(@src()); |
| 754 | defer tracy.end(); | 637 | defer tracy.end(); |
| 755 | 638 | ||
| 756 | _ = ind; | 639 | _ = ind; |
| 757 | 640 | ||
| 758 | for (macho_file.stubs.symbols.items) |sym_index| { | 641 | for (macho_file.stubs.symbols.items) |ref| { |
| 759 | const sym = macho_file.getSymbol(sym_index); | 642 | const sym = ref.getSymbol(macho_file).?; |
| 760 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); | 643 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); |
| 761 | } | 644 | } |
| 762 | 645 | ||
| 763 | for (macho_file.got.symbols.items) |sym_index| { | 646 | for (macho_file.got.symbols.items) |ref| { |
| 764 | const sym = macho_file.getSymbol(sym_index); | 647 | const sym = ref.getSymbol(macho_file).?; |
| 765 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); | 648 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); |
| 766 | } | 649 | } |
| 767 | 650 | ||
| 768 | for (macho_file.stubs.symbols.items) |sym_index| { | 651 | for (macho_file.stubs.symbols.items) |ref| { |
| 769 | const sym = macho_file.getSymbol(sym_index); | 652 | const sym = ref.getSymbol(macho_file).?; |
| 770 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); | 653 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); |
| 771 | } | 654 | } |
| 772 | } | 655 | } |
| 773 | }; | 656 | }; |
| 774 | 657 | ||
| 775 | pub const RebaseSection = Rebase; | 658 | pub const DataInCode = struct { |
| 776 | pub const BindSection = bind.Bind; | 659 | entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 777 | pub const WeakBindSection = bind.WeakBind; | 660 | |
| 778 | pub const LazyBindSection = bind.LazyBind; | 661 | pub fn deinit(dice: *DataInCode, allocator: Allocator) void { |
| 779 | pub const ExportTrieSection = Trie; | 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 | const aarch64 = @import("../aarch64.zig"); | 730 | const aarch64 = @import("../aarch64.zig"); |
| 782 | const assert = std.debug.assert; | 731 | const assert = std.debug.assert; |
| 783 | const bind = @import("dyld_info/bind.zig"); | 732 | const macho = std.macho; |
| 784 | const math = std.math; | 733 | const math = std.math; |
| 785 | const std = @import("std"); | 734 | const std = @import("std"); |
| 786 | const trace = @import("../../tracy.zig").trace; | 735 | const trace = @import("../../tracy.zig").trace; |
| 787 | 736 | ||
| 788 | const Allocator = std.mem.Allocator; | 737 | const Allocator = std.mem.Allocator; |
| 789 | const MachO = @import("../MachO.zig"); | 738 | const MachO = @import("../MachO.zig"); |
| 790 | const Rebase = @import("dyld_info/Rebase.zig"); | ||
| 791 | const Symbol = @import("Symbol.zig"); | 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,55 +5,45 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void { |
| 5 | const gpa = macho_file.base.comp.gpa; | 5 | const gpa = macho_file.base.comp.gpa; |
| 6 | const slice = macho_file.sections.slice(); | 6 | const slice = macho_file.sections.slice(); |
| 7 | const header = &slice.items(.header)[sect_id]; | 7 | const header = &slice.items(.header)[sect_id]; |
| 8 | const thnks = &slice.items(.thunks)[sect_id]; | ||
| 8 | const atoms = slice.items(.atoms)[sect_id].items; | 9 | const atoms = slice.items(.atoms)[sect_id].items; |
| 9 | assert(atoms.len > 0); | 10 | assert(atoms.len > 0); |
| 10 | 11 | ||
| 11 | for (atoms) |atom_index| { | 12 | for (atoms) |ref| { |
| 12 | macho_file.getAtom(atom_index).?.value = @bitCast(@as(i64, -1)); | 13 | ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1)); |
| 13 | } | 14 | } |
| 14 | 15 | ||
| 15 | var i: usize = 0; | 16 | var i: usize = 0; |
| 16 | while (i < atoms.len) { | 17 | while (i < atoms.len) { |
| 17 | const start = i; | 18 | const start = i; |
| 18 | const start_atom = macho_file.getAtom(atoms[start]).?; | 19 | const start_atom = atoms[start].getAtom(macho_file).?; |
| 19 | assert(start_atom.flags.alive); | 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 | i += 1; | 22 | i += 1; |
| 22 | 23 | ||
| 23 | while (i < atoms.len and | 24 | while (i < atoms.len and |
| 24 | header.size - start_atom.value < max_allowed_distance) : (i += 1) | 25 | header.size - start_atom.value < max_allowed_distance) : (i += 1) |
| 25 | { | 26 | { |
| 26 | const atom_index = atoms[i]; | 27 | const atom = atoms[i].getAtom(macho_file).?; |
| 27 | const atom = macho_file.getAtom(atom_index).?; | ||
| 28 | assert(atom.flags.alive); | 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 | // Insert a thunk at the group end | 32 | // Insert a thunk at the group end |
| 33 | const thunk_index = try macho_file.addThunk(); | 33 | const thunk_index = try macho_file.addThunk(); |
| 34 | const thunk = macho_file.getThunk(thunk_index); | 34 | const thunk = macho_file.getThunk(thunk_index); |
| 35 | thunk.out_n_sect = sect_id; | 35 | thunk.out_n_sect = sect_id; |
| 36 | try thnks.append(gpa, thunk_index); | ||
| 36 | 37 | ||
| 37 | // Scan relocs in the group and create trampolines for any unreachable callsite | 38 | // Scan relocs in the group and create trampolines for any unreachable callsite |
| 38 | for (atoms[start..i]) |atom_index| { | 39 | try scanRelocs(thunk_index, gpa, atoms[start..i], macho_file); |
| 39 | const atom = macho_file.getAtom(atom_index).?; | 40 | thunk.value = advance(header, thunk.size(), .@"4"); |
| 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"); | ||
| 51 | 41 | ||
| 52 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) }); | 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 | const offset = alignment.forward(sect.size); | 47 | const offset = alignment.forward(sect.size); |
| 58 | const padding = offset - sect.size; | 48 | const padding = offset - sect.size; |
| 59 | sect.size += padding + size; | 49 | sect.size += padding + size; |
| ... | @@ -61,14 +51,32 @@ fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 { | ... | @@ -61,14 +51,32 @@ fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 { |
| 61 | return offset; | 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 | fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { | 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 | if (target.flags.stubs or target.flags.objc_stubs) return false; | 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 | const target_atom = target.getAtom(macho_file).?; | 76 | const target_atom = target.getAtom(macho_file).?; |
| 69 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; | 77 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; |
| 70 | const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off)); | 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 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; | 80 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; |
| 73 | return true; | 81 | return true; |
| 74 | } | 82 | } |
| ... | @@ -76,7 +84,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { | ... | @@ -76,7 +84,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { |
| 76 | pub const Thunk = struct { | 84 | pub const Thunk = struct { |
| 77 | value: u64 = 0, | 85 | value: u64 = 0, |
| 78 | out_n_sect: u8 = 0, | 86 | out_n_sect: u8 = 0, |
| 79 | symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, | 87 | symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{}, |
| 80 | 88 | ||
| 81 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { | 89 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { |
| 82 | thunk.symbols.deinit(allocator); | 90 | thunk.symbols.deinit(allocator); |
| ... | @@ -91,13 +99,13 @@ pub const Thunk = struct { | ... | @@ -91,13 +99,13 @@ pub const Thunk = struct { |
| 91 | return header.addr + thunk.value; | 99 | return header.addr + thunk.value; |
| 92 | } | 100 | } |
| 93 | 101 | ||
| 94 | pub fn getTargetAddress(thunk: Thunk, sym_index: Symbol.Index, macho_file: *MachO) u64 { | 102 | pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { |
| 95 | return thunk.getAddress(macho_file) + thunk.symbols.getIndex(sym_index).? * trampoline_size; | 103 | return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size; |
| 96 | } | 104 | } |
| 97 | 105 | ||
| 98 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { | 106 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { |
| 99 | for (thunk.symbols.keys(), 0..) |sym_index, i| { | 107 | for (thunk.symbols.keys(), 0..) |ref, i| { |
| 100 | const sym = macho_file.getSymbol(sym_index); | 108 | const sym = ref.getSymbol(macho_file).?; |
| 101 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; | 109 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; |
| 102 | const taddr = sym.getAddress(.{}, macho_file); | 110 | const taddr = sym.getAddress(.{}, macho_file); |
| 103 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); | 111 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); |
| ... | @@ -144,9 +152,9 @@ pub const Thunk = struct { | ... | @@ -144,9 +152,9 @@ pub const Thunk = struct { |
| 144 | const thunk = ctx.thunk; | 152 | const thunk = ctx.thunk; |
| 145 | const macho_file = ctx.macho_file; | 153 | const macho_file = ctx.macho_file; |
| 146 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); | 154 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); |
| 147 | for (thunk.symbols.keys()) |index| { | 155 | for (thunk.symbols.keys()) |ref| { |
| 148 | const sym = macho_file.getSymbol(index); | 156 | const sym = ref.getSymbol(macho_file).?; |
| 149 | try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.getName(macho_file), sym.value }); | 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,8 +74,9 @@ fn addCompileStep( |
| 74 | .target = base.target, | 74 | .target = base.target, |
| 75 | .optimize = base.optimize, | 75 | .optimize = base.optimize, |
| 76 | .root_source_file = rsf: { | 76 | .root_source_file = rsf: { |
| 77 | const name = b.fmt("{s}.zig", .{overlay.name}); | ||
| 77 | const bytes = overlay.zig_source_bytes orelse break :rsf null; | 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 | .pic = overlay.pic, | 81 | .pic = overlay.pic, |
| 81 | .strip = if (base.strip) |s| s else overlay.strip, | 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,9 +25,12 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 25 | macho_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = x86_64_target })); | 25 | macho_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = x86_64_target })); |
| 26 | macho_step.dependOn(testReexportsZig(b, .{ .use_llvm = false, .target = x86_64_target })); | 26 | macho_step.dependOn(testReexportsZig(b, .{ .use_llvm = false, .target = x86_64_target })); |
| 27 | macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .target = x86_64_target })); | 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 | // Exercise linker with LLVM backend | 31 | // Exercise linker with LLVM backend |
| 30 | macho_step.dependOn(testDeadStrip(b, .{ .target = default_target })); | 32 | macho_step.dependOn(testDeadStrip(b, .{ .target = default_target })); |
| 33 | macho_step.dependOn(testDuplicateDefinitions(b, .{ .target = default_target })); | ||
| 31 | macho_step.dependOn(testEmptyObject(b, .{ .target = default_target })); | 34 | macho_step.dependOn(testEmptyObject(b, .{ .target = default_target })); |
| 32 | macho_step.dependOn(testEmptyZig(b, .{ .target = default_target })); | 35 | macho_step.dependOn(testEmptyZig(b, .{ .target = default_target })); |
| 33 | macho_step.dependOn(testEntryPoint(b, .{ .target = default_target })); | 36 | macho_step.dependOn(testEntryPoint(b, .{ .target = default_target })); |
| ... | @@ -56,7 +59,9 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -56,7 +59,9 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 56 | macho_step.dependOn(testTentative(b, .{ .target = default_target })); | 59 | macho_step.dependOn(testTentative(b, .{ .target = default_target })); |
| 57 | macho_step.dependOn(testThunks(b, .{ .target = aarch64_target })); | 60 | macho_step.dependOn(testThunks(b, .{ .target = aarch64_target })); |
| 58 | macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target })); | 61 | macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target })); |
| 62 | macho_step.dependOn(testTlsZig(b, .{ .target = default_target })); | ||
| 59 | macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target })); | 63 | macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target })); |
| 64 | macho_step.dependOn(testUnresolvedError(b, .{ .target = default_target })); | ||
| 60 | macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target })); | 65 | macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target })); |
| 61 | macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target })); | 66 | macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target })); |
| 62 | macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target })); | 67 | macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target })); |
| ... | @@ -178,6 +183,37 @@ fn testDeadStrip(b: *Build, opts: Options) *Step { | ... | @@ -178,6 +183,37 @@ fn testDeadStrip(b: *Build, opts: Options) *Step { |
| 178 | return test_step; | 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 | fn testDeadStripDylibs(b: *Build, opts: Options) *Step { | 217 | fn testDeadStripDylibs(b: *Build, opts: Options) *Step { |
| 182 | const test_step = addTestStep(b, "dead-strip-dylibs", opts); | 218 | const test_step = addTestStep(b, "dead-strip-dylibs", opts); |
| 183 | 219 | ||
| ... | @@ -912,7 +948,7 @@ fn testLinksection(b: *Build, opts: Options) *Step { | ... | @@ -912,7 +948,7 @@ fn testLinksection(b: *Build, opts: Options) *Step { |
| 912 | 948 | ||
| 913 | if (opts.optimize == .Debug) { | 949 | if (opts.optimize == .Debug) { |
| 914 | check.checkInSymtab(); | 950 | check.checkInSymtab(); |
| 915 | check.checkContains("(__TEXT,__TestGenFnA) _a.testGenericFn__anon_"); | 951 | check.checkContains("(__TEXT,__TestGenFnA) _main.testGenericFn__anon_"); |
| 916 | } | 952 | } |
| 917 | 953 | ||
| 918 | test_step.dependOn(&check.step); | 954 | test_step.dependOn(&check.step); |
| ... | @@ -2274,6 +2310,32 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { | ... | @@ -2274,6 +2310,32 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { |
| 2274 | return test_step; | 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 | fn testTwoLevelNamespace(b: *Build, opts: Options) *Step { | 2339 | fn testTwoLevelNamespace(b: *Build, opts: Options) *Step { |
| 2278 | const test_step = addTestStep(b, "two-level-namespace", opts); | 2340 | const test_step = addTestStep(b, "two-level-namespace", opts); |
| 2279 | 2341 | ||
| ... | @@ -2471,6 +2533,42 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { | ... | @@ -2471,6 +2533,42 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { |
| 2471 | return test_step; | 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 | fn testUnwindInfo(b: *Build, opts: Options) *Step { | 2572 | fn testUnwindInfo(b: *Build, opts: Options) *Step { |
| 2475 | const test_step = addTestStep(b, "unwind-info", opts); | 2573 | const test_step = addTestStep(b, "unwind-info", opts); |
| 2476 | 2574 |