authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-17 17:20:55+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-17 21:01:52+01:00
log81183365852e7f871500a3f71810ae3b468f0027
tree96a4de9d67ed5cf4330c81564c23973db381a7d3
parent3562edf13772bca66b4f04fc87be25b518393221

macho: refactor undef symbol handling

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,21 +1920,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1920 }1920 }
1921 } else if (func_value.castTag(.extern_fn)) |func_payload| {1921 } else if (func_value.castTag(.extern_fn)) |func_payload| {
1922 const decl = func_payload.data;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 const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name});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 const already_defined = macho_file.extern_lazy_symbols.contains(decl_name);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: {1926 const symbol: u32 = if (macho_file.extern_lazy_symbols.getIndex(decl_name)) |index|
1928 self.bin_file.allocator.free(decl_name);1927 @intCast(u32, index)
1929 break :blk @intCast(u32, index);1928 else
1930 } else blk: {1929 try macho_file.addExternSymbol(decl_name);
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 };
1938 const start = self.code.items.len;1930 const start = self.code.items.len;
1939 const len: usize = blk: {1931 const len: usize = blk: {
1940 switch (arch) {1932 switch (arch) {
src/link/MachO.zig+39-50
...@@ -1011,11 +1011,11 @@ pub fn deinit(self: *MachO) void {...@@ -1011,11 +1011,11 @@ pub fn deinit(self: *MachO) void {
1011 ds.deinit(self.base.allocator);1011 ds.deinit(self.base.allocator);
1012 }1012 }
1013 for (self.extern_lazy_symbols.items()) |*entry| {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 self.extern_lazy_symbols.deinit(self.base.allocator);1016 self.extern_lazy_symbols.deinit(self.base.allocator);
1017 for (self.extern_nonlazy_symbols.items()) |*entry| {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 self.extern_nonlazy_symbols.deinit(self.base.allocator);1020 self.extern_nonlazy_symbols.deinit(self.base.allocator);
1021 self.pie_fixups.deinit(self.base.allocator);1021 self.pie_fixups.deinit(self.base.allocator);
...@@ -2042,9 +2042,16 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -2042,9 +2042,16 @@ pub fn populateMissingMetadata(self: *MachO) !void {
2042 }2042 }
2043 if (!self.extern_nonlazy_symbols.contains("dyld_stub_binder")) {2043 if (!self.extern_nonlazy_symbols.contains("dyld_stub_binder")) {
2044 const index = @intCast(u32, self.extern_nonlazy_symbols.items().len);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 try self.extern_nonlazy_symbols.putNoClobber(self.base.allocator, name, .{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 .dylib_ordinal = 1, // TODO this is currently hardcoded.2055 .dylib_ordinal = 1, // TODO this is currently hardcoded.
2049 .segment = self.data_const_segment_cmd_index.?,2056 .segment = self.data_const_segment_cmd_index.?,
2050 .offset = index * @sizeOf(u64),2057 .offset = index * @sizeOf(u64),
...@@ -2222,15 +2229,15 @@ pub fn makeStaticString(comptime bytes: []const u8) [16]u8 {...@@ -2222,15 +2229,15 @@ pub fn makeStaticString(comptime bytes: []const u8) [16]u8 {
2222 return buf;2229 return buf;
2223}2230}
22242231
2225pub fn makeString(self: *MachO, bytes: []const u8) !u32 {2232fn makeString(self: *MachO, bytes: []const u8) !u32 {
2226 try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1);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 self.string_table.appendSliceAssumeCapacity(bytes);2235 self.string_table.appendSliceAssumeCapacity(bytes);
2229 self.string_table.appendAssumeCapacity(0);2236 self.string_table.appendAssumeCapacity(0);
2230 self.string_table_dirty = true;2237 self.string_table_dirty = true;
2231 if (self.d_sym) |*ds|2238 if (self.d_sym) |*ds|
2232 ds.string_table_dirty = true;2239 ds.string_table_dirty = true;
2233 return result;2240 return offset;
2234}2241}
22352242
2236fn getString(self: *MachO, str_off: u32) []const u8 {2243fn 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,6 +2253,23 @@ fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 {
2246 return self.makeString(new_name);2253 return self.makeString(new_name);
2247}2254}
22482255
2256pub 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
2249const NextSegmentAddressAndOffset = struct {2273const NextSegmentAddressAndOffset = struct {
2250 address: u64,2274 address: u64,
2251 offset: u64,2275 offset: u64,
...@@ -2585,24 +2609,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {...@@ -2585,24 +2609,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
2585 defer undefs.deinit();2609 defer undefs.deinit();
2586 try undefs.ensureCapacity(nundefs);2610 try undefs.ensureCapacity(nundefs);
2587 for (self.extern_lazy_symbols.items()) |entry| {2611 for (self.extern_lazy_symbols.items()) |entry| {
2588 const name = try self.makeString(entry.key);2612 undefs.appendAssumeCapacity(entry.value.inner);
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 });
2596 }2613 }
2597 for (self.extern_nonlazy_symbols.items()) |entry| {2614 for (self.extern_nonlazy_symbols.items()) |entry| {
2598 const name = try self.makeString(entry.key);2615 undefs.appendAssumeCapacity(entry.value.inner);
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 });
2606 }2616 }
26072617
2608 const locals_off = symtab.symoff;2618 const locals_off = symtab.symoff;
...@@ -2781,19 +2791,12 @@ fn writeRebaseInfoTable(self: *MachO) !void {...@@ -2781,19 +2791,12 @@ fn writeRebaseInfoTable(self: *MachO) !void {
2781 const tracy = trace(@src());2791 const tracy = trace(@src());
2782 defer tracy.end();2792 defer tracy.end();
27832793
2784 var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_lazy_symbols.items().len);2794 const size = try rebaseInfoSize(self.extern_lazy_symbols.items());
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);
2792 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));2795 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
2793 defer self.base.allocator.free(buffer);2796 defer self.base.allocator.free(buffer);
27942797
2795 var stream = std.io.fixedBufferStream(buffer);2798 var stream = std.io.fixedBufferStream(buffer);
2796 try writeRebaseInfo(symbols, stream.writer());2799 try writeRebaseInfo(self.extern_lazy_symbols.items(), stream.writer());
27972800
2798 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2801 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2799 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;2802 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
...@@ -2820,19 +2823,12 @@ fn writeBindingInfoTable(self: *MachO) !void {...@@ -2820,19 +2823,12 @@ fn writeBindingInfoTable(self: *MachO) !void {
2820 const tracy = trace(@src());2823 const tracy = trace(@src());
2821 defer tracy.end();2824 defer tracy.end();
28222825
2823 var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_nonlazy_symbols.items().len);2826 const size = try bindInfoSize(self.extern_nonlazy_symbols.items());
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);
2831 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));2827 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
2832 defer self.base.allocator.free(buffer);2828 defer self.base.allocator.free(buffer);
28332829
2834 var stream = std.io.fixedBufferStream(buffer);2830 var stream = std.io.fixedBufferStream(buffer);
2835 try writeBindInfo(symbols, stream.writer());2831 try writeBindInfo(self.extern_nonlazy_symbols.items(), stream.writer());
28362832
2837 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2833 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2838 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;2834 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
...@@ -2856,19 +2852,12 @@ fn writeBindingInfoTable(self: *MachO) !void {...@@ -2856,19 +2852,12 @@ fn writeBindingInfoTable(self: *MachO) !void {
2856fn writeLazyBindingInfoTable(self: *MachO) !void {2852fn writeLazyBindingInfoTable(self: *MachO) !void {
2857 if (!self.lazy_binding_info_dirty) return;2853 if (!self.lazy_binding_info_dirty) return;
28582854
2859 var symbols = try self.base.allocator.alloc(*const ExternSymbol, self.extern_lazy_symbols.items().len);2855 const size = try lazyBindInfoSize(self.extern_lazy_symbols.items());
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);
2867 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));2856 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
2868 defer self.base.allocator.free(buffer);2857 defer self.base.allocator.free(buffer);
28692858
2870 var stream = std.io.fixedBufferStream(buffer);2859 var stream = std.io.fixedBufferStream(buffer);
2871 try writeLazyBindInfo(symbols, stream.writer());2860 try writeLazyBindInfo(self.extern_lazy_symbols.items(), stream.writer());
28722861
2873 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2862 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2874 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;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,12 +7,8 @@ const assert = std.debug.assert;
7const Allocator = mem.Allocator;7const Allocator = mem.Allocator;
88
9pub const ExternSymbol = struct {9pub const ExternSymbol = struct {
10 /// Symbol name.10 /// MachO symbol table entry.
11 /// We own the memory, therefore we'll need to free it by calling `deinit`.11 inner: macho.nlist_64,
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,
1612
17 /// Id of the dynamic library where the specified entries can be found.13 /// Id of the dynamic library where the specified entries can be found.
18 /// Id of 0 means self.14 /// Id of 0 means self.
...@@ -26,22 +22,16 @@ pub const ExternSymbol = struct {...@@ -26,22 +22,16 @@ pub const ExternSymbol = struct {
2622
27 /// Offset relative to the start address of the `segment`.23 /// Offset relative to the start address of the `segment`.
28 offset: u32 = 0,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};
3626
37pub fn rebaseInfoSize(symbols: []*const ExternSymbol) !u64 {27pub fn rebaseInfoSize(symbols: anytype) !u64 {
38 var stream = std.io.countingWriter(std.io.null_writer);28 var stream = std.io.countingWriter(std.io.null_writer);
39 var writer = stream.writer();29 var writer = stream.writer();
40 var size: u64 = 0;30 var size: u64 = 0;
4131
42 for (symbols) |symbol| {32 for (symbols) |entry| {
43 size += 2;33 size += 2;
44 try leb.writeILEB128(writer, symbol.offset);34 try leb.writeILEB128(writer, entry.value.offset);
45 size += 1;35 size += 1;
46 }36 }
4737
...@@ -49,8 +39,9 @@ pub fn rebaseInfoSize(symbols: []*const ExternSymbol) !u64 {...@@ -49,8 +39,9 @@ pub fn rebaseInfoSize(symbols: []*const ExternSymbol) !u64 {
49 return size;39 return size;
50}40}
5141
52pub fn writeRebaseInfo(symbols: []*const ExternSymbol, writer: anytype) !void {42pub fn writeRebaseInfo(symbols: anytype, writer: anytype) !void {
53 for (symbols) |symbol| {43 for (symbols) |entry| {
44 const symbol = entry.value;
54 try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.REBASE_TYPE_POINTER));45 try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.REBASE_TYPE_POINTER));
55 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));46 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
56 try leb.writeILEB128(writer, symbol.offset);47 try leb.writeILEB128(writer, symbol.offset);
...@@ -59,23 +50,23 @@ pub fn writeRebaseInfo(symbols: []*const ExternSymbol, writer: anytype) !void {...@@ -59,23 +50,23 @@ pub fn writeRebaseInfo(symbols: []*const ExternSymbol, writer: anytype) !void {
59 try writer.writeByte(macho.REBASE_OPCODE_DONE);50 try writer.writeByte(macho.REBASE_OPCODE_DONE);
60}51}
6152
62pub fn bindInfoSize(symbols: []*const ExternSymbol) !u64 {53pub fn bindInfoSize(symbols: anytype) !u64 {
63 var stream = std.io.countingWriter(std.io.null_writer);54 var stream = std.io.countingWriter(std.io.null_writer);
64 var writer = stream.writer();55 var writer = stream.writer();
65 var size: u64 = 0;56 var size: u64 = 0;
6657
67 for (symbols) |symbol| {58 for (symbols) |entry| {
59 const symbol = entry.value;
60
68 size += 1;61 size += 1;
69 if (symbol.dylib_ordinal > 15) {62 if (symbol.dylib_ordinal > 15) {
70 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));63 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
71 }64 }
72 size += 1;65 size += 1;
7366
74 if (symbol.name) |name| {67 size += 1;
75 size += 1;68 size += entry.key.len;
76 size += name.len;69 size += 1;
77 size += 1;
78 }
7970
80 size += 1;71 size += 1;
81 try leb.writeILEB128(writer, symbol.offset);72 try leb.writeILEB128(writer, symbol.offset);
...@@ -86,8 +77,10 @@ pub fn bindInfoSize(symbols: []*const ExternSymbol) !u64 {...@@ -86,8 +77,10 @@ pub fn bindInfoSize(symbols: []*const ExternSymbol) !u64 {
86 return size;77 return size;
87}78}
8879
89pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {80pub fn writeBindInfo(symbols: anytype, writer: anytype) !void {
90 for (symbols) |symbol| {81 for (symbols) |entry| {
82 const symbol = entry.value;
83
91 if (symbol.dylib_ordinal > 15) {84 if (symbol.dylib_ordinal > 15) {
92 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);85 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
93 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));86 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
...@@ -98,11 +91,9 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {...@@ -98,11 +91,9 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {
98 }91 }
99 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.BIND_TYPE_POINTER));92 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.BIND_TYPE_POINTER));
10093
101 if (symbol.name) |name| {94 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags.
102 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);
103 try writer.writeAll(name);96 try writer.writeByte(0);
104 try writer.writeByte(0);
105 }
10697
107 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));98 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
108 try leb.writeILEB128(writer, symbol.offset);99 try leb.writeILEB128(writer, symbol.offset);
...@@ -111,23 +102,24 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {...@@ -111,23 +102,24 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {
111 }102 }
112}103}
113104
114pub fn lazyBindInfoSize(symbols: []*const ExternSymbol) !u64 {105pub fn lazyBindInfoSize(symbols: anytype) !u64 {
115 var stream = std.io.countingWriter(std.io.null_writer);106 var stream = std.io.countingWriter(std.io.null_writer);
116 var writer = stream.writer();107 var writer = stream.writer();
117 var size: u64 = 0;108 var size: u64 = 0;
118109
119 for (symbols) |symbol| {110 for (symbols) |entry| {
111 const symbol = entry.value;
120 size += 1;112 size += 1;
121 try leb.writeILEB128(writer, symbol.offset);113 try leb.writeILEB128(writer, symbol.offset);
122 size += 1;114 size += 1;
123 if (symbol.dylib_ordinal > 15) {115 if (symbol.dylib_ordinal > 15) {
124 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));116 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
125 }117 }
126 if (symbol.name) |name| {118
127 size += 1;119 size += 1;
128 size += name.len;120 size += entry.key.len;
129 size += 1;121 size += 1;
130 }122
131 size += 2;123 size += 2;
132 }124 }
133125
...@@ -135,8 +127,9 @@ pub fn lazyBindInfoSize(symbols: []*const ExternSymbol) !u64 {...@@ -135,8 +127,9 @@ pub fn lazyBindInfoSize(symbols: []*const ExternSymbol) !u64 {
135 return size;127 return size;
136}128}
137129
138pub fn writeLazyBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {130pub fn writeLazyBindInfo(symbols: anytype, writer: anytype) !void {
139 for (symbols) |symbol| {131 for (symbols) |entry| {
132 const symbol = entry.value;
140 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));133 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
141 try leb.writeILEB128(writer, symbol.offset);134 try leb.writeILEB128(writer, symbol.offset);
142135
...@@ -149,11 +142,9 @@ pub fn writeLazyBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void...@@ -149,11 +142,9 @@ pub fn writeLazyBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void
149 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal)));142 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal)));
150 }143 }
151144
152 if (symbol.name) |name| {145 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags.
153 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);
154 try writer.writeAll(name);147 try writer.writeByte(0);
155 try writer.writeByte(0);
156 }
157148
158 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);149 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
159 try writer.writeByte(macho.BIND_OPCODE_DONE);150 try writer.writeByte(macho.BIND_OPCODE_DONE);