| author | |
| committer | |
| log | ee6e25bc13b3f23b5f2fd0c8b57f0d115c239fc2 |
| tree | 592e8d3db7226c8dbf79af9a3a0c0c1eb1b7b97b |
| parent | 2b3bda43e352152f0150bf2e795419cf1bcfcd90 |
5 files changed, 216 insertions(+), 178 deletions(-)
src/link/MachO/Archive.zig+6| ... | ... | @@ -81,6 +81,11 @@ const ar_hdr = extern struct { |
| 81 | 81 | } |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | fn date(self: ar_hdr) !u64 { | |
| 85 | const value = getValue(&self.ar_date); | |
| 86 | return std.fmt.parseInt(u64, value, 10); | |
| 87 | } | |
| 88 | ||
| 84 | 89 | fn size(self: ar_hdr) !u32 { |
| 85 | 90 | const value = getValue(&self.ar_size); |
| 86 | 91 | return std.fmt.parseInt(u32, value, 10); |
| ... | ... | @@ -264,6 +269,7 @@ pub fn parseObject(self: Archive, offset: u32) !*Object { |
| 264 | 269 | .file = try fs.cwd().openFile(self.name.?, .{}), |
| 265 | 270 | .name = name, |
| 266 | 271 | .file_offset = @intCast(u32, try reader.context.getPos()), |
| 272 | .mtime = try self.header.?.date(), | |
| 267 | 273 | }; |
| 268 | 274 | try object.parse(); |
| 269 | 275 | try reader.context.seekTo(0); |
src/link/MachO/Dylib.zig-1| ... | ... | @@ -18,7 +18,6 @@ const LibStub = @import("../tapi.zig").LibStub; |
| 18 | 18 | usingnamespace @import("commands.zig"); |
| 19 | 19 | |
| 20 | 20 | allocator: *Allocator, |
| 21 | ||
| 22 | 21 | arch: ?Arch = null, |
| 23 | 22 | header: ?macho.mach_header_64 = null, |
| 24 | 23 | file: ?fs.File = null, |
src/link/MachO/Object.zig+55-14| ... | ... | @@ -24,6 +24,7 @@ header: ?macho.mach_header_64 = null, |
| 24 | 24 | file: ?fs.File = null, |
| 25 | 25 | file_offset: ?u32 = null, |
| 26 | 26 | name: ?[]const u8 = null, |
| 27 | mtime: ?u64 = null, | |
| 27 | 28 | |
| 28 | 29 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 29 | 30 | sections: std.ArrayListUnmanaged(Section) = .{}, |
| ... | ... | @@ -45,12 +46,10 @@ dwarf_debug_line_index: ?u16 = null, |
| 45 | 46 | dwarf_debug_ranges_index: ?u16 = null, |
| 46 | 47 | |
| 47 | 48 | symbols: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 49 | stabs: std.ArrayListUnmanaged(*Symbol) = .{}, | |
| 48 | 50 | initializers: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 49 | 51 | data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, |
| 50 | 52 | |
| 51 | tu_path: ?[]const u8 = null, | |
| 52 | tu_mtime: ?u64 = null, | |
| 53 | ||
| 54 | 53 | pub const Section = struct { |
| 55 | 54 | inner: macho.section_64, |
| 56 | 55 | code: []u8, |
| ... | ... | @@ -223,16 +222,18 @@ pub fn deinit(self: *Object) void { |
| 223 | 222 | } |
| 224 | 223 | self.symbols.deinit(self.allocator); |
| 225 | 224 | |
| 225 | for (self.stabs.items) |stab| { | |
| 226 | stab.deinit(self.allocator); | |
| 227 | self.allocator.destroy(stab); | |
| 228 | } | |
| 229 | self.stabs.deinit(self.allocator); | |
| 230 | ||
| 226 | 231 | self.data_in_code_entries.deinit(self.allocator); |
| 227 | 232 | self.initializers.deinit(self.allocator); |
| 228 | 233 | |
| 229 | 234 | if (self.name) |n| { |
| 230 | 235 | self.allocator.free(n); |
| 231 | 236 | } |
| 232 | ||
| 233 | if (self.tu_path) |tu_path| { | |
| 234 | self.allocator.free(tu_path); | |
| 235 | } | |
| 236 | 237 | } |
| 237 | 238 | |
| 238 | 239 | pub fn closeFile(self: Object) void { |
| ... | ... | @@ -484,11 +485,33 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 484 | 485 | const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name); |
| 485 | 486 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); |
| 486 | 487 | |
| 487 | self.tu_path = try std.fs.path.join(self.allocator, &[_][]const u8{ comp_dir, name }); | |
| 488 | self.tu_mtime = mtime: { | |
| 489 | const stat = try self.file.?.stat(); | |
| 490 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); | |
| 491 | }; | |
| 488 | if (self.mtime == null) { | |
| 489 | self.mtime = mtime: { | |
| 490 | const file = self.file orelse break :mtime 0; | |
| 491 | const stat = file.stat() catch break :mtime 0; | |
| 492 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); | |
| 493 | }; | |
| 494 | } | |
| 495 | ||
| 496 | try self.stabs.ensureUnusedCapacity(self.allocator, self.symbols.items.len + 4); | |
| 497 | ||
| 498 | // Current dir | |
| 499 | self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, comp_dir, .{ | |
| 500 | .kind = .so, | |
| 501 | .file = self, | |
| 502 | })); | |
| 503 | ||
| 504 | // Artifact name | |
| 505 | self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, name, .{ | |
| 506 | .kind = .so, | |
| 507 | .file = self, | |
| 508 | })); | |
| 509 | ||
| 510 | // Path to object file with debug info | |
| 511 | self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, self.name.?, .{ | |
| 512 | .kind = .oso, | |
| 513 | .file = self, | |
| 514 | })); | |
| 492 | 515 | |
| 493 | 516 | for (self.symbols.items) |sym| { |
| 494 | 517 | if (sym.cast(Symbol.Regular)) |reg| { |
| ... | ... | @@ -500,7 +523,7 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 500 | 523 | } |
| 501 | 524 | } else 0; |
| 502 | 525 | |
| 503 | reg.stab = .{ | |
| 526 | const stab = try Symbol.Stab.new(self.allocator, sym.name, .{ | |
| 504 | 527 | .kind = kind: { |
| 505 | 528 | if (size > 0) break :kind .function; |
| 506 | 529 | switch (reg.linkage) { |
| ... | ... | @@ -509,9 +532,27 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 509 | 532 | } |
| 510 | 533 | }, |
| 511 | 534 | .size = size, |
| 512 | }; | |
| 535 | .symbol = sym, | |
| 536 | .file = self, | |
| 537 | }); | |
| 538 | self.stabs.appendAssumeCapacity(stab); | |
| 539 | } else if (sym.cast(Symbol.Tentative)) |_| { | |
| 540 | const stab = try Symbol.Stab.new(self.allocator, sym.name, .{ | |
| 541 | .kind = .global, | |
| 542 | .size = 0, | |
| 543 | .symbol = sym, | |
| 544 | .file = self, | |
| 545 | }); | |
| 546 | self.stabs.appendAssumeCapacity(stab); | |
| 513 | 547 | } |
| 514 | 548 | } |
| 549 | ||
| 550 | // Closing delimiter. | |
| 551 | const delim_stab = try Symbol.Stab.new(self.allocator, "", .{ | |
| 552 | .kind = .so, | |
| 553 | .file = self, | |
| 554 | }); | |
| 555 | self.stabs.appendAssumeCapacity(delim_stab); | |
| 515 | 556 | } |
| 516 | 557 | |
| 517 | 558 | fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 { |
src/link/MachO/Symbol.zig+146-26| ... | ... | @@ -10,6 +10,7 @@ const Object = @import("Object.zig"); |
| 10 | 10 | const StringTable = @import("StringTable.zig"); |
| 11 | 11 | |
| 12 | 12 | pub const Type = enum { |
| 13 | stab, | |
| 13 | 14 | regular, |
| 14 | 15 | proxy, |
| 15 | 16 | unresolved, |
| ... | ... | @@ -31,6 +32,151 @@ got_index: ?u32 = null, |
| 31 | 32 | /// Index in stubs table for late binding. |
| 32 | 33 | stubs_index: ?u32 = null, |
| 33 | 34 | |
| 35 | pub const Stab = struct { | |
| 36 | base: Symbol, | |
| 37 | ||
| 38 | // Symbol kind: function, etc. | |
| 39 | kind: Kind, | |
| 40 | ||
| 41 | // Size of stab. | |
| 42 | size: u64, | |
| 43 | ||
| 44 | // Base regular symbol for this stub if defined. | |
| 45 | symbol: ?*Symbol = null, | |
| 46 | ||
| 47 | // null means self-reference. | |
| 48 | file: ?*Object = null, | |
| 49 | ||
| 50 | pub const base_type: Symbol.Type = .stab; | |
| 51 | ||
| 52 | pub const Kind = enum { | |
| 53 | so, | |
| 54 | oso, | |
| 55 | function, | |
| 56 | global, | |
| 57 | static, | |
| 58 | }; | |
| 59 | ||
| 60 | const Opts = struct { | |
| 61 | kind: Kind = .so, | |
| 62 | size: u64 = 0, | |
| 63 | symbol: ?*Symbol = null, | |
| 64 | file: ?*Object = null, | |
| 65 | }; | |
| 66 | ||
| 67 | pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol { | |
| 68 | const stab = try allocator.create(Stab); | |
| 69 | errdefer allocator.destroy(stab); | |
| 70 | ||
| 71 | stab.* = .{ | |
| 72 | .base = .{ | |
| 73 | .@"type" = .stab, | |
| 74 | .name = try allocator.dupe(u8, name), | |
| 75 | }, | |
| 76 | .kind = opts.kind, | |
| 77 | .size = opts.size, | |
| 78 | .symbol = opts.symbol, | |
| 79 | .file = opts.file, | |
| 80 | }; | |
| 81 | ||
| 82 | return &stab.base; | |
| 83 | } | |
| 84 | ||
| 85 | pub fn asNlists(stab: *Stab, allocator: *Allocator, strtab: *StringTable) ![]macho.nlist_64 { | |
| 86 | var out = std.ArrayList(macho.nlist_64).init(allocator); | |
| 87 | defer out.deinit(); | |
| 88 | if (stab.kind == .so) { | |
| 89 | try out.append(.{ | |
| 90 | .n_strx = try strtab.getOrPut(stab.base.name), | |
| 91 | .n_type = macho.N_SO, | |
| 92 | .n_sect = 0, | |
| 93 | .n_desc = 0, | |
| 94 | .n_value = 0, | |
| 95 | }); | |
| 96 | } else if (stab.kind == .oso) { | |
| 97 | const mtime = mtime: { | |
| 98 | const object = stab.file orelse break :mtime 0; | |
| 99 | break :mtime object.mtime orelse 0; | |
| 100 | }; | |
| 101 | try out.append(.{ | |
| 102 | .n_strx = try strtab.getOrPut(stab.base.name), | |
| 103 | .n_type = macho.N_OSO, | |
| 104 | .n_sect = 0, | |
| 105 | .n_desc = 1, | |
| 106 | .n_value = mtime, | |
| 107 | }); | |
| 108 | } else outer: { | |
| 109 | const symbol = stab.symbol orelse unreachable; | |
| 110 | const regular = symbol.getTopmostAlias().cast(Regular) orelse unreachable; | |
| 111 | const is_match = blk: { | |
| 112 | if (regular.file == null and stab.file == null) break :blk true; | |
| 113 | if (regular.file) |f1| { | |
| 114 | if (stab.file) |f2| { | |
| 115 | if (f1 == f2) break :blk true; | |
| 116 | } | |
| 117 | } | |
| 118 | break :blk false; | |
| 119 | }; | |
| 120 | if (!is_match) break :outer; | |
| 121 | ||
| 122 | switch (stab.kind) { | |
| 123 | .function => { | |
| 124 | try out.ensureUnusedCapacity(4); | |
| 125 | out.appendAssumeCapacity(.{ | |
| 126 | .n_strx = 0, | |
| 127 | .n_type = macho.N_BNSYM, | |
| 128 | .n_sect = regular.section, | |
| 129 | .n_desc = 0, | |
| 130 | .n_value = regular.address, | |
| 131 | }); | |
| 132 | out.appendAssumeCapacity(.{ | |
| 133 | .n_strx = try strtab.getOrPut(stab.base.name), | |
| 134 | .n_type = macho.N_FUN, | |
| 135 | .n_sect = regular.section, | |
| 136 | .n_desc = 0, | |
| 137 | .n_value = regular.address, | |
| 138 | }); | |
| 139 | out.appendAssumeCapacity(.{ | |
| 140 | .n_strx = 0, | |
| 141 | .n_type = macho.N_FUN, | |
| 142 | .n_sect = 0, | |
| 143 | .n_desc = 0, | |
| 144 | .n_value = stab.size, | |
| 145 | }); | |
| 146 | out.appendAssumeCapacity(.{ | |
| 147 | .n_strx = 0, | |
| 148 | .n_type = macho.N_ENSYM, | |
| 149 | .n_sect = regular.section, | |
| 150 | .n_desc = 0, | |
| 151 | .n_value = stab.size, | |
| 152 | }); | |
| 153 | }, | |
| 154 | .global => { | |
| 155 | try out.append(.{ | |
| 156 | .n_strx = try strtab.getOrPut(stab.base.name), | |
| 157 | .n_type = macho.N_GSYM, | |
| 158 | .n_sect = 0, | |
| 159 | .n_desc = 0, | |
| 160 | .n_value = 0, | |
| 161 | }); | |
| 162 | }, | |
| 163 | .static => { | |
| 164 | try out.append(.{ | |
| 165 | .n_strx = try strtab.getOrPut(stab.base.name), | |
| 166 | .n_type = macho.N_STSYM, | |
| 167 | .n_sect = regular.section, | |
| 168 | .n_desc = 0, | |
| 169 | .n_value = regular.address, | |
| 170 | }); | |
| 171 | }, | |
| 172 | .so, .oso => unreachable, | |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | return out.toOwnedSlice(); | |
| 177 | } | |
| 178 | }; | |
| 179 | ||
| 34 | 180 | pub const Regular = struct { |
| 35 | 181 | base: Symbol, |
| 36 | 182 | |
| ... | ... | @@ -50,9 +196,6 @@ pub const Regular = struct { |
| 50 | 196 | /// null means self-reference. |
| 51 | 197 | file: ?*Object = null, |
| 52 | 198 | |
| 53 | /// Debug stab if defined. | |
| 54 | stab: ?Stab = null, | |
| 55 | ||
| 56 | 199 | /// True if symbol was already committed into the final |
| 57 | 200 | /// symbol table. |
| 58 | 201 | visited: bool = false, |
| ... | ... | @@ -65,25 +208,12 @@ pub const Regular = struct { |
| 65 | 208 | global, |
| 66 | 209 | }; |
| 67 | 210 | |
| 68 | pub const Stab = struct { | |
| 69 | /// Stab kind | |
| 70 | kind: enum { | |
| 71 | function, | |
| 72 | global, | |
| 73 | static, | |
| 74 | }, | |
| 75 | ||
| 76 | /// Size of the stab. | |
| 77 | size: u64, | |
| 78 | }; | |
| 79 | ||
| 80 | 211 | const Opts = struct { |
| 81 | 212 | linkage: Linkage = .translation_unit, |
| 82 | 213 | address: u64 = 0, |
| 83 | 214 | section: u8 = 0, |
| 84 | 215 | weak_ref: bool = false, |
| 85 | 216 | file: ?*Object = null, |
| 86 | stab: ?Stab = null, | |
| 87 | 217 | }; |
| 88 | 218 | |
| 89 | 219 | pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol { |
| ... | ... | @@ -100,7 +230,6 @@ pub const Regular = struct { |
| 100 | 230 | .section = opts.section, |
| 101 | 231 | .weak_ref = opts.weak_ref, |
| 102 | 232 | .file = opts.file, |
| 103 | .stab = opts.stab, | |
| 104 | 233 | }; |
| 105 | 234 | |
| 106 | 235 | return &reg.base; |
| ... | ... | @@ -304,15 +433,6 @@ pub fn getTopmostAlias(base: *Symbol) *Symbol { |
| 304 | 433 | return base; |
| 305 | 434 | } |
| 306 | 435 | |
| 307 | pub fn asNlist(base: *Symbol, strtab: *StringTable) !macho.nlist_64 { | |
| 308 | return switch (base.tag) { | |
| 309 | .regular => @fieldParentPtr(Regular, "base", base).asNlist(strtab), | |
| 310 | .proxy => @fieldParentPtr(Proxy, "base", base).asNlist(strtab), | |
| 311 | .unresolved => @fieldParentPtr(Unresolved, "base", base).asNlist(strtab), | |
| 312 | .tentative => @fieldParentPtr(Tentative, "base", base).asNlist(strtab), | |
| 313 | }; | |
| 314 | } | |
| 315 | ||
| 316 | 436 | pub fn isStab(sym: macho.nlist_64) bool { |
| 317 | 437 | return (macho.N_STAB & sym.n_type) != 0; |
| 318 | 438 | } |
src/link/MachO/Zld.zig+9-137| ... | ... | @@ -1137,10 +1137,6 @@ fn allocateTentativeSymbols(self: *Zld) !void { |
| 1137 | 1137 | .section = section, |
| 1138 | 1138 | .weak_ref = false, |
| 1139 | 1139 | .file = tent.file, |
| 1140 | .stab = .{ | |
| 1141 | .kind = .global, | |
| 1142 | .size = 0, | |
| 1143 | }, | |
| 1144 | 1140 | }); |
| 1145 | 1141 | reg.got_index = tent.base.got_index; |
| 1146 | 1142 | reg.stubs_index = tent.base.stubs_index; |
| ... | ... | @@ -2338,7 +2334,6 @@ fn flush(self: *Zld) !void { |
| 2338 | 2334 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 2339 | 2335 | } |
| 2340 | 2336 | |
| 2341 | try self.writeDebugInfo(); | |
| 2342 | 2337 | try self.writeSymbolTable(); |
| 2343 | 2338 | try self.writeStringTable(); |
| 2344 | 2339 | |
| ... | ... | @@ -2711,138 +2706,6 @@ fn writeExportInfo(self: *Zld) !void { |
| 2711 | 2706 | try self.file.?.pwriteAll(buffer, dyld_info.export_off); |
| 2712 | 2707 | } |
| 2713 | 2708 | |
| 2714 | fn writeDebugInfo(self: *Zld) !void { | |
| 2715 | var stabs = std.ArrayList(macho.nlist_64).init(self.allocator); | |
| 2716 | defer stabs.deinit(); | |
| 2717 | ||
| 2718 | for (self.objects.items) |object| { | |
| 2719 | const tu_path = object.tu_path orelse continue; | |
| 2720 | const tu_mtime = object.tu_mtime orelse continue; | |
| 2721 | _ = tu_mtime; | |
| 2722 | const dirname = std.fs.path.dirname(tu_path) orelse "./"; | |
| 2723 | // Current dir | |
| 2724 | try stabs.append(.{ | |
| 2725 | .n_strx = try self.strtab.getOrPut(tu_path[0 .. dirname.len + 1]), | |
| 2726 | .n_type = macho.N_SO, | |
| 2727 | .n_sect = 0, | |
| 2728 | .n_desc = 0, | |
| 2729 | .n_value = 0, | |
| 2730 | }); | |
| 2731 | // Artifact name | |
| 2732 | try stabs.append(.{ | |
| 2733 | .n_strx = try self.strtab.getOrPut(tu_path[dirname.len + 1 ..]), | |
| 2734 | .n_type = macho.N_SO, | |
| 2735 | .n_sect = 0, | |
| 2736 | .n_desc = 0, | |
| 2737 | .n_value = 0, | |
| 2738 | }); | |
| 2739 | // Path to object file with debug info | |
| 2740 | try stabs.append(.{ | |
| 2741 | .n_strx = try self.strtab.getOrPut(object.name.?), | |
| 2742 | .n_type = macho.N_OSO, | |
| 2743 | .n_sect = 0, | |
| 2744 | .n_desc = 1, | |
| 2745 | .n_value = 0, //tu_mtime, TODO figure out why precalculated mtime value doesn't work | |
| 2746 | }); | |
| 2747 | ||
| 2748 | for (object.symbols.items) |sym| { | |
| 2749 | const reg = reg: { | |
| 2750 | switch (sym.@"type") { | |
| 2751 | .regular => break :reg sym.cast(Symbol.Regular) orelse unreachable, | |
| 2752 | .tentative => { | |
| 2753 | const final = sym.getTopmostAlias().cast(Symbol.Regular) orelse unreachable; | |
| 2754 | if (object != final.file) continue; | |
| 2755 | break :reg final; | |
| 2756 | }, | |
| 2757 | else => continue, | |
| 2758 | } | |
| 2759 | }; | |
| 2760 | ||
| 2761 | if (reg.isTemp() or reg.stab == null) continue; | |
| 2762 | const stab = reg.stab orelse unreachable; | |
| 2763 | ||
| 2764 | switch (stab.kind) { | |
| 2765 | .function => { | |
| 2766 | try stabs.append(.{ | |
| 2767 | .n_strx = 0, | |
| 2768 | .n_type = macho.N_BNSYM, | |
| 2769 | .n_sect = reg.section, | |
| 2770 | .n_desc = 0, | |
| 2771 | .n_value = reg.address, | |
| 2772 | }); | |
| 2773 | try stabs.append(.{ | |
| 2774 | .n_strx = try self.strtab.getOrPut(sym.name), | |
| 2775 | .n_type = macho.N_FUN, | |
| 2776 | .n_sect = reg.section, | |
| 2777 | .n_desc = 0, | |
| 2778 | .n_value = reg.address, | |
| 2779 | }); | |
| 2780 | try stabs.append(.{ | |
| 2781 | .n_strx = 0, | |
| 2782 | .n_type = macho.N_FUN, | |
| 2783 | .n_sect = 0, | |
| 2784 | .n_desc = 0, | |
| 2785 | .n_value = stab.size, | |
| 2786 | }); | |
| 2787 | try stabs.append(.{ | |
| 2788 | .n_strx = 0, | |
| 2789 | .n_type = macho.N_ENSYM, | |
| 2790 | .n_sect = reg.section, | |
| 2791 | .n_desc = 0, | |
| 2792 | .n_value = stab.size, | |
| 2793 | }); | |
| 2794 | }, | |
| 2795 | .global => { | |
| 2796 | try stabs.append(.{ | |
| 2797 | .n_strx = try self.strtab.getOrPut(sym.name), | |
| 2798 | .n_type = macho.N_GSYM, | |
| 2799 | .n_sect = 0, | |
| 2800 | .n_desc = 0, | |
| 2801 | .n_value = 0, | |
| 2802 | }); | |
| 2803 | }, | |
| 2804 | .static => { | |
| 2805 | try stabs.append(.{ | |
| 2806 | .n_strx = try self.strtab.getOrPut(sym.name), | |
| 2807 | .n_type = macho.N_STSYM, | |
| 2808 | .n_sect = reg.section, | |
| 2809 | .n_desc = 0, | |
| 2810 | .n_value = reg.address, | |
| 2811 | }); | |
| 2812 | }, | |
| 2813 | } | |
| 2814 | } | |
| 2815 | ||
| 2816 | // Close the source file! | |
| 2817 | try stabs.append(.{ | |
| 2818 | .n_strx = 0, | |
| 2819 | .n_type = macho.N_SO, | |
| 2820 | .n_sect = 0, | |
| 2821 | .n_desc = 0, | |
| 2822 | .n_value = 0, | |
| 2823 | }); | |
| 2824 | } | |
| 2825 | ||
| 2826 | if (stabs.items.len == 0) return; | |
| 2827 | ||
| 2828 | // Write stabs into the symbol table | |
| 2829 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 2830 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | |
| 2831 | ||
| 2832 | symtab.nsyms = @intCast(u32, stabs.items.len); | |
| 2833 | ||
| 2834 | const stabs_off = symtab.symoff; | |
| 2835 | const stabs_size = symtab.nsyms * @sizeOf(macho.nlist_64); | |
| 2836 | log.debug("writing symbol stabs from 0x{x} to 0x{x}", .{ stabs_off, stabs_size + stabs_off }); | |
| 2837 | try self.file.?.pwriteAll(mem.sliceAsBytes(stabs.items), stabs_off); | |
| 2838 | ||
| 2839 | linkedit.inner.filesize += stabs_size; | |
| 2840 | ||
| 2841 | // Update dynamic symbol table. | |
| 2842 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | |
| 2843 | dysymtab.nlocalsym = symtab.nsyms; | |
| 2844 | } | |
| 2845 | ||
| 2846 | 2709 | fn writeSymbolTable(self: *Zld) !void { |
| 2847 | 2710 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2848 | 2711 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| ... | ... | @@ -2854,6 +2717,15 @@ fn writeSymbolTable(self: *Zld) !void { |
| 2854 | 2717 | defer exports.deinit(); |
| 2855 | 2718 | |
| 2856 | 2719 | for (self.objects.items) |object| { |
| 2720 | for (object.stabs.items) |sym| { | |
| 2721 | const stab = sym.cast(Symbol.Stab) orelse unreachable; | |
| 2722 | ||
| 2723 | const nlists = try stab.asNlists(self.allocator, &self.strtab); | |
| 2724 | defer self.allocator.free(nlists); | |
| 2725 | ||
| 2726 | try locals.appendSlice(nlists); | |
| 2727 | } | |
| 2728 | ||
| 2857 | 2729 | for (object.symbols.items) |sym| { |
| 2858 | 2730 | const final = sym.getTopmostAlias(); |
| 2859 | 2731 | if (final.@"type" != .regular) continue; |