authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-02 00:13:46+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:46+02:00
logee6e25bc13b3f23b5f2fd0c8b57f0d115c239fc2
tree592e8d3db7226c8dbf79af9a3a0c0c1eb1b7b97b
parent2b3bda43e352152f0150bf2e795419cf1bcfcd90

zld: add Symbol.Stab and move nlist creation logic there


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 }
8383
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;
18usingnamespace @import("commands.zig");18usingnamespace @import("commands.zig");
1919
20allocator: *Allocator,20allocator: *Allocator,
21
22arch: ?Arch = null,21arch: ?Arch = null,
23header: ?macho.mach_header_64 = null,22header: ?macho.mach_header_64 = null,
24file: ?fs.File = null,23file: ?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,
24file: ?fs.File = null,24file: ?fs.File = null,
25file_offset: ?u32 = null,25file_offset: ?u32 = null,
26name: ?[]const u8 = null,26name: ?[]const u8 = null,
27mtime: ?u64 = null,
2728
28load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},29load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
29sections: std.ArrayListUnmanaged(Section) = .{},30sections: std.ArrayListUnmanaged(Section) = .{},
...@@ -45,12 +46,10 @@ dwarf_debug_line_index: ?u16 = null,...@@ -45,12 +46,10 @@ dwarf_debug_line_index: ?u16 = null,
45dwarf_debug_ranges_index: ?u16 = null,46dwarf_debug_ranges_index: ?u16 = null,
4647
47symbols: std.ArrayListUnmanaged(*Symbol) = .{},48symbols: std.ArrayListUnmanaged(*Symbol) = .{},
49stabs: std.ArrayListUnmanaged(*Symbol) = .{},
48initializers: std.ArrayListUnmanaged(*Symbol) = .{},50initializers: std.ArrayListUnmanaged(*Symbol) = .{},
49data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},51data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
5052
51tu_path: ?[]const u8 = null,
52tu_mtime: ?u64 = null,
53
54pub const Section = struct {53pub 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);
225224
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);
228233
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}
237238
238pub fn closeFile(self: Object) void {239pub 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);
486487
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 }));
492515
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;
502525
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}
516557
517fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {558fn 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");
10const StringTable = @import("StringTable.zig");10const StringTable = @import("StringTable.zig");
1111
12pub const Type = enum {12pub 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.
32stubs_index: ?u32 = null,33stubs_index: ?u32 = null,
3334
35pub 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
34pub const Regular = struct {180pub const Regular = struct {
35 base: Symbol,181 base: Symbol,
36182
...@@ -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,
52198
53 /// Debug stab if defined.
54 stab: ?Stab = null,
55
56 /// True if symbol was already committed into the final199 /// 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 };
67210
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 };
88218
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 };
105234
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}
306435
307pub 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
316pub fn isStab(sym: macho.nlist_64) bool {436pub 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 }
23402336
2341 try self.writeDebugInfo();
2342 try self.writeSymbolTable();2337 try self.writeSymbolTable();
2343 try self.writeStringTable();2338 try self.writeStringTable();
23442339
...@@ -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}
27132708
2714fn 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
2846fn writeSymbolTable(self: *Zld) !void {2709fn 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();
28552718
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;