| author | |
| committer | |
| log | 81183365852e7f871500a3f71810ae3b468f0027 |
| tree | 96a4de9d67ed5cf4330c81564c23973db381a7d3 |
| parent | 3562edf13772bca66b4f04fc87be25b518393221 |
Now, we don't erroneously write to the string table on every
write of global and undef symbols.3 files changed, 80 insertions(+), 108 deletions(-)
src/codegen.zig+5-13| ... | ... | @@ -1920,21 +1920,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1920 | 1920 | } |
| 1921 | 1921 | } else if (func_value.castTag(.extern_fn)) |func_payload| { |
| 1922 | 1922 | const decl = func_payload.data; |
| 1923 | // We don't free the decl_name immediately unless it already exists. | |
| 1924 | // If it doesn't, it will get autofreed when we clean up the extern symbol table. | |
| 1925 | 1923 | const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name}); |
| 1924 | defer self.bin_file.allocator.free(decl_name); | |
| 1926 | 1925 | const already_defined = macho_file.extern_lazy_symbols.contains(decl_name); |
| 1927 | const symbol: u32 = if (macho_file.extern_lazy_symbols.getIndex(decl_name)) |index| blk: { | |
| 1928 | self.bin_file.allocator.free(decl_name); | |
| 1929 | break :blk @intCast(u32, index); | |
| 1930 | } else blk: { | |
| 1931 | const index = @intCast(u32, macho_file.extern_lazy_symbols.items().len); | |
| 1932 | try macho_file.extern_lazy_symbols.putNoClobber(self.bin_file.allocator, decl_name, .{ | |
| 1933 | .name = decl_name, | |
| 1934 | .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem. | |
| 1935 | }); | |
| 1936 | break :blk index; | |
| 1937 | }; | |
| 1926 | const symbol: u32 = if (macho_file.extern_lazy_symbols.getIndex(decl_name)) |index| | |
| 1927 | @intCast(u32, index) | |
| 1928 | else | |
| 1929 | try macho_file.addExternSymbol(decl_name); | |
| 1938 | 1930 | const start = self.code.items.len; |
| 1939 | 1931 | const len: usize = blk: { |
| 1940 | 1932 | switch (arch) { |
src/link/MachO.zig+39-50| ... | ... | @@ -1011,11 +1011,11 @@ pub fn deinit(self: *MachO) void { |
| 1011 | 1011 | ds.deinit(self.base.allocator); |
| 1012 | 1012 | } |
| 1013 | 1013 | for (self.extern_lazy_symbols.items()) |*entry| { |
| 1014 | entry.value.deinit(self.base.allocator); | |
| 1014 | self.base.allocator.free(entry.key); | |
| 1015 | 1015 | } |
| 1016 | 1016 | self.extern_lazy_symbols.deinit(self.base.allocator); |
| 1017 | 1017 | for (self.extern_nonlazy_symbols.items()) |*entry| { |
| 1018 | entry.value.deinit(self.base.allocator); | |
| 1018 | self.base.allocator.free(entry.key); | |
| 1019 | 1019 | } |
| 1020 | 1020 | self.extern_nonlazy_symbols.deinit(self.base.allocator); |
| 1021 | 1021 | self.pie_fixups.deinit(self.base.allocator); |
| ... | ... | @@ -2042,9 +2042,16 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2042 | 2042 | } |
| 2043 | 2043 | if (!self.extern_nonlazy_symbols.contains("dyld_stub_binder")) { |
| 2044 | 2044 | const index = @intCast(u32, self.extern_nonlazy_symbols.items().len); |
| 2045 | const name = try std.fmt.allocPrint(self.base.allocator, "dyld_stub_binder", .{}); | |
| 2045 | const name = try self.base.allocator.dupe(u8, "dyld_stub_binder"); | |
| 2046 | const offset = try self.makeString("dyld_stub_binder"); | |
| 2046 | 2047 | try self.extern_nonlazy_symbols.putNoClobber(self.base.allocator, name, .{ |
| 2047 | .name = name, | |
| 2048 | .inner = .{ | |
| 2049 | .n_strx = offset, | |
| 2050 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, | |
| 2051 | .n_sect = 0, | |
| 2052 | .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, | |
| 2053 | .n_value = 0, | |
| 2054 | }, | |
| 2048 | 2055 | .dylib_ordinal = 1, // TODO this is currently hardcoded. |
| 2049 | 2056 | .segment = self.data_const_segment_cmd_index.?, |
| 2050 | 2057 | .offset = index * @sizeOf(u64), |
| ... | ... | @@ -2222,15 +2229,15 @@ pub fn makeStaticString(comptime bytes: []const u8) [16]u8 { |
| 2222 | 2229 | return buf; |
| 2223 | 2230 | } |
| 2224 | 2231 | |
| 2225 | pub fn makeString(self: *MachO, bytes: []const u8) !u32 { | |
| 2232 | fn makeString(self: *MachO, bytes: []const u8) !u32 { | |
| 2226 | 2233 | try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1); |
| 2227 | const result = @intCast(u32, self.string_table.items.len); | |
| 2234 | const offset = @intCast(u32, self.string_table.items.len); | |
| 2228 | 2235 | self.string_table.appendSliceAssumeCapacity(bytes); |
| 2229 | 2236 | self.string_table.appendAssumeCapacity(0); |
| 2230 | 2237 | self.string_table_dirty = true; |
| 2231 | 2238 | if (self.d_sym) |*ds| |
| 2232 | 2239 | ds.string_table_dirty = true; |
| 2233 | return result; | |
| 2240 | return offset; | |
| 2234 | 2241 | } |
| 2235 | 2242 | |
| 2236 | 2243 | fn getString(self: *MachO, str_off: u32) []const u8 { |
| ... | ... | @@ -2246,6 +2253,23 @@ fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 { |
| 2246 | 2253 | return self.makeString(new_name); |
| 2247 | 2254 | } |
| 2248 | 2255 | |
| 2256 | pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { | |
| 2257 | const index = @intCast(u32, self.extern_lazy_symbols.items().len); | |
| 2258 | const offset = try self.makeString(name); | |
| 2259 | const sym_name = try self.base.allocator.dupe(u8, name); | |
| 2260 | try self.extern_lazy_symbols.putNoClobber(self.base.allocator, sym_name, .{ | |
| 2261 | .inner = .{ | |
| 2262 | .n_strx = offset, | |
| 2263 | .n_type = macho.N_UNDF | macho.N_EXT, | |
| 2264 | .n_sect = 0, | |
| 2265 | .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, | |
| 2266 | .n_value = 0, | |
| 2267 | }, | |
| 2268 | .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem. | |
| 2269 | }); | |
| 2270 | return index; | |
| 2271 | } | |
| 2272 | ||
| 2249 | 2273 | const NextSegmentAddressAndOffset = struct { |
| 2250 | 2274 | address: u64, |
| 2251 | 2275 | offset: u64, |
| ... | ... | @@ -2585,24 +2609,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2585 | 2609 | defer undefs.deinit(); |
| 2586 | 2610 | try undefs.ensureCapacity(nundefs); |
| 2587 | 2611 | for (self.extern_lazy_symbols.items()) |entry| { |
| 2588 | const name = try self.makeString(entry.key); | |
| 2589 | undefs.appendAssumeCapacity(.{ | |
| 2590 | .n_strx = name, | |
| 2591 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, | |
| 2592 | .n_sect = 0, | |
| 2593 | .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, | |
| 2594 | .n_value = 0, | |
| 2595 | }); | |
| 2612 | undefs.appendAssumeCapacity(entry.value.inner); | |
| 2596 | 2613 | } |
| 2597 | 2614 | for (self.extern_nonlazy_symbols.items()) |entry| { |
| 2598 | const name = try self.makeString(entry.key); | |
| 2599 | undefs.appendAssumeCapacity(.{ | |
| 2600 | .n_strx = name, | |
| 2601 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, | |
| 2602 | .n_sect = 0, | |
| 2603 | .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, | |
| 2604 | .n_value = 0, | |
| 2605 | }); | |
| 2615 | undefs.appendAssumeCapacity(entry.value.inner); | |
| 2606 | 2616 | } |
| 2607 | 2617 | |
| 2608 | 2618 | const locals_off = symtab.symoff; |
| ... | ... | @@ -2781,19 +2791,12 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2781 | 2791 | const tracy = trace(@src()); |
| 2782 | 2792 | defer tracy.end(); |
| 2783 | 2793 | |
| 2784 | var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_lazy_symbols.items().len); | |
| 2785 | defer self.base.allocator.free(symbols); | |
| 2786 | ||
| 2787 | for (self.extern_lazy_symbols.items()) |*entry, i| { | |
| 2788 | symbols[i] = &entry.value; | |
| 2789 | } | |
| 2790 | ||
| 2791 | const size = try rebaseInfoSize(symbols); | |
| 2794 | const size = try rebaseInfoSize(self.extern_lazy_symbols.items()); | |
| 2792 | 2795 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2793 | 2796 | defer self.base.allocator.free(buffer); |
| 2794 | 2797 | |
| 2795 | 2798 | var stream = std.io.fixedBufferStream(buffer); |
| 2796 | try writeRebaseInfo(symbols, stream.writer()); | |
| 2799 | try writeRebaseInfo(self.extern_lazy_symbols.items(), stream.writer()); | |
| 2797 | 2800 | |
| 2798 | 2801 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2799 | 2802 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| ... | ... | @@ -2820,19 +2823,12 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2820 | 2823 | const tracy = trace(@src()); |
| 2821 | 2824 | defer tracy.end(); |
| 2822 | 2825 | |
| 2823 | var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_nonlazy_symbols.items().len); | |
| 2824 | defer self.base.allocator.free(symbols); | |
| 2825 | ||
| 2826 | for (self.extern_nonlazy_symbols.items()) |*entry, i| { | |
| 2827 | symbols[i] = &entry.value; | |
| 2828 | } | |
| 2829 | ||
| 2830 | const size = try bindInfoSize(symbols); | |
| 2826 | const size = try bindInfoSize(self.extern_nonlazy_symbols.items()); | |
| 2831 | 2827 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2832 | 2828 | defer self.base.allocator.free(buffer); |
| 2833 | 2829 | |
| 2834 | 2830 | var stream = std.io.fixedBufferStream(buffer); |
| 2835 | try writeBindInfo(symbols, stream.writer()); | |
| 2831 | try writeBindInfo(self.extern_nonlazy_symbols.items(), stream.writer()); | |
| 2836 | 2832 | |
| 2837 | 2833 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2838 | 2834 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| ... | ... | @@ -2856,19 +2852,12 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2856 | 2852 | fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2857 | 2853 | if (!self.lazy_binding_info_dirty) return; |
| 2858 | 2854 | |
| 2859 | var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_lazy_symbols.items().len); | |
| 2860 | defer self.base.allocator.free(symbols); | |
| 2861 | ||
| 2862 | for (self.extern_lazy_symbols.items()) |*entry, i| { | |
| 2863 | symbols[i] = &entry.value; | |
| 2864 | } | |
| 2865 | ||
| 2866 | const size = try lazyBindInfoSize(symbols); | |
| 2855 | const size = try lazyBindInfoSize(self.extern_lazy_symbols.items()); | |
| 2867 | 2856 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2868 | 2857 | defer self.base.allocator.free(buffer); |
| 2869 | 2858 | |
| 2870 | 2859 | var stream = std.io.fixedBufferStream(buffer); |
| 2871 | try writeLazyBindInfo(symbols, stream.writer()); | |
| 2860 | try writeLazyBindInfo(self.extern_lazy_symbols.items(), stream.writer()); | |
| 2872 | 2861 | |
| 2873 | 2862 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2874 | 2863 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
src/link/MachO/imports.zig+36-45| ... | ... | @@ -7,12 +7,8 @@ const assert = std.debug.assert; |
| 7 | 7 | const Allocator = mem.Allocator; |
| 8 | 8 | |
| 9 | 9 | pub const ExternSymbol = struct { |
| 10 | /// Symbol name. | |
| 11 | /// We own the memory, therefore we'll need to free it by calling `deinit`. | |
| 12 | /// In self-hosted, we don't expect it to be null ever. | |
| 13 | /// However, this is for backwards compatibility with LLD when | |
| 14 | /// we'll be patching things up post mortem. | |
| 15 | name: ?[]u8 = null, | |
| 10 | /// MachO symbol table entry. | |
| 11 | inner: macho.nlist_64, | |
| 16 | 12 | |
| 17 | 13 | /// Id of the dynamic library where the specified entries can be found. |
| 18 | 14 | /// Id of 0 means self. |
| ... | ... | @@ -26,22 +22,16 @@ pub const ExternSymbol = struct { |
| 26 | 22 | |
| 27 | 23 | /// Offset relative to the start address of the `segment`. |
| 28 | 24 | offset: u32 = 0, |
| 29 | ||
| 30 | pub fn deinit(self: *ExternSymbol, allocator: *Allocator) void { | |
| 31 | if (self.name) |name| { | |
| 32 | allocator.free(name); | |
| 33 | } | |
| 34 | } | |
| 35 | 25 | }; |
| 36 | 26 | |
| 37 | pub fn rebaseInfoSize(symbols: []*const ExternSymbol) !u64 { | |
| 27 | pub fn rebaseInfoSize(symbols: anytype) !u64 { | |
| 38 | 28 | var stream = std.io.countingWriter(std.io.null_writer); |
| 39 | 29 | var writer = stream.writer(); |
| 40 | 30 | var size: u64 = 0; |
| 41 | 31 | |
| 42 | for (symbols) |symbol| { | |
| 32 | for (symbols) |entry| { | |
| 43 | 33 | size += 2; |
| 44 | try leb.writeILEB128(writer, symbol.offset); | |
| 34 | try leb.writeILEB128(writer, entry.value.offset); | |
| 45 | 35 | size += 1; |
| 46 | 36 | } |
| 47 | 37 | |
| ... | ... | @@ -49,8 +39,9 @@ pub fn rebaseInfoSize(symbols: []*const ExternSymbol) !u64 { |
| 49 | 39 | return size; |
| 50 | 40 | } |
| 51 | 41 | |
| 52 | pub fn writeRebaseInfo(symbols: []*const ExternSymbol, writer: anytype) !void { | |
| 53 | for (symbols) |symbol| { | |
| 42 | pub fn writeRebaseInfo(symbols: anytype, writer: anytype) !void { | |
| 43 | for (symbols) |entry| { | |
| 44 | const symbol = entry.value; | |
| 54 | 45 | try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.REBASE_TYPE_POINTER)); |
| 55 | 46 | try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment)); |
| 56 | 47 | try leb.writeILEB128(writer, symbol.offset); |
| ... | ... | @@ -59,23 +50,23 @@ pub fn writeRebaseInfo(symbols: []*const ExternSymbol, writer: anytype) !void { |
| 59 | 50 | try writer.writeByte(macho.REBASE_OPCODE_DONE); |
| 60 | 51 | } |
| 61 | 52 | |
| 62 | pub fn bindInfoSize(symbols: []*const ExternSymbol) !u64 { | |
| 53 | pub fn bindInfoSize(symbols: anytype) !u64 { | |
| 63 | 54 | var stream = std.io.countingWriter(std.io.null_writer); |
| 64 | 55 | var writer = stream.writer(); |
| 65 | 56 | var size: u64 = 0; |
| 66 | 57 | |
| 67 | for (symbols) |symbol| { | |
| 58 | for (symbols) |entry| { | |
| 59 | const symbol = entry.value; | |
| 60 | ||
| 68 | 61 | size += 1; |
| 69 | 62 | if (symbol.dylib_ordinal > 15) { |
| 70 | 63 | try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal)); |
| 71 | 64 | } |
| 72 | 65 | size += 1; |
| 73 | 66 | |
| 74 | if (symbol.name) |name| { | |
| 75 | size += 1; | |
| 76 | size += name.len; | |
| 77 | size += 1; | |
| 78 | } | |
| 67 | size += 1; | |
| 68 | size += entry.key.len; | |
| 69 | size += 1; | |
| 79 | 70 | |
| 80 | 71 | size += 1; |
| 81 | 72 | try leb.writeILEB128(writer, symbol.offset); |
| ... | ... | @@ -86,8 +77,10 @@ pub fn bindInfoSize(symbols: []*const ExternSymbol) !u64 { |
| 86 | 77 | return size; |
| 87 | 78 | } |
| 88 | 79 | |
| 89 | pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void { | |
| 90 | for (symbols) |symbol| { | |
| 80 | pub fn writeBindInfo(symbols: anytype, writer: anytype) !void { | |
| 81 | for (symbols) |entry| { | |
| 82 | const symbol = entry.value; | |
| 83 | ||
| 91 | 84 | if (symbol.dylib_ordinal > 15) { |
| 92 | 85 | try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); |
| 93 | 86 | try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal)); |
| ... | ... | @@ -98,11 +91,9 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void { |
| 98 | 91 | } |
| 99 | 92 | try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.BIND_TYPE_POINTER)); |
| 100 | 93 | |
| 101 | if (symbol.name) |name| { | |
| 102 | try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags. | |
| 103 | try writer.writeAll(name); | |
| 104 | try writer.writeByte(0); | |
| 105 | } | |
| 94 | try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags. | |
| 95 | try writer.writeAll(entry.key); | |
| 96 | try writer.writeByte(0); | |
| 106 | 97 | |
| 107 | 98 | try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment)); |
| 108 | 99 | try leb.writeILEB128(writer, symbol.offset); |
| ... | ... | @@ -111,23 +102,24 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void { |
| 111 | 102 | } |
| 112 | 103 | } |
| 113 | 104 | |
| 114 | pub fn lazyBindInfoSize(symbols: []*const ExternSymbol) !u64 { | |
| 105 | pub fn lazyBindInfoSize(symbols: anytype) !u64 { | |
| 115 | 106 | var stream = std.io.countingWriter(std.io.null_writer); |
| 116 | 107 | var writer = stream.writer(); |
| 117 | 108 | var size: u64 = 0; |
| 118 | 109 | |
| 119 | for (symbols) |symbol| { | |
| 110 | for (symbols) |entry| { | |
| 111 | const symbol = entry.value; | |
| 120 | 112 | size += 1; |
| 121 | 113 | try leb.writeILEB128(writer, symbol.offset); |
| 122 | 114 | size += 1; |
| 123 | 115 | if (symbol.dylib_ordinal > 15) { |
| 124 | 116 | try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal)); |
| 125 | 117 | } |
| 126 | if (symbol.name) |name| { | |
| 127 | size += 1; | |
| 128 | size += name.len; | |
| 129 | size += 1; | |
| 130 | } | |
| 118 | ||
| 119 | size += 1; | |
| 120 | size += entry.key.len; | |
| 121 | size += 1; | |
| 122 | ||
| 131 | 123 | size += 2; |
| 132 | 124 | } |
| 133 | 125 | |
| ... | ... | @@ -135,8 +127,9 @@ pub fn lazyBindInfoSize(symbols: []*const ExternSymbol) !u64 { |
| 135 | 127 | return size; |
| 136 | 128 | } |
| 137 | 129 | |
| 138 | pub fn writeLazyBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void { | |
| 139 | for (symbols) |symbol| { | |
| 130 | pub fn writeLazyBindInfo(symbols: anytype, writer: anytype) !void { | |
| 131 | for (symbols) |entry| { | |
| 132 | const symbol = entry.value; | |
| 140 | 133 | try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment)); |
| 141 | 134 | try leb.writeILEB128(writer, symbol.offset); |
| 142 | 135 | |
| ... | ... | @@ -149,11 +142,9 @@ pub fn writeLazyBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void |
| 149 | 142 | try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal))); |
| 150 | 143 | } |
| 151 | 144 | |
| 152 | if (symbol.name) |name| { | |
| 153 | try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags. | |
| 154 | try writer.writeAll(name); | |
| 155 | try writer.writeByte(0); | |
| 156 | } | |
| 145 | try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags. | |
| 146 | try writer.writeAll(entry.key); | |
| 147 | try writer.writeByte(0); | |
| 157 | 148 | |
| 158 | 149 | try writer.writeByte(macho.BIND_OPCODE_DO_BIND); |
| 159 | 150 | try writer.writeByte(macho.BIND_OPCODE_DONE); |