| 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,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 | fn size(self: ar_hdr) !u32 { | 89 | fn size(self: ar_hdr) !u32 { |
| 85 | const value = getValue(&self.ar_size); | 90 | const value = getValue(&self.ar_size); |
| 86 | return std.fmt.parseInt(u32, value, 10); | 91 | return std.fmt.parseInt(u32, value, 10); |
| ... | @@ -264,6 +269,7 @@ pub fn parseObject(self: Archive, offset: u32) !*Object { | ... | @@ -264,6 +269,7 @@ pub fn parseObject(self: Archive, offset: u32) !*Object { |
| 264 | .file = try fs.cwd().openFile(self.name.?, .{}), | 269 | .file = try fs.cwd().openFile(self.name.?, .{}), |
| 265 | .name = name, | 270 | .name = name, |
| 266 | .file_offset = @intCast(u32, try reader.context.getPos()), | 271 | .file_offset = @intCast(u32, try reader.context.getPos()), |
| 272 | .mtime = try self.header.?.date(), | ||
| 267 | }; | 273 | }; |
| 268 | try object.parse(); | 274 | try object.parse(); |
| 269 | try reader.context.seekTo(0); | 275 | try reader.context.seekTo(0); |
src/link/MachO/Dylib.zig-1| ... | @@ -18,7 +18,6 @@ const LibStub = @import("../tapi.zig").LibStub; | ... | @@ -18,7 +18,6 @@ const LibStub = @import("../tapi.zig").LibStub; |
| 18 | usingnamespace @import("commands.zig"); | 18 | usingnamespace @import("commands.zig"); |
| 19 | 19 | ||
| 20 | allocator: *Allocator, | 20 | allocator: *Allocator, |
| 21 | |||
| 22 | arch: ?Arch = null, | 21 | arch: ?Arch = null, |
| 23 | header: ?macho.mach_header_64 = null, | 22 | header: ?macho.mach_header_64 = null, |
| 24 | file: ?fs.File = null, | 23 | file: ?fs.File = null, |
src/link/MachO/Object.zig+55-14| ... | @@ -24,6 +24,7 @@ header: ?macho.mach_header_64 = null, | ... | @@ -24,6 +24,7 @@ header: ?macho.mach_header_64 = null, |
| 24 | file: ?fs.File = null, | 24 | file: ?fs.File = null, |
| 25 | file_offset: ?u32 = null, | 25 | file_offset: ?u32 = null, |
| 26 | name: ?[]const u8 = null, | 26 | name: ?[]const u8 = null, |
| 27 | mtime: ?u64 = null, | ||
| 27 | 28 | ||
| 28 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 29 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 29 | sections: std.ArrayListUnmanaged(Section) = .{}, | 30 | sections: std.ArrayListUnmanaged(Section) = .{}, |
| ... | @@ -45,12 +46,10 @@ dwarf_debug_line_index: ?u16 = null, | ... | @@ -45,12 +46,10 @@ dwarf_debug_line_index: ?u16 = null, |
| 45 | dwarf_debug_ranges_index: ?u16 = null, | 46 | dwarf_debug_ranges_index: ?u16 = null, |
| 46 | 47 | ||
| 47 | symbols: std.ArrayListUnmanaged(*Symbol) = .{}, | 48 | symbols: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 49 | stabs: std.ArrayListUnmanaged(*Symbol) = .{}, | ||
| 48 | initializers: std.ArrayListUnmanaged(*Symbol) = .{}, | 50 | initializers: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 49 | data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, | 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 | pub const Section = struct { | 53 | pub const Section = struct { |
| 55 | inner: macho.section_64, | 54 | inner: macho.section_64, |
| 56 | code: []u8, | 55 | code: []u8, |
| ... | @@ -223,16 +222,18 @@ pub fn deinit(self: *Object) void { | ... | @@ -223,16 +222,18 @@ pub fn deinit(self: *Object) void { |
| 223 | } | 222 | } |
| 224 | self.symbols.deinit(self.allocator); | 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 | self.data_in_code_entries.deinit(self.allocator); | 231 | self.data_in_code_entries.deinit(self.allocator); |
| 227 | self.initializers.deinit(self.allocator); | 232 | self.initializers.deinit(self.allocator); |
| 228 | 233 | ||
| 229 | if (self.name) |n| { | 234 | if (self.name) |n| { |
| 230 | self.allocator.free(n); | 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 | pub fn closeFile(self: Object) void { | 239 | pub fn closeFile(self: Object) void { |
| ... | @@ -484,11 +485,33 @@ pub fn parseDebugInfo(self: *Object) !void { | ... | @@ -484,11 +485,33 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 484 | const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name); | 485 | const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name); |
| 485 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); | 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 | if (self.mtime == null) { |
| 488 | self.tu_mtime = mtime: { | 489 | self.mtime = mtime: { |
| 489 | const stat = try self.file.?.stat(); | 490 | const file = self.file orelse break :mtime 0; |
| 490 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); | 491 | const stat = file.stat() catch break :mtime 0; |
| 491 | }; | 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 | for (self.symbols.items) |sym| { | 516 | for (self.symbols.items) |sym| { |
| 494 | if (sym.cast(Symbol.Regular)) |reg| { | 517 | if (sym.cast(Symbol.Regular)) |reg| { |
| ... | @@ -500,7 +523,7 @@ pub fn parseDebugInfo(self: *Object) !void { | ... | @@ -500,7 +523,7 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 500 | } | 523 | } |
| 501 | } else 0; | 524 | } else 0; |
| 502 | 525 | ||
| 503 | reg.stab = .{ | 526 | const stab = try Symbol.Stab.new(self.allocator, sym.name, .{ |
| 504 | .kind = kind: { | 527 | .kind = kind: { |
| 505 | if (size > 0) break :kind .function; | 528 | if (size > 0) break :kind .function; |
| 506 | switch (reg.linkage) { | 529 | switch (reg.linkage) { |
| ... | @@ -509,9 +532,27 @@ pub fn parseDebugInfo(self: *Object) !void { | ... | @@ -509,9 +532,27 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 509 | } | 532 | } |
| 510 | }, | 533 | }, |
| 511 | .size = size, | 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 | fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 { | 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,6 +10,7 @@ const Object = @import("Object.zig"); |
| 10 | const StringTable = @import("StringTable.zig"); | 10 | const StringTable = @import("StringTable.zig"); |
| 11 | 11 | ||
| 12 | pub const Type = enum { | 12 | pub const Type = enum { |
| 13 | stab, | ||
| 13 | regular, | 14 | regular, |
| 14 | proxy, | 15 | proxy, |
| 15 | unresolved, | 16 | unresolved, |
| ... | @@ -31,6 +32,151 @@ got_index: ?u32 = null, | ... | @@ -31,6 +32,151 @@ got_index: ?u32 = null, |
| 31 | /// Index in stubs table for late binding. | 32 | /// Index in stubs table for late binding. |
| 32 | stubs_index: ?u32 = null, | 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 | pub const Regular = struct { | 180 | pub const Regular = struct { |
| 35 | base: Symbol, | 181 | base: Symbol, |
| 36 | 182 | ||
| ... | @@ -50,9 +196,6 @@ pub const Regular = struct { | ... | @@ -50,9 +196,6 @@ pub const Regular = struct { |
| 50 | /// null means self-reference. | 196 | /// null means self-reference. |
| 51 | file: ?*Object = null, | 197 | file: ?*Object = null, |
| 52 | 198 | ||
| 53 | /// Debug stab if defined. | ||
| 54 | stab: ?Stab = null, | ||
| 55 | |||
| 56 | /// True if symbol was already committed into the final | 199 | /// True if symbol was already committed into the final |
| 57 | /// symbol table. | 200 | /// symbol table. |
| 58 | visited: bool = false, | 201 | visited: bool = false, |
| ... | @@ -65,25 +208,12 @@ pub const Regular = struct { | ... | @@ -65,25 +208,12 @@ pub const Regular = struct { |
| 65 | global, | 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 | const Opts = struct { | 211 | const Opts = struct { |
| 81 | linkage: Linkage = .translation_unit, | 212 | linkage: Linkage = .translation_unit, |
| 82 | address: u64 = 0, | 213 | address: u64 = 0, |
| 83 | section: u8 = 0, | 214 | section: u8 = 0, |
| 84 | weak_ref: bool = false, | 215 | weak_ref: bool = false, |
| 85 | file: ?*Object = null, | 216 | file: ?*Object = null, |
| 86 | stab: ?Stab = null, | ||
| 87 | }; | 217 | }; |
| 88 | 218 | ||
| 89 | pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol { | 219 | pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol { |
| ... | @@ -100,7 +230,6 @@ pub const Regular = struct { | ... | @@ -100,7 +230,6 @@ pub const Regular = struct { |
| 100 | .section = opts.section, | 230 | .section = opts.section, |
| 101 | .weak_ref = opts.weak_ref, | 231 | .weak_ref = opts.weak_ref, |
| 102 | .file = opts.file, | 232 | .file = opts.file, |
| 103 | .stab = opts.stab, | ||
| 104 | }; | 233 | }; |
| 105 | 234 | ||
| 106 | return &reg.base; | 235 | return &reg.base; |
| ... | @@ -304,15 +433,6 @@ pub fn getTopmostAlias(base: *Symbol) *Symbol { | ... | @@ -304,15 +433,6 @@ pub fn getTopmostAlias(base: *Symbol) *Symbol { |
| 304 | return base; | 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 | pub fn isStab(sym: macho.nlist_64) bool { | 436 | pub fn isStab(sym: macho.nlist_64) bool { |
| 317 | return (macho.N_STAB & sym.n_type) != 0; | 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,10 +1137,6 @@ fn allocateTentativeSymbols(self: *Zld) !void { |
| 1137 | .section = section, | 1137 | .section = section, |
| 1138 | .weak_ref = false, | 1138 | .weak_ref = false, |
| 1139 | .file = tent.file, | 1139 | .file = tent.file, |
| 1140 | .stab = .{ | ||
| 1141 | .kind = .global, | ||
| 1142 | .size = 0, | ||
| 1143 | }, | ||
| 1144 | }); | 1140 | }); |
| 1145 | reg.got_index = tent.base.got_index; | 1141 | reg.got_index = tent.base.got_index; |
| 1146 | reg.stubs_index = tent.base.stubs_index; | 1142 | reg.stubs_index = tent.base.stubs_index; |
| ... | @@ -2338,7 +2334,6 @@ fn flush(self: *Zld) !void { | ... | @@ -2338,7 +2334,6 @@ fn flush(self: *Zld) !void { |
| 2338 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); | 2334 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 2339 | } | 2335 | } |
| 2340 | 2336 | ||
| 2341 | try self.writeDebugInfo(); | ||
| 2342 | try self.writeSymbolTable(); | 2337 | try self.writeSymbolTable(); |
| 2343 | try self.writeStringTable(); | 2338 | try self.writeStringTable(); |
| 2344 | 2339 | ||
| ... | @@ -2711,138 +2706,6 @@ fn writeExportInfo(self: *Zld) !void { | ... | @@ -2711,138 +2706,6 @@ fn writeExportInfo(self: *Zld) !void { |
| 2711 | try self.file.?.pwriteAll(buffer, dyld_info.export_off); | 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 | fn writeSymbolTable(self: *Zld) !void { | 2709 | fn writeSymbolTable(self: *Zld) !void { |
| 2847 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 2710 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2848 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 2711 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| ... | @@ -2854,6 +2717,15 @@ fn writeSymbolTable(self: *Zld) !void { | ... | @@ -2854,6 +2717,15 @@ fn writeSymbolTable(self: *Zld) !void { |
| 2854 | defer exports.deinit(); | 2717 | defer exports.deinit(); |
| 2855 | 2718 | ||
| 2856 | for (self.objects.items) |object| { | 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 | for (object.symbols.items) |sym| { | 2729 | for (object.symbols.items) |sym| { |
| 2858 | const final = sym.getTopmostAlias(); | 2730 | const final = sym.getTopmostAlias(); |
| 2859 | if (final.@"type" != .regular) continue; | 2731 | if (final.@"type" != .regular) continue; |