| author | |
| committer | |
| log | 983d6dcd9ea75e05abd8ce2bd247bbad3960acd7 |
| tree | c5767d15a29bcc1e3704ca37e3dc0ddf54eca376 |
| parent | 506f24cac2f5226210f9ce505d5b93c47b7b8c87 |
* In watch mode, when changing the C source, we will trigger complete
relinking of objects, dylibs and archives (atoms coming from the
incremental updates stay put however). This means, we need to undo
metadata populated when linking in objects, archives and dylibs.
* Remove unused splitting section into atoms bit. This optimisation
will probably be best rewritten from scratch once self-hosted
matures so parking the idea for now. Also, for easier management
of atoms spawned from the Object file, keep the atoms subgraph as
part of the Object file struct.
* Remove obsolete ref to static initializers in object struct.
* Implement handling of global symbol collision in updateDeclExports.3 files changed, 368 insertions(+), 327 deletions(-)
src/link/MachO.zig+150-34| ... | @@ -231,7 +231,7 @@ const SymbolWithLoc = struct { | ... | @@ -231,7 +231,7 @@ const SymbolWithLoc = struct { |
| 231 | }, | 231 | }, |
| 232 | where_index: u32, | 232 | where_index: u32, |
| 233 | local_sym_index: u32 = 0, | 233 | local_sym_index: u32 = 0, |
| 234 | file: u16 = 0, | 234 | file: ?u16 = null, // null means Zig module |
| 235 | }; | 235 | }; |
| 236 | 236 | ||
| 237 | pub const GotIndirectionKey = struct { | 237 | pub const GotIndirectionKey = struct { |
| ... | @@ -543,9 +543,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -543,9 +543,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 543 | .mode = link.determineMode(self.base.options), | 543 | .mode = link.determineMode(self.base.options), |
| 544 | }); | 544 | }); |
| 545 | try self.populateMissingMetadata(); | 545 | try self.populateMissingMetadata(); |
| 546 | |||
| 547 | // TODO mimicking insertion of null symbol from incremental linker. | ||
| 548 | // This will need to moved. | ||
| 549 | try self.locals.append(self.base.allocator, .{ | 546 | try self.locals.append(self.base.allocator, .{ |
| 550 | .n_strx = 0, | 547 | .n_strx = 0, |
| 551 | .n_type = macho.N_UNDF, | 548 | .n_type = macho.N_UNDF, |
| ... | @@ -557,13 +554,56 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -557,13 +554,56 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 557 | } | 554 | } |
| 558 | 555 | ||
| 559 | if (needs_full_relink) { | 556 | if (needs_full_relink) { |
| 557 | for (self.objects.items) |*object| { | ||
| 558 | object.free(self.base.allocator, self); | ||
| 559 | object.deinit(self.base.allocator); | ||
| 560 | } | ||
| 560 | self.objects.clearRetainingCapacity(); | 561 | self.objects.clearRetainingCapacity(); |
| 562 | |||
| 563 | for (self.archives.items) |*archive| { | ||
| 564 | archive.deinit(self.base.allocator); | ||
| 565 | } | ||
| 561 | self.archives.clearRetainingCapacity(); | 566 | self.archives.clearRetainingCapacity(); |
| 567 | |||
| 568 | for (self.dylibs.items) |*dylib| { | ||
| 569 | dylib.deinit(self.base.allocator); | ||
| 570 | } | ||
| 562 | self.dylibs.clearRetainingCapacity(); | 571 | self.dylibs.clearRetainingCapacity(); |
| 563 | self.dylibs_map.clearRetainingCapacity(); | 572 | self.dylibs_map.clearRetainingCapacity(); |
| 564 | self.referenced_dylibs.clearRetainingCapacity(); | 573 | self.referenced_dylibs.clearRetainingCapacity(); |
| 565 | 574 | ||
| 566 | // TODO figure out how to clear atoms from objects, etc. | 575 | { |
| 576 | var to_remove = std.ArrayList(u32).init(self.base.allocator); | ||
| 577 | defer to_remove.deinit(); | ||
| 578 | var it = self.symbol_resolver.iterator(); | ||
| 579 | while (it.next()) |entry| { | ||
| 580 | const key = entry.key_ptr.*; | ||
| 581 | const value = entry.value_ptr.*; | ||
| 582 | if (value.file != null) { | ||
| 583 | try to_remove.append(key); | ||
| 584 | } | ||
| 585 | } | ||
| 586 | |||
| 587 | for (to_remove.items) |key| { | ||
| 588 | if (self.symbol_resolver.fetchRemove(key)) |entry| { | ||
| 589 | const resolv = entry.value; | ||
| 590 | switch (resolv.where) { | ||
| 591 | .global => { | ||
| 592 | self.globals_free_list.append(self.base.allocator, resolv.where_index) catch {}; | ||
| 593 | const sym = &self.globals.items[resolv.where_index]; | ||
| 594 | sym.n_strx = 0; | ||
| 595 | sym.n_type = 0; | ||
| 596 | sym.n_value = 0; | ||
| 597 | }, | ||
| 598 | .undef => { | ||
| 599 | const sym = &self.undefs.items[resolv.where_index]; | ||
| 600 | sym.n_strx = 0; | ||
| 601 | sym.n_desc = 0; | ||
| 602 | }, | ||
| 603 | } | ||
| 604 | } | ||
| 605 | } | ||
| 606 | } | ||
| 567 | 607 | ||
| 568 | // Positional arguments to the linker such as object files and static archives. | 608 | // Positional arguments to the linker such as object files and static archives. |
| 569 | var positionals = std.ArrayList([]const u8).init(arena); | 609 | var positionals = std.ArrayList([]const u8).init(arena); |
| ... | @@ -802,13 +842,35 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -802,13 +842,35 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 802 | try self.createDsoHandleAtom(); | 842 | try self.createDsoHandleAtom(); |
| 803 | try self.addCodeSignatureLC(); | 843 | try self.addCodeSignatureLC(); |
| 804 | 844 | ||
| 845 | // log.warn("locals:", .{}); | ||
| 846 | // for (self.locals.items) |sym, id| { | ||
| 847 | // log.warn(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym }); | ||
| 848 | // } | ||
| 849 | // log.warn("globals:", .{}); | ||
| 850 | // for (self.globals.items) |sym, id| { | ||
| 851 | // log.warn(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym }); | ||
| 852 | // } | ||
| 853 | // log.warn("undefs:", .{}); | ||
| 854 | // for (self.undefs.items) |sym, id| { | ||
| 855 | // log.warn(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym }); | ||
| 856 | // } | ||
| 857 | // { | ||
| 858 | // log.warn("resolver:", .{}); | ||
| 859 | // var it = self.symbol_resolver.iterator(); | ||
| 860 | // while (it.next()) |entry| { | ||
| 861 | // log.warn(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* }); | ||
| 862 | // } | ||
| 863 | // } | ||
| 864 | |||
| 805 | for (self.unresolved.keys()) |index| { | 865 | for (self.unresolved.keys()) |index| { |
| 806 | const sym = self.undefs.items[index]; | 866 | const sym = self.undefs.items[index]; |
| 807 | const sym_name = self.getString(sym.n_strx); | 867 | const sym_name = self.getString(sym.n_strx); |
| 808 | const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable; | 868 | const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable; |
| 809 | 869 | ||
| 810 | log.err("undefined reference to symbol '{s}'", .{sym_name}); | 870 | log.err("undefined reference to symbol '{s}'", .{sym_name}); |
| 811 | log.err(" first referenced in '{s}'", .{self.objects.items[resolv.file].name}); | 871 | if (resolv.file) |file| { |
| 872 | log.err(" first referenced in '{s}'", .{self.objects.items[file].name}); | ||
| 873 | } | ||
| 812 | } | 874 | } |
| 813 | if (self.unresolved.count() > 0) { | 875 | if (self.unresolved.count() > 0) { |
| 814 | return error.UndefinedSymbolReference; | 876 | return error.UndefinedSymbolReference; |
| ... | @@ -2349,7 +2411,9 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { | ... | @@ -2349,7 +2411,9 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { |
| 2349 | !(symbolIsWeakDef(global.*) or symbolIsPext(global.*))) | 2411 | !(symbolIsWeakDef(global.*) or symbolIsPext(global.*))) |
| 2350 | { | 2412 | { |
| 2351 | log.err("symbol '{s}' defined multiple times", .{sym_name}); | 2413 | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 2352 | log.err(" first definition in '{s}'", .{self.objects.items[resolv.file].name}); | 2414 | if (resolv.file) |file| { |
| 2415 | log.err(" first definition in '{s}'", .{self.objects.items[file].name}); | ||
| 2416 | } | ||
| 2353 | log.err(" next definition in '{s}'", .{object.name}); | 2417 | log.err(" next definition in '{s}'", .{object.name}); |
| 2354 | return error.MultipleSymbolDefinitions; | 2418 | return error.MultipleSymbolDefinitions; |
| 2355 | } else if (symbolIsWeakDef(sym) or symbolIsPext(sym)) continue; // Current symbol is weak, so skip it. | 2419 | } else if (symbolIsWeakDef(sym) or symbolIsPext(sym)) continue; // Current symbol is weak, so skip it. |
| ... | @@ -2632,10 +2696,10 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { | ... | @@ -2632,10 +2696,10 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2632 | const tracy = trace(@src()); | 2696 | const tracy = trace(@src()); |
| 2633 | defer tracy.end(); | 2697 | defer tracy.end(); |
| 2634 | 2698 | ||
| 2635 | var parsed_atoms = Object.ParsedAtoms.init(self.base.allocator); | 2699 | var parsed_atoms = std.AutoArrayHashMap(MatchingSection, *Atom).init(self.base.allocator); |
| 2636 | defer parsed_atoms.deinit(); | 2700 | defer parsed_atoms.deinit(); |
| 2637 | 2701 | ||
| 2638 | var first_atoms = Object.ParsedAtoms.init(self.base.allocator); | 2702 | var first_atoms = std.AutoArrayHashMap(MatchingSection, *Atom).init(self.base.allocator); |
| 2639 | defer first_atoms.deinit(); | 2703 | defer first_atoms.deinit(); |
| 2640 | 2704 | ||
| 2641 | var section_metadata = std.AutoHashMap(MatchingSection, struct { | 2705 | var section_metadata = std.AutoHashMap(MatchingSection, struct { |
| ... | @@ -2644,13 +2708,12 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { | ... | @@ -2644,13 +2708,12 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2644 | }).init(self.base.allocator); | 2708 | }).init(self.base.allocator); |
| 2645 | defer section_metadata.deinit(); | 2709 | defer section_metadata.deinit(); |
| 2646 | 2710 | ||
| 2647 | for (self.objects.items) |*object, object_id| { | 2711 | for (self.objects.items) |*object| { |
| 2648 | if (object.analyzed) continue; | 2712 | if (object.analyzed) continue; |
| 2649 | 2713 | ||
| 2650 | var atoms_in_objects = try object.parseIntoAtoms(self.base.allocator, @intCast(u16, object_id), self); | 2714 | try object.parseIntoAtoms(self.base.allocator, self); |
| 2651 | defer atoms_in_objects.deinit(); | ||
| 2652 | 2715 | ||
| 2653 | var it = atoms_in_objects.iterator(); | 2716 | var it = object.end_atoms.iterator(); |
| 2654 | while (it.next()) |entry| { | 2717 | while (it.next()) |entry| { |
| 2655 | const match = entry.key_ptr.*; | 2718 | const match = entry.key_ptr.*; |
| 2656 | const last_atom = entry.value_ptr.*; | 2719 | const last_atom = entry.value_ptr.*; |
| ... | @@ -3292,8 +3355,6 @@ pub fn updateDeclExports( | ... | @@ -3292,8 +3355,6 @@ pub fn updateDeclExports( |
| 3292 | decl: *Module.Decl, | 3355 | decl: *Module.Decl, |
| 3293 | exports: []const *Module.Export, | 3356 | exports: []const *Module.Export, |
| 3294 | ) !void { | 3357 | ) !void { |
| 3295 | // TODO If we are exporting with global linkage, check for already defined globals and flag | ||
| 3296 | // symbol duplicate/collision! | ||
| 3297 | if (build_options.skip_non_native and builtin.object_format != .macho) { | 3358 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 3298 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 3359 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 3299 | } | 3360 | } |
| ... | @@ -3303,7 +3364,7 @@ pub fn updateDeclExports( | ... | @@ -3303,7 +3364,7 @@ pub fn updateDeclExports( |
| 3303 | const tracy = trace(@src()); | 3364 | const tracy = trace(@src()); |
| 3304 | defer tracy.end(); | 3365 | defer tracy.end(); |
| 3305 | 3366 | ||
| 3306 | try self.globals.ensureCapacity(self.base.allocator, self.globals.items.len + exports.len); | 3367 | try self.globals.ensureUnusedCapacity(self.base.allocator, exports.len); |
| 3307 | if (decl.link.macho.local_sym_index == 0) return; | 3368 | if (decl.link.macho.local_sym_index == 0) return; |
| 3308 | const decl_sym = &self.locals.items[decl.link.macho.local_sym_index]; | 3369 | const decl_sym = &self.locals.items[decl.link.macho.local_sym_index]; |
| 3309 | 3370 | ||
| ... | @@ -3313,15 +3374,76 @@ pub fn updateDeclExports( | ... | @@ -3313,15 +3374,76 @@ pub fn updateDeclExports( |
| 3313 | 3374 | ||
| 3314 | if (exp.options.section) |section_name| { | 3375 | if (exp.options.section) |section_name| { |
| 3315 | if (!mem.eql(u8, section_name, "__text")) { | 3376 | if (!mem.eql(u8, section_name, "__text")) { |
| 3316 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.count() + 1); | 3377 | try module.failed_exports.putNoClobber( |
| 3317 | module.failed_exports.putAssumeCapacityNoClobber( | 3378 | module.gpa, |
| 3318 | exp, | 3379 | exp, |
| 3319 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: ExportOptions.section", .{}), | 3380 | try Module.ErrorMsg.create( |
| 3381 | self.base.allocator, | ||
| 3382 | decl.srcLoc(), | ||
| 3383 | "Unimplemented: ExportOptions.section", | ||
| 3384 | .{}, | ||
| 3385 | ), | ||
| 3320 | ); | 3386 | ); |
| 3321 | continue; | 3387 | continue; |
| 3322 | } | 3388 | } |
| 3323 | } | 3389 | } |
| 3324 | 3390 | ||
| 3391 | if (exp.options.linkage == .LinkOnce) { | ||
| 3392 | try module.failed_exports.putNoClobber( | ||
| 3393 | module.gpa, | ||
| 3394 | exp, | ||
| 3395 | try Module.ErrorMsg.create( | ||
| 3396 | self.base.allocator, | ||
| 3397 | decl.srcLoc(), | ||
| 3398 | "Unimplemented: GlobalLinkage.LinkOnce", | ||
| 3399 | .{}, | ||
| 3400 | ), | ||
| 3401 | ); | ||
| 3402 | continue; | ||
| 3403 | } | ||
| 3404 | |||
| 3405 | const is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak; | ||
| 3406 | const n_strx = try self.makeString(exp_name); | ||
| 3407 | if (self.symbol_resolver.getPtr(n_strx)) |resolv| { | ||
| 3408 | switch (resolv.where) { | ||
| 3409 | .global => { | ||
| 3410 | if (resolv.local_sym_index == decl.link.macho.local_sym_index) continue; | ||
| 3411 | |||
| 3412 | const sym = &self.globals.items[resolv.where_index]; | ||
| 3413 | |||
| 3414 | if (symbolIsTentative(sym.*)) { | ||
| 3415 | _ = self.tentatives.fetchSwapRemove(resolv.where_index); | ||
| 3416 | } else if (!is_weak and !(symbolIsWeakDef(sym.*) or symbolIsPext(sym.*))) { | ||
| 3417 | _ = try module.failed_exports.put( | ||
| 3418 | module.gpa, | ||
| 3419 | exp, | ||
| 3420 | try Module.ErrorMsg.create( | ||
| 3421 | self.base.allocator, | ||
| 3422 | decl.srcLoc(), | ||
| 3423 | \\LinkError: symbol '{s}' defined multiple times | ||
| 3424 | \\ first definition in '{s}' | ||
| 3425 | , | ||
| 3426 | .{ exp_name, self.objects.items[resolv.file.?].name }, | ||
| 3427 | ), | ||
| 3428 | ); | ||
| 3429 | continue; | ||
| 3430 | } else if (is_weak) continue; // Current symbol is weak, so skip it. | ||
| 3431 | |||
| 3432 | // Otherwise, update the resolver and the global symbol. | ||
| 3433 | sym.n_type = macho.N_SECT | macho.N_EXT; | ||
| 3434 | resolv.local_sym_index = decl.link.macho.local_sym_index; | ||
| 3435 | resolv.file = null; | ||
| 3436 | exp.link.macho.sym_index = resolv.where_index; | ||
| 3437 | |||
| 3438 | continue; | ||
| 3439 | }, | ||
| 3440 | .undef => { | ||
| 3441 | _ = self.unresolved.fetchSwapRemove(resolv.where_index); | ||
| 3442 | _ = self.symbol_resolver.remove(n_strx); | ||
| 3443 | }, | ||
| 3444 | } | ||
| 3445 | } | ||
| 3446 | |||
| 3325 | var n_type: u8 = macho.N_SECT | macho.N_EXT; | 3447 | var n_type: u8 = macho.N_SECT | macho.N_EXT; |
| 3326 | var n_desc: u16 = 0; | 3448 | var n_desc: u16 = 0; |
| 3327 | 3449 | ||
| ... | @@ -3339,14 +3461,7 @@ pub fn updateDeclExports( | ... | @@ -3339,14 +3461,7 @@ pub fn updateDeclExports( |
| 3339 | // Symbol's n_type is like for a symbol with strong linkage. | 3461 | // Symbol's n_type is like for a symbol with strong linkage. |
| 3340 | n_desc |= macho.N_WEAK_DEF; | 3462 | n_desc |= macho.N_WEAK_DEF; |
| 3341 | }, | 3463 | }, |
| 3342 | .LinkOnce => { | 3464 | else => unreachable, |
| 3343 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.count() + 1); | ||
| 3344 | module.failed_exports.putAssumeCapacityNoClobber( | ||
| 3345 | exp, | ||
| 3346 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: GlobalLinkage.LinkOnce", .{}), | ||
| 3347 | ); | ||
| 3348 | continue; | ||
| 3349 | }, | ||
| 3350 | } | 3465 | } |
| 3351 | 3466 | ||
| 3352 | const global_sym_index = if (exp.link.macho.sym_index) |i| i else blk: { | 3467 | const global_sym_index = if (exp.link.macho.sym_index) |i| i else blk: { |
| ... | @@ -3356,8 +3471,6 @@ pub fn updateDeclExports( | ... | @@ -3356,8 +3471,6 @@ pub fn updateDeclExports( |
| 3356 | }; | 3471 | }; |
| 3357 | break :blk i; | 3472 | break :blk i; |
| 3358 | }; | 3473 | }; |
| 3359 | |||
| 3360 | const n_strx = try self.makeString(exp_name); | ||
| 3361 | const sym = &self.globals.items[global_sym_index]; | 3474 | const sym = &self.globals.items[global_sym_index]; |
| 3362 | sym.* = .{ | 3475 | sym.* = .{ |
| 3363 | .n_strx = try self.makeString(exp_name), | 3476 | .n_strx = try self.makeString(exp_name), |
| ... | @@ -3368,12 +3481,11 @@ pub fn updateDeclExports( | ... | @@ -3368,12 +3481,11 @@ pub fn updateDeclExports( |
| 3368 | }; | 3481 | }; |
| 3369 | exp.link.macho.sym_index = global_sym_index; | 3482 | exp.link.macho.sym_index = global_sym_index; |
| 3370 | 3483 | ||
| 3371 | const resolv = try self.symbol_resolver.getOrPut(self.base.allocator, n_strx); | 3484 | try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{ |
| 3372 | resolv.value_ptr.* = .{ | ||
| 3373 | .where = .global, | 3485 | .where = .global, |
| 3374 | .where_index = global_sym_index, | 3486 | .where_index = global_sym_index, |
| 3375 | .local_sym_index = decl.link.macho.local_sym_index, | 3487 | .local_sym_index = decl.link.macho.local_sym_index, |
| 3376 | }; | 3488 | }); |
| 3377 | } | 3489 | } |
| 3378 | } | 3490 | } |
| 3379 | 3491 | ||
| ... | @@ -3381,8 +3493,11 @@ pub fn deleteExport(self: *MachO, exp: Export) void { | ... | @@ -3381,8 +3493,11 @@ pub fn deleteExport(self: *MachO, exp: Export) void { |
| 3381 | const sym_index = exp.sym_index orelse return; | 3493 | const sym_index = exp.sym_index orelse return; |
| 3382 | self.globals_free_list.append(self.base.allocator, sym_index) catch {}; | 3494 | self.globals_free_list.append(self.base.allocator, sym_index) catch {}; |
| 3383 | const global = &self.globals.items[sym_index]; | 3495 | const global = &self.globals.items[sym_index]; |
| 3384 | global.n_type = 0; | 3496 | log.debug("deleting export '{s}': {}", .{ self.getString(global.n_strx), global }); |
| 3385 | assert(self.symbol_resolver.remove(global.n_strx)); | 3497 | assert(self.symbol_resolver.remove(global.n_strx)); |
| 3498 | global.n_type = 0; | ||
| 3499 | global.n_strx = 0; | ||
| 3500 | global.n_value = 0; | ||
| 3386 | } | 3501 | } |
| 3387 | 3502 | ||
| 3388 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | 3503 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| ... | @@ -4403,6 +4518,7 @@ fn writeDyldInfoData(self: *MachO) !void { | ... | @@ -4403,6 +4518,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 4403 | const base_address = text_segment.inner.vmaddr; | 4518 | const base_address = text_segment.inner.vmaddr; |
| 4404 | 4519 | ||
| 4405 | for (self.globals.items) |sym| { | 4520 | for (self.globals.items) |sym| { |
| 4521 | if (sym.n_type == 0) continue; | ||
| 4406 | const sym_name = self.getString(sym.n_strx); | 4522 | const sym_name = self.getString(sym.n_strx); |
| 4407 | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); | 4523 | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); |
| 4408 | 4524 | ||
| ... | @@ -4655,7 +4771,7 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -4655,7 +4771,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 4655 | .n_value = object.mtime orelse 0, | 4771 | .n_value = object.mtime orelse 0, |
| 4656 | }); | 4772 | }); |
| 4657 | 4773 | ||
| 4658 | for (object.atoms.items) |atom| { | 4774 | for (object.contained_atoms.items) |atom| { |
| 4659 | if (atom.stab) |stab| { | 4775 | if (atom.stab) |stab| { |
| 4660 | const nlists = try stab.asNlists(atom.local_sym_index, self); | 4776 | const nlists = try stab.asNlists(atom.local_sym_index, self); |
| 4661 | defer self.base.allocator.free(nlists); | 4777 | defer self.base.allocator.free(nlists); |
src/link/MachO/Atom.zig+58-44| ... | @@ -645,7 +645,6 @@ const RelocContext = struct { | ... | @@ -645,7 +645,6 @@ const RelocContext = struct { |
| 645 | allocator: *Allocator, | 645 | allocator: *Allocator, |
| 646 | object: *Object, | 646 | object: *Object, |
| 647 | macho_file: *MachO, | 647 | macho_file: *MachO, |
| 648 | parsed_atoms: *Object.ParsedAtoms, | ||
| 649 | }; | 648 | }; |
| 650 | 649 | ||
| 651 | fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Relocation { | 650 | fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Relocation { |
| ... | @@ -877,12 +876,16 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC | ... | @@ -877,12 +876,16 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 877 | .sect = context.macho_file.got_section_index.?, | 876 | .sect = context.macho_file.got_section_index.?, |
| 878 | }; | 877 | }; |
| 879 | 878 | ||
| 880 | if (context.parsed_atoms.getPtr(match)) |last| { | 879 | if (!context.object.start_atoms.contains(match)) { |
| 880 | try context.object.start_atoms.putNoClobber(context.allocator, match, atom); | ||
| 881 | } | ||
| 882 | |||
| 883 | if (context.object.end_atoms.getPtr(match)) |last| { | ||
| 881 | last.*.next = atom; | 884 | last.*.next = atom; |
| 882 | atom.prev = last.*; | 885 | atom.prev = last.*; |
| 883 | last.* = atom; | 886 | last.* = atom; |
| 884 | } else { | 887 | } else { |
| 885 | try context.parsed_atoms.putNoClobber(match, atom); | 888 | try context.object.end_atoms.putNoClobber(context.allocator, match, atom); |
| 886 | } | 889 | } |
| 887 | } else if (parsed_rel.payload == .unsigned) { | 890 | } else if (parsed_rel.payload == .unsigned) { |
| 888 | switch (parsed_rel.where) { | 891 | switch (parsed_rel.where) { |
| ... | @@ -939,52 +942,63 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC | ... | @@ -939,52 +942,63 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 939 | if (parsed_rel.where != .undef) break :blk; | 942 | if (parsed_rel.where != .undef) break :blk; |
| 940 | if (context.macho_file.stubs_map.contains(parsed_rel.where_index)) break :blk; | 943 | if (context.macho_file.stubs_map.contains(parsed_rel.where_index)) break :blk; |
| 941 | 944 | ||
| 942 | const stub_helper_atom = try context.macho_file.createStubHelperAtom(); | ||
| 943 | const laptr_atom = try context.macho_file.createLazyPointerAtom( | ||
| 944 | stub_helper_atom.local_sym_index, | ||
| 945 | parsed_rel.where_index, | ||
| 946 | ); | ||
| 947 | const stub_atom = try context.macho_file.createStubAtom(laptr_atom.local_sym_index); | ||
| 948 | try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stub_atom); | ||
| 949 | // TODO clean this up! | 945 | // TODO clean this up! |
| 950 | if (context.parsed_atoms.getPtr(.{ | 946 | const stub_helper_atom = atom: { |
| 951 | .seg = context.macho_file.text_segment_cmd_index.?, | 947 | const atom = try context.macho_file.createStubHelperAtom(); |
| 952 | .sect = context.macho_file.stub_helper_section_index.?, | 948 | const match = MachO.MatchingSection{ |
| 953 | })) |last| { | ||
| 954 | last.*.next = stub_helper_atom; | ||
| 955 | stub_helper_atom.prev = last.*; | ||
| 956 | last.* = stub_helper_atom; | ||
| 957 | } else { | ||
| 958 | try context.parsed_atoms.putNoClobber(.{ | ||
| 959 | .seg = context.macho_file.text_segment_cmd_index.?, | 949 | .seg = context.macho_file.text_segment_cmd_index.?, |
| 960 | .sect = context.macho_file.stub_helper_section_index.?, | 950 | .sect = context.macho_file.stub_helper_section_index.?, |
| 961 | }, stub_helper_atom); | 951 | }; |
| 962 | } | 952 | if (!context.object.start_atoms.contains(match)) { |
| 963 | if (context.parsed_atoms.getPtr(.{ | 953 | try context.object.start_atoms.putNoClobber(context.allocator, match, atom); |
| 964 | .seg = context.macho_file.text_segment_cmd_index.?, | 954 | } |
| 965 | .sect = context.macho_file.stubs_section_index.?, | 955 | if (context.object.end_atoms.getPtr(match)) |last| { |
| 966 | })) |last| { | 956 | last.*.next = atom; |
| 967 | last.*.next = stub_atom; | 957 | atom.prev = last.*; |
| 968 | stub_atom.prev = last.*; | 958 | last.* = atom; |
| 969 | last.* = stub_atom; | 959 | } else { |
| 970 | } else { | 960 | try context.object.end_atoms.putNoClobber(context.allocator, match, atom); |
| 971 | try context.parsed_atoms.putNoClobber(.{ | 961 | } |
| 972 | .seg = context.macho_file.text_segment_cmd_index.?, | 962 | break :atom atom; |
| 973 | .sect = context.macho_file.stubs_section_index.?, | 963 | }; |
| 974 | }, stub_atom); | 964 | const laptr_atom = atom: { |
| 975 | } | 965 | const atom = try context.macho_file.createLazyPointerAtom( |
| 976 | if (context.parsed_atoms.getPtr(.{ | 966 | stub_helper_atom.local_sym_index, |
| 977 | .seg = context.macho_file.data_segment_cmd_index.?, | 967 | parsed_rel.where_index, |
| 978 | .sect = context.macho_file.la_symbol_ptr_section_index.?, | 968 | ); |
| 979 | })) |last| { | 969 | const match = MachO.MatchingSection{ |
| 980 | last.*.next = laptr_atom; | ||
| 981 | laptr_atom.prev = last.*; | ||
| 982 | last.* = laptr_atom; | ||
| 983 | } else { | ||
| 984 | try context.parsed_atoms.putNoClobber(.{ | ||
| 985 | .seg = context.macho_file.data_segment_cmd_index.?, | 970 | .seg = context.macho_file.data_segment_cmd_index.?, |
| 986 | .sect = context.macho_file.la_symbol_ptr_section_index.?, | 971 | .sect = context.macho_file.la_symbol_ptr_section_index.?, |
| 987 | }, laptr_atom); | 972 | }; |
| 973 | if (!context.object.start_atoms.contains(match)) { | ||
| 974 | try context.object.start_atoms.putNoClobber(context.allocator, match, atom); | ||
| 975 | } | ||
| 976 | if (context.object.end_atoms.getPtr(match)) |last| { | ||
| 977 | last.*.next = atom; | ||
| 978 | atom.prev = last.*; | ||
| 979 | last.* = atom; | ||
| 980 | } else { | ||
| 981 | try context.object.end_atoms.putNoClobber(context.allocator, match, atom); | ||
| 982 | } | ||
| 983 | break :atom atom; | ||
| 984 | }; | ||
| 985 | { | ||
| 986 | const atom = try context.macho_file.createStubAtom(laptr_atom.local_sym_index); | ||
| 987 | const match = MachO.MatchingSection{ | ||
| 988 | .seg = context.macho_file.text_segment_cmd_index.?, | ||
| 989 | .sect = context.macho_file.stubs_section_index.?, | ||
| 990 | }; | ||
| 991 | if (!context.object.start_atoms.contains(match)) { | ||
| 992 | try context.object.start_atoms.putNoClobber(context.allocator, match, atom); | ||
| 993 | } | ||
| 994 | if (context.object.end_atoms.getPtr(match)) |last| { | ||
| 995 | last.*.next = atom; | ||
| 996 | atom.prev = last.*; | ||
| 997 | last.* = atom; | ||
| 998 | } else { | ||
| 999 | try context.object.end_atoms.putNoClobber(context.allocator, match, atom); | ||
| 1000 | } | ||
| 1001 | try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, atom); | ||
| 988 | } | 1002 | } |
| 989 | } | 1003 | } |
| 990 | } | 1004 | } |
src/link/MachO/Object.zig+160-249| ... | @@ -31,14 +31,12 @@ header: ?macho.mach_header_64 = null, | ... | @@ -31,14 +31,12 @@ header: ?macho.mach_header_64 = null, |
| 31 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 31 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 32 | 32 | ||
| 33 | segment_cmd_index: ?u16 = null, | 33 | segment_cmd_index: ?u16 = null, |
| 34 | text_section_index: ?u16 = null, | ||
| 34 | symtab_cmd_index: ?u16 = null, | 35 | symtab_cmd_index: ?u16 = null, |
| 35 | dysymtab_cmd_index: ?u16 = null, | 36 | dysymtab_cmd_index: ?u16 = null, |
| 36 | build_version_cmd_index: ?u16 = null, | 37 | build_version_cmd_index: ?u16 = null, |
| 37 | data_in_code_cmd_index: ?u16 = null, | 38 | data_in_code_cmd_index: ?u16 = null, |
| 38 | 39 | ||
| 39 | text_section_index: ?u16 = null, | ||
| 40 | mod_init_func_section_index: ?u16 = null, | ||
| 41 | |||
| 42 | // __DWARF segment sections | 40 | // __DWARF segment sections |
| 43 | dwarf_debug_info_index: ?u16 = null, | 41 | dwarf_debug_info_index: ?u16 = null, |
| 44 | dwarf_debug_abbrev_index: ?u16 = null, | 42 | dwarf_debug_abbrev_index: ?u16 = null, |
| ... | @@ -56,7 +54,9 @@ tu_name: ?[]const u8 = null, | ... | @@ -56,7 +54,9 @@ tu_name: ?[]const u8 = null, |
| 56 | tu_comp_dir: ?[]const u8 = null, | 54 | tu_comp_dir: ?[]const u8 = null, |
| 57 | mtime: ?u64 = null, | 55 | mtime: ?u64 = null, |
| 58 | 56 | ||
| 59 | atoms: std.ArrayListUnmanaged(*Atom) = .{}, | 57 | contained_atoms: std.ArrayListUnmanaged(*Atom) = .{}, |
| 58 | start_atoms: std.AutoHashMapUnmanaged(MachO.MatchingSection, *Atom) = .{}, | ||
| 59 | end_atoms: std.AutoHashMapUnmanaged(MachO.MatchingSection, *Atom) = .{}, | ||
| 60 | sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{}, | 60 | sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{}, |
| 61 | 61 | ||
| 62 | // TODO symbol mapping and its inverse can probably be simple arrays | 62 | // TODO symbol mapping and its inverse can probably be simple arrays |
| ... | @@ -138,12 +138,15 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { | ... | @@ -138,12 +138,15 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { |
| 138 | self.data_in_code_entries.deinit(allocator); | 138 | self.data_in_code_entries.deinit(allocator); |
| 139 | self.symtab.deinit(allocator); | 139 | self.symtab.deinit(allocator); |
| 140 | self.strtab.deinit(allocator); | 140 | self.strtab.deinit(allocator); |
| 141 | self.atoms.deinit(allocator); | ||
| 142 | self.sections_as_symbols.deinit(allocator); | 141 | self.sections_as_symbols.deinit(allocator); |
| 143 | self.symbol_mapping.deinit(allocator); | 142 | self.symbol_mapping.deinit(allocator); |
| 144 | self.reverse_symbol_mapping.deinit(allocator); | 143 | self.reverse_symbol_mapping.deinit(allocator); |
| 145 | allocator.free(self.name); | 144 | allocator.free(self.name); |
| 146 | 145 | ||
| 146 | self.contained_atoms.deinit(allocator); | ||
| 147 | self.start_atoms.deinit(allocator); | ||
| 148 | self.end_atoms.deinit(allocator); | ||
| 149 | |||
| 147 | if (self.debug_info) |*db| { | 150 | if (self.debug_info) |*db| { |
| 148 | db.deinit(allocator); | 151 | db.deinit(allocator); |
| 149 | } | 152 | } |
| ... | @@ -157,6 +160,67 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { | ... | @@ -157,6 +160,67 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { |
| 157 | } | 160 | } |
| 158 | } | 161 | } |
| 159 | 162 | ||
| 163 | pub fn free(self: *Object, allocator: *Allocator, macho_file: *MachO) void { | ||
| 164 | log.debug("freeObject {*}", .{self}); | ||
| 165 | |||
| 166 | var it = self.end_atoms.iterator(); | ||
| 167 | while (it.next()) |entry| { | ||
| 168 | const match = entry.key_ptr.*; | ||
| 169 | const first_atom = self.start_atoms.get(match).?; | ||
| 170 | const last_atom = entry.value_ptr.*; | ||
| 171 | var atom = first_atom; | ||
| 172 | |||
| 173 | while (true) { | ||
| 174 | if (atom.local_sym_index != 0) { | ||
| 175 | macho_file.locals_free_list.append(allocator, atom.local_sym_index) catch {}; | ||
| 176 | const local = &macho_file.locals.items[atom.local_sym_index]; | ||
| 177 | local.n_type = 0; | ||
| 178 | atom.local_sym_index = 0; | ||
| 179 | } | ||
| 180 | if (atom == last_atom) { | ||
| 181 | break; | ||
| 182 | } | ||
| 183 | if (atom.next) |next| { | ||
| 184 | atom = next; | ||
| 185 | } else break; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | self.freeAtoms(macho_file); | ||
| 190 | } | ||
| 191 | |||
| 192 | fn freeAtoms(self: *Object, macho_file: *MachO) void { | ||
| 193 | var it = self.end_atoms.iterator(); | ||
| 194 | while (it.next()) |entry| { | ||
| 195 | const match = entry.key_ptr.*; | ||
| 196 | var first_atom: *Atom = self.start_atoms.get(match).?; | ||
| 197 | var last_atom: *Atom = entry.value_ptr.*; | ||
| 198 | |||
| 199 | if (macho_file.atoms.getPtr(match)) |atom_ptr| { | ||
| 200 | if (atom_ptr.* == last_atom) { | ||
| 201 | if (first_atom.prev) |prev| { | ||
| 202 | // TODO shrink the section size here | ||
| 203 | atom_ptr.* = prev; | ||
| 204 | } else { | ||
| 205 | _ = macho_file.atoms.fetchRemove(match); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | if (first_atom.prev) |prev| { | ||
| 211 | prev.next = last_atom.next; | ||
| 212 | } else { | ||
| 213 | first_atom.prev = null; | ||
| 214 | } | ||
| 215 | |||
| 216 | if (last_atom.next) |next| { | ||
| 217 | next.prev = last_atom.prev; | ||
| 218 | } else { | ||
| 219 | last_atom.next = null; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 160 | pub fn parse(self: *Object, allocator: *Allocator, target: std.Target) !void { | 224 | pub fn parse(self: *Object, allocator: *Allocator, target: std.Target) !void { |
| 161 | const reader = self.file.reader(); | 225 | const reader = self.file.reader(); |
| 162 | if (self.file_offset) |offset| { | 226 | if (self.file_offset) |offset| { |
| ... | @@ -226,10 +290,6 @@ pub fn readLoadCommands(self: *Object, allocator: *Allocator, reader: anytype) ! | ... | @@ -226,10 +290,6 @@ pub fn readLoadCommands(self: *Object, allocator: *Allocator, reader: anytype) ! |
| 226 | if (mem.eql(u8, sectname, "__text")) { | 290 | if (mem.eql(u8, sectname, "__text")) { |
| 227 | self.text_section_index = index; | 291 | self.text_section_index = index; |
| 228 | } | 292 | } |
| 229 | } else if (mem.eql(u8, segname, "__DATA")) { | ||
| 230 | if (mem.eql(u8, sectname, "__mod_init_func")) { | ||
| 231 | self.mod_init_func_section_index = index; | ||
| 232 | } | ||
| 233 | } | 293 | } |
| 234 | 294 | ||
| 235 | sect.offset += offset; | 295 | sect.offset += offset; |
| ... | @@ -320,7 +380,6 @@ const Context = struct { | ... | @@ -320,7 +380,6 @@ const Context = struct { |
| 320 | object: *Object, | 380 | object: *Object, |
| 321 | macho_file: *MachO, | 381 | macho_file: *MachO, |
| 322 | match: MachO.MatchingSection, | 382 | match: MachO.MatchingSection, |
| 323 | parsed_atoms: *ParsedAtoms, | ||
| 324 | }; | 383 | }; |
| 325 | 384 | ||
| 326 | const AtomParser = struct { | 385 | const AtomParser = struct { |
| ... | @@ -437,7 +496,6 @@ const AtomParser = struct { | ... | @@ -437,7 +496,6 @@ const AtomParser = struct { |
| 437 | .allocator = context.allocator, | 496 | .allocator = context.allocator, |
| 438 | .object = context.object, | 497 | .object = context.object, |
| 439 | .macho_file = context.macho_file, | 498 | .macho_file = context.macho_file, |
| 440 | .parsed_atoms = context.parsed_atoms, | ||
| 441 | }); | 499 | }); |
| 442 | 500 | ||
| 443 | if (context.macho_file.has_dices) { | 501 | if (context.macho_file.has_dices) { |
| ... | @@ -463,18 +521,10 @@ const AtomParser = struct { | ... | @@ -463,18 +521,10 @@ const AtomParser = struct { |
| 463 | } | 521 | } |
| 464 | }; | 522 | }; |
| 465 | 523 | ||
| 466 | pub const ParsedAtoms = std.AutoHashMap(MachO.MatchingSection, *Atom); | 524 | pub fn parseIntoAtoms(self: *Object, allocator: *Allocator, macho_file: *MachO) !void { |
| 467 | |||
| 468 | pub fn parseIntoAtoms( | ||
| 469 | self: *Object, | ||
| 470 | allocator: *Allocator, | ||
| 471 | object_id: u16, | ||
| 472 | macho_file: *MachO, | ||
| 473 | ) !ParsedAtoms { | ||
| 474 | const tracy = trace(@src()); | 525 | const tracy = trace(@src()); |
| 475 | defer tracy.end(); | 526 | defer tracy.end(); |
| 476 | 527 | ||
| 477 | var parsed_atoms = ParsedAtoms.init(allocator); | ||
| 478 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | 528 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; |
| 479 | 529 | ||
| 480 | log.debug("analysing {s}", .{self.name}); | 530 | log.debug("analysing {s}", .{self.name}); |
| ... | @@ -540,16 +590,6 @@ pub fn parseIntoAtoms( | ... | @@ -540,16 +590,6 @@ pub fn parseIntoAtoms( |
| 540 | // Symbols within this section only. | 590 | // Symbols within this section only. |
| 541 | const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect); | 591 | const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect); |
| 542 | 592 | ||
| 543 | // TODO rewrite and re-enable dead-code stripping optimisation. I think it might make sense | ||
| 544 | // to do this in a standalone pass after we parse the sections as atoms. | ||
| 545 | // In release mode, if the object file was generated with dead code stripping optimisations, | ||
| 546 | // note it now and parse sections as atoms. | ||
| 547 | // const is_splittable = blk: { | ||
| 548 | // if (macho_file.base.options.optimize_mode == .Debug) break :blk false; | ||
| 549 | // break :blk self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; | ||
| 550 | // }; | ||
| 551 | const is_splittable = false; | ||
| 552 | |||
| 553 | macho_file.has_dices = macho_file.has_dices or blk: { | 593 | macho_file.has_dices = macho_file.has_dices or blk: { |
| 554 | if (self.text_section_index) |index| { | 594 | if (self.text_section_index) |index| { |
| 555 | if (index != id) break :blk false; | 595 | if (index != id) break :blk false; |
| ... | @@ -560,237 +600,108 @@ pub fn parseIntoAtoms( | ... | @@ -560,237 +600,108 @@ pub fn parseIntoAtoms( |
| 560 | }; | 600 | }; |
| 561 | macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null; | 601 | macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null; |
| 562 | 602 | ||
| 563 | next: { | 603 | // Since there is no symbol to refer to this atom, we create |
| 564 | if (is_splittable) atoms: { | 604 | // a temp one, unless we already did that when working out the relocations |
| 565 | if (filtered_nlists.len == 0) break :atoms; | 605 | // of other atoms. |
| 566 | 606 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ | |
| 567 | // If the first nlist does not match the start of the section, | 607 | self.name, |
| 568 | // then we need to encapsulate the memory range [section start, first symbol) | 608 | segmentName(sect), |
| 569 | // as a temporary symbol and insert the matching Atom. | 609 | sectionName(sect), |
| 570 | const first_nlist = filtered_nlists[0].nlist; | 610 | }); |
| 571 | if (first_nlist.n_value > sect.addr) { | 611 | defer allocator.free(sym_name); |
| 572 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ | 612 | |
| 573 | self.name, | 613 | const atom_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 574 | segmentName(sect), | 614 | const atom_local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 575 | sectionName(sect), | 615 | try macho_file.locals.append(allocator, .{ |
| 576 | }); | 616 | .n_strx = try macho_file.makeString(sym_name), |
| 577 | defer allocator.free(sym_name); | 617 | .n_type = macho.N_SECT, |
| 578 | 618 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), | |
| 579 | const atom_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { | 619 | .n_desc = 0, |
| 580 | const atom_local_sym_index = @intCast(u32, macho_file.locals.items.len); | 620 | .n_value = 0, |
| 581 | try macho_file.locals.append(allocator, .{ | 621 | }); |
| 582 | .n_strx = try macho_file.makeString(sym_name), | 622 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index); |
| 583 | .n_type = macho.N_SECT, | 623 | break :blk atom_local_sym_index; |
| 584 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), | 624 | }; |
| 585 | .n_desc = 0, | 625 | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, sect.size, sect.@"align"); |
| 586 | .n_value = 0, | ||
| 587 | }); | ||
| 588 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index); | ||
| 589 | break :blk atom_local_sym_index; | ||
| 590 | }; | ||
| 591 | const atom_code = code[0 .. first_nlist.n_value - sect.addr]; | ||
| 592 | const atom_size = atom_code.len; | ||
| 593 | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, atom_size, sect.@"align"); | ||
| 594 | |||
| 595 | const is_zerofill = blk: { | ||
| 596 | const section_type = commands.sectionType(sect); | ||
| 597 | break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; | ||
| 598 | }; | ||
| 599 | if (!is_zerofill) { | ||
| 600 | mem.copy(u8, atom.code.items, atom_code); | ||
| 601 | } | ||
| 602 | |||
| 603 | try atom.parseRelocs(relocs, .{ | ||
| 604 | .base_addr = sect.addr, | ||
| 605 | .base_offset = 0, | ||
| 606 | .allocator = allocator, | ||
| 607 | .object = self, | ||
| 608 | .macho_file = macho_file, | ||
| 609 | .parsed_atoms = &parsed_atoms, | ||
| 610 | }); | ||
| 611 | |||
| 612 | if (macho_file.has_dices) { | ||
| 613 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + atom_size); | ||
| 614 | try atom.dices.ensureTotalCapacity(allocator, dices.len); | ||
| 615 | |||
| 616 | for (dices) |dice| { | ||
| 617 | atom.dices.appendAssumeCapacity(.{ | ||
| 618 | .offset = dice.offset - try math.cast(u32, sect.addr), | ||
| 619 | .length = dice.length, | ||
| 620 | .kind = dice.kind, | ||
| 621 | }); | ||
| 622 | } | ||
| 623 | } | ||
| 624 | |||
| 625 | if (parsed_atoms.getPtr(match)) |last| { | ||
| 626 | last.*.next = atom; | ||
| 627 | atom.prev = last.*; | ||
| 628 | last.* = atom; | ||
| 629 | } else { | ||
| 630 | try parsed_atoms.putNoClobber(match, atom); | ||
| 631 | } | ||
| 632 | try self.atoms.append(allocator, atom); | ||
| 633 | } | ||
| 634 | |||
| 635 | var parser = AtomParser{ | ||
| 636 | .section = sect, | ||
| 637 | .code = code, | ||
| 638 | .relocs = relocs, | ||
| 639 | .nlists = filtered_nlists, | ||
| 640 | }; | ||
| 641 | |||
| 642 | while (try parser.next(.{ | ||
| 643 | .allocator = allocator, | ||
| 644 | .object = self, | ||
| 645 | .macho_file = macho_file, | ||
| 646 | .match = match, | ||
| 647 | .parsed_atoms = &parsed_atoms, | ||
| 648 | })) |atom| { | ||
| 649 | const sym = macho_file.locals.items[atom.local_sym_index]; | ||
| 650 | const is_ext = blk: { | ||
| 651 | const orig_sym_id = self.reverse_symbol_mapping.get(atom.local_sym_index) orelse unreachable; | ||
| 652 | break :blk MachO.symbolIsExt(self.symtab.items[orig_sym_id]); | ||
| 653 | }; | ||
| 654 | if (is_ext) { | ||
| 655 | if (macho_file.symbol_resolver.get(sym.n_strx)) |resolv| { | ||
| 656 | assert(resolv.where == .global); | ||
| 657 | if (resolv.file != object_id) { | ||
| 658 | log.debug("deduping definition of {s} in {s}", .{ | ||
| 659 | macho_file.getString(sym.n_strx), | ||
| 660 | self.name, | ||
| 661 | }); | ||
| 662 | log.debug(" already defined in {s}", .{ | ||
| 663 | macho_file.objects.items[resolv.file].name, | ||
| 664 | }); | ||
| 665 | continue; | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } | ||
| 669 | 626 | ||
| 670 | if (sym.n_value == sect.addr) { | 627 | const is_zerofill = blk: { |
| 671 | if (self.sections_as_symbols.get(sect_id)) |alias| { | 628 | const section_type = commands.sectionType(sect); |
| 672 | // In x86_64 relocs, it can so happen that the compiler refers to the same | 629 | break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; |
| 673 | // atom by both the actual assigned symbol and the start of the section. In this | 630 | }; |
| 674 | // case, we need to link the two together so add an alias. | 631 | if (!is_zerofill) { |
| 675 | try atom.aliases.append(allocator, alias); | 632 | mem.copy(u8, atom.code.items, code); |
| 676 | } | 633 | } |
| 677 | } | ||
| 678 | 634 | ||
| 679 | if (parsed_atoms.getPtr(match)) |last| { | 635 | try atom.parseRelocs(relocs, .{ |
| 680 | last.*.next = atom; | 636 | .base_addr = sect.addr, |
| 681 | atom.prev = last.*; | 637 | .base_offset = 0, |
| 682 | last.* = atom; | 638 | .allocator = allocator, |
| 683 | } else { | 639 | .object = self, |
| 684 | try parsed_atoms.putNoClobber(match, atom); | 640 | .macho_file = macho_file, |
| 685 | } | 641 | }); |
| 686 | try self.atoms.append(allocator, atom); | ||
| 687 | } | ||
| 688 | 642 | ||
| 689 | break :next; | 643 | if (macho_file.has_dices) { |
| 690 | } | 644 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size); |
| 645 | try atom.dices.ensureTotalCapacity(allocator, dices.len); | ||
| 691 | 646 | ||
| 692 | // Since there is no symbol to refer to this atom, we create | 647 | for (dices) |dice| { |
| 693 | // a temp one, unless we already did that when working out the relocations | 648 | atom.dices.appendAssumeCapacity(.{ |
| 694 | // of other atoms. | 649 | .offset = dice.offset - try math.cast(u32, sect.addr), |
| 695 | const sym_name = try std.fmt.allocPrint(allocator, "l_{s}_{s}_{s}", .{ | 650 | .length = dice.length, |
| 696 | self.name, | 651 | .kind = dice.kind, |
| 697 | segmentName(sect), | ||
| 698 | sectionName(sect), | ||
| 699 | }); | ||
| 700 | defer allocator.free(sym_name); | ||
| 701 | |||
| 702 | const atom_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { | ||
| 703 | const atom_local_sym_index = @intCast(u32, macho_file.locals.items.len); | ||
| 704 | try macho_file.locals.append(allocator, .{ | ||
| 705 | .n_strx = try macho_file.makeString(sym_name), | ||
| 706 | .n_type = macho.N_SECT, | ||
| 707 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), | ||
| 708 | .n_desc = 0, | ||
| 709 | .n_value = 0, | ||
| 710 | }); | 652 | }); |
| 711 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index); | ||
| 712 | break :blk atom_local_sym_index; | ||
| 713 | }; | ||
| 714 | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, sect.size, sect.@"align"); | ||
| 715 | |||
| 716 | const is_zerofill = blk: { | ||
| 717 | const section_type = commands.sectionType(sect); | ||
| 718 | break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; | ||
| 719 | }; | ||
| 720 | if (!is_zerofill) { | ||
| 721 | mem.copy(u8, atom.code.items, code); | ||
| 722 | } | ||
| 723 | |||
| 724 | try atom.parseRelocs(relocs, .{ | ||
| 725 | .base_addr = sect.addr, | ||
| 726 | .base_offset = 0, | ||
| 727 | .allocator = allocator, | ||
| 728 | .object = self, | ||
| 729 | .macho_file = macho_file, | ||
| 730 | .parsed_atoms = &parsed_atoms, | ||
| 731 | }); | ||
| 732 | |||
| 733 | if (macho_file.has_dices) { | ||
| 734 | const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size); | ||
| 735 | try atom.dices.ensureTotalCapacity(allocator, dices.len); | ||
| 736 | |||
| 737 | for (dices) |dice| { | ||
| 738 | atom.dices.appendAssumeCapacity(.{ | ||
| 739 | .offset = dice.offset - try math.cast(u32, sect.addr), | ||
| 740 | .length = dice.length, | ||
| 741 | .kind = dice.kind, | ||
| 742 | }); | ||
| 743 | } | ||
| 744 | } | 653 | } |
| 654 | } | ||
| 745 | 655 | ||
| 746 | // Since this is atom gets a helper local temporary symbol that didn't exist | 656 | // Since this is atom gets a helper local temporary symbol that didn't exist |
| 747 | // in the object file which encompasses the entire section, we need traverse | 657 | // in the object file which encompasses the entire section, we need traverse |
| 748 | // the filtered symbols and note which symbol is contained within so that | 658 | // the filtered symbols and note which symbol is contained within so that |
| 749 | // we can properly allocate addresses down the line. | 659 | // we can properly allocate addresses down the line. |
| 750 | // While we're at it, we need to update segment,section mapping of each symbol too. | 660 | // While we're at it, we need to update segment,section mapping of each symbol too. |
| 751 | try atom.contained.ensureTotalCapacity(allocator, filtered_nlists.len); | 661 | try atom.contained.ensureTotalCapacity(allocator, filtered_nlists.len); |
| 752 | 662 | ||
| 753 | for (filtered_nlists) |nlist_with_index| { | 663 | for (filtered_nlists) |nlist_with_index| { |
| 754 | const nlist = nlist_with_index.nlist; | 664 | const nlist = nlist_with_index.nlist; |
| 755 | const local_sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable; | 665 | const local_sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable; |
| 756 | const local = &macho_file.locals.items[local_sym_index]; | 666 | const local = &macho_file.locals.items[local_sym_index]; |
| 757 | local.n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1); | 667 | local.n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1); |
| 758 | 668 | ||
| 759 | const stab: ?Atom.Stab = if (self.debug_info) |di| blk: { | 669 | const stab: ?Atom.Stab = if (self.debug_info) |di| blk: { |
| 760 | // TODO there has to be a better to handle this. | 670 | // TODO there has to be a better to handle this. |
| 761 | for (di.inner.func_list.items) |func| { | 671 | for (di.inner.func_list.items) |func| { |
| 762 | if (func.pc_range) |range| { | 672 | if (func.pc_range) |range| { |
| 763 | if (nlist.n_value >= range.start and nlist.n_value < range.end) { | 673 | if (nlist.n_value >= range.start and nlist.n_value < range.end) { |
| 764 | break :blk Atom.Stab{ | 674 | break :blk Atom.Stab{ |
| 765 | .function = range.end - range.start, | 675 | .function = range.end - range.start, |
| 766 | }; | 676 | }; |
| 767 | } | ||
| 768 | } | 677 | } |
| 769 | } | 678 | } |
| 770 | // TODO | 679 | } |
| 771 | // if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; | 680 | // TODO |
| 772 | break :blk .static; | 681 | // if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; |
| 773 | } else null; | 682 | break :blk .static; |
| 774 | 683 | } else null; | |
| 775 | atom.contained.appendAssumeCapacity(.{ | 684 | |
| 776 | .local_sym_index = local_sym_index, | 685 | atom.contained.appendAssumeCapacity(.{ |
| 777 | .offset = nlist.n_value - sect.addr, | 686 | .local_sym_index = local_sym_index, |
| 778 | .stab = stab, | 687 | .offset = nlist.n_value - sect.addr, |
| 779 | }); | 688 | .stab = stab, |
| 780 | } | 689 | }); |
| 690 | } | ||
| 781 | 691 | ||
| 782 | if (parsed_atoms.getPtr(match)) |last| { | 692 | if (!self.start_atoms.contains(match)) { |
| 783 | last.*.next = atom; | 693 | try self.start_atoms.putNoClobber(allocator, match, atom); |
| 784 | atom.prev = last.*; | ||
| 785 | last.* = atom; | ||
| 786 | } else { | ||
| 787 | try parsed_atoms.putNoClobber(match, atom); | ||
| 788 | } | ||
| 789 | try self.atoms.append(allocator, atom); | ||
| 790 | } | 694 | } |
| 791 | } | ||
| 792 | 695 | ||
| 793 | return parsed_atoms; | 696 | if (self.end_atoms.getPtr(match)) |last| { |
| 697 | last.*.next = atom; | ||
| 698 | atom.prev = last.*; | ||
| 699 | last.* = atom; | ||
| 700 | } else { | ||
| 701 | try self.end_atoms.putNoClobber(allocator, match, atom); | ||
| 702 | } | ||
| 703 | try self.contained_atoms.append(allocator, atom); | ||
| 704 | } | ||
| 794 | } | 705 | } |
| 795 | 706 | ||
| 796 | fn parseSymtab(self: *Object, allocator: *Allocator) !void { | 707 | fn parseSymtab(self: *Object, allocator: *Allocator) !void { |