authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-02 23:40:08+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-04 13:09:32+02:00
log86ab6ca56c4e6d115b017eed40dc62815a6a8e3d
tree7d429b531800dfe8614ea4789686338d5fd9a5df
parentb6be28ddcc50bd4bf085294ffcb696e31a7a1de5

zld: rewrite Object to include pointers to Symbols


5 files changed, 186 insertions(+), 145 deletions(-)

src/link/MachO/Object.zig+80-98
......@@ -43,17 +43,13 @@ dwarf_debug_str_index: ?u16 = null,
4343dwarf_debug_line_index: ?u16 = null,
4444dwarf_debug_ranges_index: ?u16 = null,
4545
46symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
47strtab: std.ArrayListUnmanaged(u8) = .{},
46symbols: std.ArrayListUnmanaged(*Symbol) = .{},
47initializers: std.ArrayListUnmanaged(*Symbol) = .{},
48data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
4849
49locals: std.StringArrayHashMapUnmanaged(Symbol) = .{},
50stabs: std.ArrayListUnmanaged(Stab) = .{},
5150tu_path: ?[]const u8 = null,
5251tu_mtime: ?u64 = null,
5352
54initializers: std.ArrayListUnmanaged(CppStatic) = .{},
55data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
56
5753pub const Section = struct {
5854 inner: macho.section_64,
5955 code: []u8,
......@@ -71,23 +67,6 @@ pub const Section = struct {
7167 }
7268};
7369
74const CppStatic = struct {
75 symbol: u32,
76 target_addr: u64,
77};
78
79const Stab = struct {
80 tag: Tag,
81 symbol: u32,
82 size: ?u64 = null,
83
84 const Tag = enum {
85 function,
86 global,
87 static,
88 };
89};
90
9170const DebugInfo = struct {
9271 inner: dwarf.DwarfInfo,
9372 debug_info: []u8,
......@@ -169,14 +148,12 @@ pub fn deinit(self: *Object) void {
169148 }
170149 self.sections.deinit(self.allocator);
171150
172 for (self.locals.items()) |*entry| {
173 entry.value.deinit(self.allocator);
151 for (self.symbols.items) |sym| {
152 sym.deinit(self.allocator);
153 self.allocator.destroy(sym);
174154 }
175 self.locals.deinit(self.allocator);
155 self.symbols.deinit(self.allocator);
176156
177 self.symtab.deinit(self.allocator);
178 self.strtab.deinit(self.allocator);
179 self.stabs.deinit(self.allocator);
180157 self.data_in_code_entries.deinit(self.allocator);
181158 self.initializers.deinit(self.allocator);
182159
......@@ -222,9 +199,9 @@ pub fn parse(self: *Object) !void {
222199 }
223200
224201 try self.readLoadCommands(reader);
202 try self.parseSymbols();
225203 try self.parseSections();
226 if (self.symtab_cmd_index != null) try self.parseSymtab();
227 if (self.data_in_code_cmd_index != null) try self.readDataInCode();
204 try self.parseDataInCode();
228205 try self.parseInitializers();
229206 try self.parseDebugInfo();
230207}
......@@ -298,9 +275,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
298275}
299276
300277pub fn parseSections(self: *Object) !void {
301 log.debug("parsing sections in {s}", .{self.name.?});
302278 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
303279
280 log.debug("parsing sections in {s}", .{self.name.?});
281
304282 try self.sections.ensureCapacity(self.allocator, seg.sections.items.len);
305283
306284 for (seg.sections.items) |sect| {
......@@ -327,6 +305,7 @@ pub fn parseSections(self: *Object) !void {
327305 self.arch.?,
328306 section.code,
329307 mem.bytesAsSlice(macho.relocation_info, raw_relocs),
308 self.symbols.items,
330309 );
331310 }
332311
......@@ -344,60 +323,70 @@ pub fn parseInitializers(self: *Object) !void {
344323 const relocs = section.relocs orelse unreachable;
345324 try self.initializers.ensureCapacity(self.allocator, relocs.len);
346325 for (relocs) |rel| {
347 self.initializers.appendAssumeCapacity(.{
348 .symbol = rel.target.symbol,
349 .target_addr = undefined,
350 });
326 self.initializers.appendAssumeCapacity(rel.target.symbol);
351327 }
352328
353 mem.reverse(CppStatic, self.initializers.items);
354
355 for (self.initializers.items) |initializer| {
356 const sym = self.symtab.items[initializer.symbol];
357 const sym_name = self.getString(sym.n_strx);
358 log.debug(" | {s}", .{sym_name});
359 }
329 mem.reverse(*Symbol, self.initializers.items);
360330}
361331
362pub fn parseSymtab(self: *Object) !void {
363 const symtab_cmd = self.load_commands.items[self.symtab_cmd_index.?].Symtab;
332pub fn parseSymbols(self: *Object) !void {
333 const index = self.symtab_cmd_index orelse return;
334 const symtab_cmd = self.load_commands.items[index].Symtab;
364335
365336 var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
366337 defer self.allocator.free(symtab);
367
368338 _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff);
369339 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));
370 try self.symtab.appendSlice(self.allocator, slice);
371340
372341 var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize);
373342 defer self.allocator.free(strtab);
374
375343 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);
376 try self.strtab.appendSlice(self.allocator, strtab);
377344
378 for (self.symtab.items) |sym, sym_id| {
379 if (Symbol.isStab(sym) or Symbol.isUndef(sym)) continue;
345 for (slice) |sym| {
346 if (Symbol.isStab(sym)) {
347 log.err("TODO handle stabs embedded within object files", .{});
348 return error.HandleStabsInObjects;
349 }
380350
381 const sym_name = self.getString(sym.n_strx);
382 const tag: Symbol.Tag = tag: {
383 if (Symbol.isLocal(sym)) {
384 if (self.arch.? == .aarch64 and mem.startsWith(u8, sym_name, "l")) continue;
385 break :tag .local;
386 }
387 if (Symbol.isWeakDef(sym)) {
388 break :tag .weak;
351 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
352 const name = try self.allocator.dupe(u8, sym_name);
353
354 const symbol: *Symbol = symbol: {
355 if (Symbol.isSect(sym)) {
356 const linkage: Symbol.Regular.Linkage = linkage: {
357 if (!Symbol.isExt(sym)) break :linkage .translation_unit;
358 if (Symbol.isWeakDef(sym) or Symbol.isPext(sym)) break :linkage .linkage_unit;
359 break :linkage .global;
360 };
361 const regular = try self.allocator.create(Symbol.Regular);
362 errdefer self.allocator.destroy(regular);
363 regular.* = .{
364 .base = .{
365 .@"type" = .regular,
366 .name = name,
367 },
368 .linkage = .translation_unit,
369 .address = sym.n_value,
370 .section = sym.n_sect - 1,
371 .weak_ref = Symbol.isWeakRef(sym),
372 .file = self,
373 };
374 break :symbol &regular.base;
389375 }
390 break :tag .strong;
376
377 const undef = try self.allocator.create(Symbol.Unresolved);
378 errdefer self.allocator.destroy(undef);
379 undef.* = .{
380 .base = .{
381 .@"type" = .unresolved,
382 .name = name,
383 },
384 .file = self,
385 };
386 break :symbol &undef.base;
391387 };
392 const name = try self.allocator.dupe(u8, sym_name);
393388
394 try self.locals.putNoClobber(self.allocator, name, .{
395 .tag = tag,
396 .name = name,
397 .address = 0,
398 .section = 0,
399 .index = @intCast(u32, sym_id),
400 });
389 try self.symbols.append(self.allocator, symbol);
401390 }
402391}
403392
......@@ -429,38 +418,31 @@ pub fn parseDebugInfo(self: *Object) !void {
429418 break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
430419 };
431420
432 for (self.locals.items()) |entry, index| {
433 const local = entry.value;
434 const source_sym = self.symtab.items[local.index.?];
435 const size = blk: for (debug_info.inner.func_list.items) |func| {
436 if (func.pc_range) |range| {
437 if (source_sym.n_value >= range.start and source_sym.n_value < range.end) {
438 break :blk range.end - range.start;
421 for (self.symbols.items) |sym| {
422 if (sym.cast(Symbol.Regular)) |reg| {
423 const size: u64 = blk: for (debug_info.inner.func_list.items) |func| {
424 if (func.pc_range) |range| {
425 if (reg.address >= range.start and reg.address < range.end) {
426 break :blk range.end - range.start;
427 }
439428 }
440 }
441 } else null;
442 const tag: Stab.Tag = tag: {
443 if (size != null) break :tag .function;
444 switch (local.tag) {
445 .weak, .strong => break :tag .global,
446 else => break :tag .static,
447 }
448 };
449
450 try self.stabs.append(self.allocator, .{
451 .tag = tag,
452 .size = size,
453 .symbol = @intCast(u32, index),
454 });
429 } else 0;
430
431 reg.stab = .{
432 .kind = kind: {
433 if (size > 0) break :kind .function;
434 switch (reg.linkage) {
435 .translation_unit => break :kind .static,
436 else => break :kind .global,
437 }
438 },
439 .size = size,
440 };
441 }
455442 }
456443}
457444
458pub fn getString(self: *const Object, str_off: u32) []const u8 {
459 assert(str_off < self.strtab.items.len);
460 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off));
461}
462
463pub fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
445fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
464446 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
465447 const sect = seg.sections.items[index];
466448 var buffer = try allocator.alloc(u8, sect.size);
......@@ -468,7 +450,7 @@ pub fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
468450 return buffer;
469451}
470452
471pub fn readDataInCode(self: *Object) !void {
453pub fn parseDataInCode(self: *Object) !void {
472454 const index = self.data_in_code_cmd_index orelse return;
473455 const data_in_code = self.load_commands.items[index].LinkeditData;
474456
src/link/MachO/Symbol.zig+81-30
......@@ -2,31 +2,93 @@ const Symbol = @This();
22
33const std = @import("std");
44const macho = std.macho;
5const mem = std.mem;
56
6const Allocator = std.mem.Allocator;
7const Allocator = mem.Allocator;
8const Object = @import("Object.zig");
79
8pub const Tag = enum {
9 local,
10 weak,
11 strong,
12 import,
13 undef,
10pub const Type = enum {
11 regular,
12 proxy,
13 unresolved,
1414};
1515
16tag: Tag,
16/// Symbol type.
17@"type": Type,
18
19/// Symbol name. Owned slice.
1720name: []u8,
18address: u64,
19section: u8,
2021
21/// Index of file where to locate this symbol.
22/// Depending on context, this is either an object file, or a dylib.
23file: ?u16 = null,
22pub const Regular = struct {
23 base: Symbol,
24
25 /// Linkage type.
26 linkage: Linkage,
27
28 /// Symbol address.
29 address: u64,
30
31 /// Section ID where the symbol resides.
32 section: u8,
33
34 /// Whether the symbol is a weak ref.
35 weak_ref: bool,
36
37 /// File where to locate this symbol.
38 file: *Object,
39
40 /// Debug stab if defined.
41 stab: ?struct {
42 /// Stab kind
43 kind: enum {
44 function,
45 global,
46 static,
47 },
2448
25/// Index of this symbol within the file's symbol table.
26index: ?u32 = null,
49 /// Size of the stab.
50 size: u64,
51 } = null,
2752
28pub fn deinit(self: *Symbol, allocator: *Allocator) void {
29 allocator.free(self.name);
53 pub const base_type: Symbol.Type = .regular;
54
55 pub const Linkage = enum {
56 translation_unit,
57 linkage_unit,
58 global,
59 };
60};
61
62pub const Proxy = struct {
63 base: Symbol,
64
65 /// Dylib ordinal.
66 dylib: u16,
67
68 pub const base_type: Symbol.Type = .proxy;
69};
70
71pub const Unresolved = struct {
72 base: Symbol,
73
74 /// Alias of.
75 alias: ?*Symbol = null,
76
77 /// File where this symbol was referenced.
78 file: *Object,
79
80 pub const base_type: Symbol.Type = .unresolved;
81};
82
83pub fn deinit(base: *Symbol, allocator: *Allocator) void {
84 allocator.free(base.name);
85}
86
87pub fn cast(base: *Symbol, comptime T: type) ?*T {
88 if (base.@"type" != T.base_type) {
89 return null;
90 }
91 return @fieldParentPtr(T, "base", base);
3092}
3193
3294pub fn isStab(sym: macho.nlist_64) bool {
......@@ -55,17 +117,6 @@ pub fn isWeakDef(sym: macho.nlist_64) bool {
55117 return (sym.n_desc & macho.N_WEAK_DEF) != 0;
56118}
57119
58/// Symbol is local if it is defined and not an extern.
59pub fn isLocal(sym: macho.nlist_64) bool {
60 return isSect(sym) and !isExt(sym);
61}
62
63/// Symbol is global if it is defined and an extern.
64pub fn isGlobal(sym: macho.nlist_64) bool {
65 return isSect(sym) and isExt(sym);
66}
67
68/// Symbol is undefined if it is not defined and an extern.
69pub fn isUndef(sym: macho.nlist_64) bool {
70 return isUndf(sym) and isExt(sym);
120pub fn isWeakRef(sym: macho.nlist_64) bool {
121 return (sym.n_desc & macho.N_WEAK_REF) != 0;
71122}
src/link/MachO/reloc.zig+7-3
......@@ -10,6 +10,7 @@ const aarch64 = @import("reloc/aarch64.zig");
1010const x86_64 = @import("reloc/x86_64.zig");
1111
1212const Allocator = mem.Allocator;
13const Symbol = @import("Symbol.zig");
1314
1415pub const Relocation = struct {
1516 @"type": Type,
......@@ -75,12 +76,12 @@ pub const Relocation = struct {
7576 };
7677
7778 pub const Target = union(enum) {
78 symbol: u32,
79 symbol: *Symbol,
7980 section: u16,
8081
81 pub fn from_reloc(reloc: macho.relocation_info) Target {
82 pub fn from_reloc(reloc: macho.relocation_info, symbols: []*Symbol) Target {
8283 return if (reloc.r_extern == 1) .{
83 .symbol = reloc.r_symbolnum,
84 .symbol = symbols[reloc.r_symbolnum],
8485 } else .{
8586 .section = @intCast(u16, reloc.r_symbolnum - 1),
8687 };
......@@ -136,6 +137,7 @@ pub fn parse(
136137 arch: std.Target.Cpu.Arch,
137138 code: []u8,
138139 relocs: []const macho.relocation_info,
140 symbols: []*Symbol,
139141) ![]*Relocation {
140142 var it = RelocIterator{
141143 .buffer = relocs,
......@@ -148,6 +150,7 @@ pub fn parse(
148150 .it = &it,
149151 .code = code,
150152 .parsed = std.ArrayList(*Relocation).init(allocator),
153 .symbols = symbols,
151154 };
152155 defer parser.deinit();
153156 try parser.parse();
......@@ -160,6 +163,7 @@ pub fn parse(
160163 .it = &it,
161164 .code = code,
162165 .parsed = std.ArrayList(*Relocation).init(allocator),
166 .symbols = symbols,
163167 };
164168 defer parser.deinit();
165169 try parser.parse();
src/link/MachO/reloc/aarch64.zig+9-7
......@@ -10,6 +10,7 @@ const reloc = @import("../reloc.zig");
1010
1111const Allocator = mem.Allocator;
1212const Relocation = reloc.Relocation;
13const Symbol = @import("../Symbol.zig");
1314
1415pub const Branch = struct {
1516 base: Relocation,
......@@ -188,6 +189,7 @@ pub const Parser = struct {
188189 it: *reloc.RelocIterator,
189190 code: []u8,
190191 parsed: std.ArrayList(*Relocation),
192 symbols: []*Symbol,
191193 addend: ?u32 = null,
192194 subtractor: ?Relocation.Target = null,
193195
......@@ -273,7 +275,7 @@ pub const Parser = struct {
273275 var branch = try parser.allocator.create(Branch);
274276 errdefer parser.allocator.destroy(branch);
275277
276 const target = Relocation.Target.from_reloc(rel);
278 const target = Relocation.Target.from_reloc(rel, parser.symbols);
277279
278280 branch.* = .{
279281 .base = .{
......@@ -294,7 +296,7 @@ pub const Parser = struct {
294296 assert(rel.r_length == 2);
295297
296298 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
297 const target = Relocation.Target.from_reloc(rel);
299 const target = Relocation.Target.from_reloc(rel, parser.symbols);
298300
299301 const offset = @intCast(u32, rel.r_address);
300302 const inst = parser.code[offset..][0..4];
......@@ -400,7 +402,7 @@ pub const Parser = struct {
400402 aarch64.Instruction.load_store_register,
401403 ), inst) };
402404 }
403 const target = Relocation.Target.from_reloc(rel);
405 const target = Relocation.Target.from_reloc(rel, parser.symbols);
404406
405407 var page_off = try parser.allocator.create(PageOff);
406408 errdefer parser.allocator.destroy(page_off);
......@@ -437,7 +439,7 @@ pub const Parser = struct {
437439 ), inst);
438440 assert(parsed_inst.size == 3);
439441
440 const target = Relocation.Target.from_reloc(rel);
442 const target = Relocation.Target.from_reloc(rel, parser.symbols);
441443
442444 var page_off = try parser.allocator.create(GotPageOff);
443445 errdefer parser.allocator.destroy(page_off);
......@@ -496,7 +498,7 @@ pub const Parser = struct {
496498 }
497499 };
498500
499 const target = Relocation.Target.from_reloc(rel);
501 const target = Relocation.Target.from_reloc(rel, parser.symbols);
500502
501503 var page_off = try parser.allocator.create(TlvpPageOff);
502504 errdefer parser.allocator.destroy(page_off);
......@@ -531,7 +533,7 @@ pub const Parser = struct {
531533 assert(rel.r_pcrel == 0);
532534 assert(parser.subtractor == null);
533535
534 parser.subtractor = Relocation.Target.from_reloc(rel);
536 parser.subtractor = Relocation.Target.from_reloc(rel, parser.symbols);
535537
536538 // Verify SUBTRACTOR is followed by UNSIGNED.
537539 const next = @intToEnum(macho.reloc_type_arm64, parser.it.peek().r_type);
......@@ -554,7 +556,7 @@ pub const Parser = struct {
554556 var unsigned = try parser.allocator.create(reloc.Unsigned);
555557 errdefer parser.allocator.destroy(unsigned);
556558
557 const target = Relocation.Target.from_reloc(rel);
559 const target = Relocation.Target.from_reloc(rel, parser.symbols);
558560 const is_64bit: bool = switch (rel.r_length) {
559561 3 => true,
560562 2 => false,
src/link/MachO/reloc/x86_64.zig+9-7
......@@ -9,6 +9,7 @@ const reloc = @import("../reloc.zig");
99
1010const Allocator = mem.Allocator;
1111const Relocation = reloc.Relocation;
12const Symbol = @import("../Symbol.zig");
1213
1314pub const Branch = struct {
1415 base: Relocation,
......@@ -95,6 +96,7 @@ pub const Parser = struct {
9596 it: *reloc.RelocIterator,
9697 code: []u8,
9798 parsed: std.ArrayList(*Relocation),
99 symbols: []*Symbol,
98100 subtractor: ?Relocation.Target = null,
99101
100102 pub fn deinit(parser: *Parser) void {
......@@ -145,7 +147,7 @@ pub const Parser = struct {
145147 var branch = try parser.allocator.create(Branch);
146148 errdefer parser.allocator.destroy(branch);
147149
148 const target = Relocation.Target.from_reloc(rel);
150 const target = Relocation.Target.from_reloc(rel, parser.symbols);
149151
150152 branch.* = .{
151153 .base = .{
......@@ -165,7 +167,7 @@ pub const Parser = struct {
165167 assert(rel.r_length == 2);
166168
167169 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
168 const target = Relocation.Target.from_reloc(rel);
170 const target = Relocation.Target.from_reloc(rel, parser.symbols);
169171 const is_extern = rel.r_extern == 1;
170172
171173 const offset = @intCast(u32, rel.r_address);
......@@ -211,7 +213,7 @@ pub const Parser = struct {
211213
212214 const offset = @intCast(u32, rel.r_address);
213215 const inst = parser.code[offset..][0..4];
214 const target = Relocation.Target.from_reloc(rel);
216 const target = Relocation.Target.from_reloc(rel, parser.symbols);
215217
216218 var got_load = try parser.allocator.create(GotLoad);
217219 errdefer parser.allocator.destroy(got_load);
......@@ -237,7 +239,7 @@ pub const Parser = struct {
237239
238240 const offset = @intCast(u32, rel.r_address);
239241 const inst = parser.code[offset..][0..4];
240 const target = Relocation.Target.from_reloc(rel);
242 const target = Relocation.Target.from_reloc(rel, parser.symbols);
241243
242244 var got = try parser.allocator.create(Got);
243245 errdefer parser.allocator.destroy(got);
......@@ -263,7 +265,7 @@ pub const Parser = struct {
263265
264266 const offset = @intCast(u32, rel.r_address);
265267 const inst = parser.code[offset..][0..4];
266 const target = Relocation.Target.from_reloc(rel);
268 const target = Relocation.Target.from_reloc(rel, parser.symbols);
267269
268270 var tlv = try parser.allocator.create(Tlv);
269271 errdefer parser.allocator.destroy(tlv);
......@@ -288,7 +290,7 @@ pub const Parser = struct {
288290 assert(rel.r_pcrel == 0);
289291 assert(parser.subtractor == null);
290292
291 parser.subtractor = Relocation.Target.from_reloc(rel);
293 parser.subtractor = Relocation.Target.from_reloc(rel, parser.symbols);
292294
293295 // Verify SUBTRACTOR is followed by UNSIGNED.
294296 const next = @intToEnum(macho.reloc_type_x86_64, parser.it.peek().r_type);
......@@ -311,7 +313,7 @@ pub const Parser = struct {
311313 var unsigned = try parser.allocator.create(reloc.Unsigned);
312314 errdefer parser.allocator.destroy(unsigned);
313315
314 const target = Relocation.Target.from_reloc(rel);
316 const target = Relocation.Target.from_reloc(rel, parser.symbols);
315317 const is_64bit: bool = switch (rel.r_length) {
316318 3 => true,
317319 2 => false,