From f8678c48ff43879d043b626031f7a5c92303fdea Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 15 Jul 2021 07:41:59 +0200 Subject: [PATCH] zld: reuse string table for symbol names rather than manage allocs separately per symbol. --- src/link/MachO/Object.zig | 39 ++++++++----- src/link/MachO/Symbol.zig | 50 ++++------------- src/link/MachO/Zld.zig | 113 ++++++++++++++++++++------------------ src/link/MachO/reloc.zig | 21 ++++--- 4 files changed, 107 insertions(+), 116 deletions(-) diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 49eb34c522..91be941256 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -389,7 +389,7 @@ const TextBlockParser = struct { return switch (rreg.linkage) { .global => true, .linkage_unit => lreg.linkage == .translation_unit, - else => lsym.isTemp(), + else => lsym.isTemp(context.zld), }; } @@ -417,7 +417,7 @@ const TextBlockParser = struct { const sym = self.object.symbols.items[nlist_with_index.index]; if (sym.payload != .regular) { log.err("expected a regular symbol, found {s}", .{sym.payload}); - log.err(" when remapping {s}", .{sym.name}); + log.err(" when remapping {s}", .{self.zld.getString(sym.strx)}); return error.SymbolIsNotRegular; } assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved. @@ -463,7 +463,7 @@ const TextBlockParser = struct { } } } - if (self.zld.globals.contains(senior_sym.name)) break :blk .global; + if (self.zld.globals.contains(self.zld.getString(senior_sym.strx))) break :blk .global; break :blk .static; } else null; @@ -598,7 +598,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { sectionName(sect), }); defer self.allocator.free(name); - const symbol = try Symbol.new(self.allocator, name); + const symbol = try zld.allocator.create(Symbol); + symbol.* = .{ + .strx = try zld.makeString(name), + .payload = .{ .undef = .{} }, + }; try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol); break :symbol symbol; }; @@ -684,7 +688,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { const reg = &sym.payload.regular; if (reg.file) |file| { if (file != self) { - log.debug("deduping definition of {s} in {s}", .{ sym.name, self.name.? }); + log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? }); block.deinit(); self.allocator.destroy(block); continue; @@ -739,7 +743,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { sectionName(sect), }); defer self.allocator.free(name); - const symbol = try Symbol.new(self.allocator, name); + const symbol = try zld.allocator.create(Symbol); + symbol.* = .{ + .strx = try zld.makeString(name), + .payload = .{ .undef = .{} }, + }; try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol); break :symbol symbol; }; @@ -812,7 +820,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { } } } - if (zld.globals.contains(sym.name)) break :blk .global; + if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; break :blk .static; } else null; @@ -870,7 +878,7 @@ fn parseRelocs( try parser.parse(); } -pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol { +pub fn symbolFromReloc(self: *Object, zld: *Zld, rel: macho.relocation_info) !*Symbol { const symbol = blk: { if (rel.r_extern == 1) { break :blk self.symbols.items[rel.r_symbolnum]; @@ -888,12 +896,15 @@ pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol { sectionName(sect), }); defer self.allocator.free(name); - const symbol = try Symbol.new(self.allocator, name); - symbol.payload = .{ - .regular = .{ - .linkage = .translation_unit, - .address = sect.addr, - .file = self, + const symbol = try zld.allocator.create(Symbol); + symbol.* = .{ + .strx = try zld.makeString(name), + .payload = .{ + .regular = .{ + .linkage = .translation_unit, + .address = sect.addr, + .file = self, + }, }, }; try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol); diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 28aee6eeb0..37072b5618 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -11,8 +11,8 @@ const Dylib = @import("Dylib.zig"); const Object = @import("Object.zig"); const Zld = @import("Zld.zig"); -/// Symbol name. Owned slice. -name: []const u8, +/// Offset into the string table. +strx: u32, /// Index in GOT table for indirection. got_index: ?u32 = null, @@ -160,26 +160,11 @@ pub const Undefined = struct { } }; -/// Create new undefined symbol. -pub fn new(allocator: *Allocator, name: []const u8) !*Symbol { - const new_sym = try allocator.create(Symbol); - errdefer allocator.destroy(new_sym); - - new_sym.* = .{ - .name = try allocator.dupe(u8, name), - .payload = .{ - .undef = .{}, - }, - }; - - return new_sym; -} - pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { _ = fmt; _ = options; try std.fmt.format(writer, "Symbol {{", .{}); - try std.fmt.format(writer, ".name = {s}, ", .{self.name}); + try std.fmt.format(writer, ".strx = {d}, ", .{self.strx}); if (self.got_index) |got_index| { try std.fmt.format(writer, ".got_index = {}, ", .{got_index}); } @@ -190,11 +175,12 @@ pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOpt try std.fmt.format(writer, "}}", .{}); } -pub fn isTemp(symbol: Symbol) bool { +pub fn isTemp(symbol: Symbol, zld: *Zld) bool { + const sym_name = zld.getString(symbol.strx); switch (symbol.payload) { .regular => |regular| { if (regular.linkage == .translation_unit) { - return mem.startsWith(u8, symbol.name, "l") or mem.startsWith(u8, symbol.name, "L"); + return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L"); } }, else => {}, @@ -202,24 +188,12 @@ pub fn isTemp(symbol: Symbol) bool { return false; } -pub fn needsTlvOffset(self: Symbol, zld: *Zld) bool { - if (self.payload != .regular) return false; - - const reg = self.payload.regular; - const seg = zld.load_command.items[reg.segment_id].Segment; - const sect = seg.sections.items[reg.section_id]; - const sect_type = commands.sectionType(sect); - - return sect_type == macho.S_THREAD_LOCAL_VARIABLES; -} - pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { - const n_strx = try zld.makeString(symbol.name); const nlist = nlist: { switch (symbol.payload) { .regular => |regular| { var nlist = macho.nlist_64{ - .n_strx = n_strx, + .n_strx = symbol.strx, .n_type = macho.N_SECT, .n_sect = regular.sectionId(zld), .n_desc = 0, @@ -239,7 +213,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { .tentative => { // TODO break :nlist macho.nlist_64{ - .n_strx = n_strx, + .n_strx = symbol.strx, .n_type = macho.N_UNDF, .n_sect = 0, .n_desc = 0, @@ -248,7 +222,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { }, .proxy => |proxy| { break :nlist macho.nlist_64{ - .n_strx = n_strx, + .n_strx = symbol.strx, .n_type = macho.N_UNDF | macho.N_EXT, .n_sect = 0, .n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY, @@ -258,7 +232,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { .undef => { // TODO break :nlist macho.nlist_64{ - .n_strx = n_strx, + .n_strx = symbol.strx, .n_type = macho.N_UNDF, .n_sect = 0, .n_desc = 0, @@ -270,10 +244,6 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { return nlist; } -pub fn deinit(symbol: *Symbol, allocator: *Allocator) void { - allocator.free(symbol.name); -} - pub fn isStab(sym: macho.nlist_64) bool { return (macho.N_STAB & sym.n_type) != 0; } diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 62e34cb6b0..3e7d825d3c 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -113,7 +113,6 @@ stub_helper_stubs_start_off: ?u64 = null, blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{}, strtab: std.ArrayListUnmanaged(u8) = .{}, -strtab_cache: std.StringHashMapUnmanaged(u32) = .{}, has_dices: bool = false, has_stabs: bool = false, @@ -171,7 +170,7 @@ pub const TextBlock = struct { .n_value = reg.address, }); nlists.appendAssumeCapacity(.{ - .n_strx = try zld.makeString(sym.name), + .n_strx = sym.strx, .n_type = macho.N_FUN, .n_sect = section_id, .n_desc = 0, @@ -194,7 +193,7 @@ pub const TextBlock = struct { }, .global => { try nlists.append(.{ - .n_strx = try zld.makeString(sym.name), + .n_strx = sym.strx, .n_type = macho.N_GSYM, .n_sect = 0, .n_desc = 0, @@ -203,7 +202,7 @@ pub const TextBlock = struct { }, .static => { try nlists.append(.{ - .n_strx = try zld.makeString(sym.name), + .n_strx = sym.strx, .n_type = macho.N_STSYM, .n_sect = reg.sectionId(zld), .n_desc = 0, @@ -349,26 +348,20 @@ pub fn deinit(self: *Zld) void { self.dylibs.deinit(self.allocator); for (self.imports.items) |sym| { - sym.deinit(self.allocator); self.allocator.destroy(sym); } self.imports.deinit(self.allocator); for (self.locals.items) |sym| { - sym.deinit(self.allocator); self.allocator.destroy(sym); } self.locals.deinit(self.allocator); + for (self.globals.keys()) |key| { + self.allocator.free(key); + } self.globals.deinit(self.allocator); - { - var it = self.strtab_cache.keyIterator(); - while (it.next()) |key| { - self.allocator.free(key.*); - } - } - self.strtab_cache.deinit(self.allocator); self.strtab.deinit(self.allocator); // TODO dealloc all blocks @@ -1168,7 +1161,7 @@ fn allocateTextBlocks(self: *Zld) !void { sym.payload.regular.address = base_addr; log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{ - sym.name, + self.getString(sym.strx), base_addr, base_addr + block.size, block.size, @@ -1231,7 +1224,7 @@ fn writeTextBlocks(self: *Zld) !void { const sym = self.locals.items[block.local_sym_index]; log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{ - sym.name, + self.getString(sym.strx), aligned_base_off, aligned_base_off + block.size, block.size, @@ -1552,14 +1545,17 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { if (Symbol.isSect(sym) and !Symbol.isExt(sym)) { // Regular symbol local to translation unit - const symbol = try Symbol.new(self.allocator, sym_name); - symbol.payload = .{ - .regular = .{ - .linkage = .translation_unit, - .address = sym.n_value, - .weak_ref = Symbol.isWeakRef(sym), - .file = object, - .local_sym_index = @intCast(u32, self.locals.items.len), + const symbol = try self.allocator.create(Symbol); + symbol.* = .{ + .strx = try self.makeString(sym_name), + .payload = .{ + .regular = .{ + .linkage = .translation_unit, + .address = sym.n_value, + .weak_ref = Symbol.isWeakRef(sym), + .file = object, + .local_sym_index = @intCast(u32, self.locals.items.len), + }, }, }; try self.locals.append(self.allocator, symbol); @@ -1569,9 +1565,13 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { const symbol = self.globals.get(sym_name) orelse symbol: { // Insert new global symbol. - const symbol = try Symbol.new(self.allocator, sym_name); - symbol.payload.undef.file = object; - try self.globals.putNoClobber(self.allocator, symbol.name, symbol); + const symbol = try self.allocator.create(Symbol); + symbol.* = .{ + .strx = try self.makeString(sym_name), + .payload = .{ .undef = .{ .file = object } }, + }; + const alloc_name = try self.allocator.dupe(u8, sym_name); + try self.globals.putNoClobber(self.allocator, alloc_name, symbol); break :symbol symbol; }; @@ -1628,7 +1628,8 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { fn resolveSymbols(self: *Zld) !void { // TODO mimicking insertion of null symbol from incremental linker. // This will need to moved. - const null_sym = try Symbol.new(self.allocator, ""); + const null_sym = try self.allocator.create(Symbol); + null_sym.* = .{ .strx = 0, .payload = .{ .undef = .{} } }; try self.locals.append(self.allocator, null_sym); // First pass, resolve symbols in provided objects. @@ -1639,12 +1640,13 @@ fn resolveSymbols(self: *Zld) !void { // Second pass, resolve symbols in static libraries. var sym_it = self.globals.iterator(); while (sym_it.next()) |entry| { + const sym_name = entry.key_ptr.*; const symbol = entry.value_ptr.*; if (symbol.payload != .undef) continue; for (self.archives.items) |archive| { // Check if the entry exists in a static archive. - const offsets = archive.toc.get(symbol.name) orelse { + const offsets = archive.toc.get(sym_name) orelse { // No hit. continue; }; @@ -1734,21 +1736,27 @@ fn resolveSymbols(self: *Zld) !void { // Third pass, resolve symbols in dynamic libraries. { // Put dyld_stub_binder as an undefined special symbol. - const symbol = try Symbol.new(self.allocator, "dyld_stub_binder"); + const symbol = try self.allocator.create(Symbol); + symbol.* = .{ + .strx = try self.makeString("dyld_stub_binder"), + .payload = .{ .undef = .{} }, + }; const index = @intCast(u32, self.got_entries.items.len); symbol.got_index = index; try self.got_entries.append(self.allocator, symbol); - try self.globals.putNoClobber(self.allocator, symbol.name, symbol); + const alloc_name = try self.allocator.dupe(u8, "dyld_stub_binder"); + try self.globals.putNoClobber(self.allocator, alloc_name, symbol); } var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator); defer referenced.deinit(); - loop: for (self.globals.values()) |symbol| { + loop: for (self.globals.keys()) |sym_name| { + const symbol = self.globals.get(sym_name).?; if (symbol.payload != .undef) continue; for (self.dylibs.items) |dylib| { - if (!dylib.symbols.contains(symbol.name)) continue; + if (!dylib.symbols.contains(sym_name)) continue; try referenced.put(dylib, {}); const index = @intCast(u32, self.imports.items.len); @@ -1798,10 +1806,11 @@ fn resolveSymbols(self: *Zld) !void { } var has_undefined = false; - for (self.globals.values()) |symbol| { + for (self.globals.keys()) |sym_name| { + const symbol = self.globals.get(sym_name).?; if (symbol.payload != .undef) continue; - log.err("undefined reference to symbol '{s}'", .{symbol.name}); + log.err("undefined reference to symbol '{s}'", .{sym_name}); if (symbol.payload.undef.file) |file| { log.err(" | referenced in {s}", .{file.name.?}); } @@ -2344,7 +2353,7 @@ fn writeBindInfoTable(self: *Zld) !void { .offset = base_offset + sym.got_index.? * @sizeOf(u64), .segment_id = segment_id, .dylib_ordinal = proxy.dylibOrdinal(), - .name = sym.name, + .name = self.getString(sym.strx), }); } } @@ -2372,7 +2381,7 @@ fn writeBindInfoTable(self: *Zld) !void { .offset = binding.offset + base_offset, .segment_id = match.seg, .dylib_ordinal = proxy.dylibOrdinal(), - .name = bind_sym.name, + .name = self.getString(bind_sym.strx), }); } @@ -2395,7 +2404,7 @@ fn writeBindInfoTable(self: *Zld) !void { .offset = base_offset, .segment_id = segment_id, .dylib_ordinal = proxy.dylibOrdinal(), - .name = sym.name, + .name = self.getString(sym.strx), }); } @@ -2435,7 +2444,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void { .offset = base_offset + sym.stubs_index.? * @sizeOf(u64), .segment_id = segment_id, .dylib_ordinal = proxy.dylibOrdinal(), - .name = sym.name, + .name = self.getString(sym.strx), }); } } @@ -2547,7 +2556,7 @@ fn writeExportInfo(self: *Zld) !void { if (sym.payload != .regular) continue; const reg = sym.payload.regular; if (reg.linkage != .global) continue; - try sorted_globals.append(sym.name); + try sorted_globals.append(self.getString(sym.strx)); } std.sort.sort([]const u8, sorted_globals.items, {}, Sorter.lessThan); @@ -2556,10 +2565,10 @@ fn writeExportInfo(self: *Zld) !void { const sym = self.globals.get(sym_name) orelse unreachable; const reg = sym.payload.regular; - log.debug(" | putting '{s}' defined at 0x{x}", .{ sym.name, reg.address }); + log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, reg.address }); try trie.put(.{ - .name = sym.name, + .name = sym_name, .vmaddr_offset = reg.address - base_address, .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, }); @@ -2597,7 +2606,7 @@ fn writeSymbolTable(self: *Zld) !void { for (self.locals.items) |symbol, i| { if (i == 0) continue; // skip null symbol - if (symbol.isTemp()) continue; // TODO when merging codepaths, this should go into freelist + if (symbol.isTemp(self)) continue; // TODO when merging codepaths, this should go into freelist const reg = symbol.payload.regular; const nlist = try symbol.asNlist(self); @@ -2673,7 +2682,7 @@ fn writeSymbolTable(self: *Zld) !void { const nlist = try sym.asNlist(self); const id = @intCast(u32, undefs.items.len); try undefs.append(nlist); - try undef_dir.putNoClobber(sym.name, id); + try undef_dir.putNoClobber(self.getString(sym.strx), id); } const nlocals = locals.items.len; @@ -2735,7 +2744,8 @@ fn writeSymbolTable(self: *Zld) !void { stubs.reserved1 = 0; for (self.stubs.items) |sym| { - const id = undef_dir.get(sym.name) orelse unreachable; + const sym_name = self.getString(sym.strx); + const id = undef_dir.get(sym_name) orelse unreachable; try writer.writeIntLittle(u32, dysymtab.iundefsym + id); } @@ -2743,7 +2753,8 @@ fn writeSymbolTable(self: *Zld) !void { for (self.got_entries.items) |sym| { switch (sym.payload) { .proxy => { - const id = undef_dir.get(sym.name) orelse unreachable; + const sym_name = self.getString(sym.strx); + const id = undef_dir.get(sym_name) orelse unreachable; try writer.writeIntLittle(u32, dysymtab.iundefsym + id); }, else => { @@ -2754,7 +2765,8 @@ fn writeSymbolTable(self: *Zld) !void { la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries; for (self.stubs.items) |sym| { - const id = undef_dir.get(sym.name) orelse unreachable; + const sym_name = self.getString(sym.strx); + const id = undef_dir.get(sym_name) orelse unreachable; try writer.writeIntLittle(u32, dysymtab.iundefsym + id); } @@ -2940,11 +2952,6 @@ fn writeHeader(self: *Zld) !void { } pub fn makeString(self: *Zld, string: []const u8) !u32 { - if (self.strtab_cache.get(string)) |off| { - log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off }); - return off; - } - try self.strtab.ensureUnusedCapacity(self.allocator, string.len + 1); const new_off = @intCast(u32, self.strtab.items.len); @@ -2953,12 +2960,10 @@ pub fn makeString(self: *Zld, string: []const u8) !u32 { self.strtab.appendSliceAssumeCapacity(string); self.strtab.appendAssumeCapacity(0); - try self.strtab_cache.putNoClobber(self.allocator, try self.allocator.dupe(u8, string), new_off); - return new_off; } -pub fn getString(self: *Zld, off: u32) ?[]const u8 { +pub fn getString(self: *Zld, off: u32) []const u8 { assert(off < self.strtab.items.len); return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off)); } diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig index c8b176c9c2..e1631081d1 100644 --- a/src/link/MachO/reloc.zig +++ b/src/link/MachO/reloc.zig @@ -407,7 +407,7 @@ pub const Relocation = struct { const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment; const got = dc_seg.sections.items[zld.got_section_index.?]; const got_index = self.target.got_index orelse { - log.err("expected GOT entry for symbol '{s}'", .{self.target.name}); + log.err("expected GOT entry for symbol '{s}'", .{zld.getString(self.target.strx)}); log.err(" this is an internal linker error", .{}); return error.FailedToResolveRelocationTarget; }; @@ -446,8 +446,8 @@ pub const Relocation = struct { break :blk reg.address; }, - .proxy => |proxy| { - if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) { + .proxy => { + if (mem.eql(u8, zld.getString(self.target.strx), "__tlv_bootstrap")) { break :blk 0; // Dynamically bound by dyld. } @@ -460,7 +460,9 @@ pub const Relocation = struct { break :blk stubs.addr + stubs_index * stubs.reserved2; }, else => { - log.err("failed to resolve symbol '{s}' as a relocation target", .{self.target.name}); + log.err("failed to resolve symbol '{s}' as a relocation target", .{ + zld.getString(self.target.strx), + }); log.err(" this is an internal linker error", .{}); return error.FailedToResolveRelocationTarget; }, @@ -634,7 +636,10 @@ pub const Parser = struct { out_rel.target.got_index = index; try self.zld.got_entries.append(self.zld.allocator, out_rel.target); - log.debug("adding GOT entry for symbol {s} at index {}", .{ out_rel.target.name, index }); + log.debug("adding GOT entry for symbol {s} at index {}", .{ + self.zld.getString(out_rel.target.strx), + index, + }); } else if (out_rel.payload == .unsigned) { const sym = out_rel.target; switch (sym.payload) { @@ -697,14 +702,14 @@ pub const Parser = struct { sym.stubs_index = index; try self.zld.stubs.append(self.zld.allocator, sym); - log.debug("adding stub entry for symbol {s} at index {}", .{ sym.name, index }); + log.debug("adding stub entry for symbol {s} at index {}", .{ self.zld.getString(sym.strx), index }); } } } fn parseBaseRelInfo(self: *Parser, rel: macho.relocation_info) !Relocation { const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); - const target = try self.object.symbolFromReloc(rel); + const target = try self.object.symbolFromReloc(self.zld, rel); return Relocation{ .offset = offset, .target = target, @@ -888,7 +893,7 @@ pub const Parser = struct { assert(rel.r_pcrel == 0); assert(self.subtractor == null); - self.subtractor = try self.object.symbolFromReloc(rel); + self.subtractor = try self.object.symbolFromReloc(self.zld, rel); } fn parseLoad(self: *Parser, rel: macho.relocation_info) !Relocation {