authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-16 23:55:52+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-17 12:10:39+01:00
logb9fa80e5880ed04f0cfd29f753297cbfebf77f2d
tree8989cdf2806ffc2cc81257d8bfeec76d5bd6d001
parent1181543dadc48e296f0de88673a46ba37841ae24

macho: use latest bind functionality


3 files changed, 237 insertions(+), 176 deletions(-)

src/link/MachO.zig+92-24
......@@ -12,6 +12,7 @@ const aarch64 = @import("../codegen/aarch64.zig");
1212const math = std.math;
1313const mem = std.mem;
1414
15const bind = @import("MachO/bind.zig");
1516const trace = @import("../tracy.zig").trace;
1617const build_options = @import("build_options");
1718const Module = @import("../Module.zig");
......@@ -26,7 +27,6 @@ const Trie = @import("MachO/Trie.zig");
2627const CodeSignature = @import("MachO/CodeSignature.zig");
2728
2829usingnamespace @import("MachO/commands.zig");
29usingnamespace @import("MachO/imports.zig");
3030
3131pub const base_tag: File.Tag = File.Tag.macho;
3232
......@@ -108,9 +108,9 @@ locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
108108/// Table of all global symbols
109109globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
110110/// Table of all extern nonlazy symbols, indexed by name.
111nonlazy_imports: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{},
111nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
112112/// Table of all extern lazy symbols, indexed by name.
113lazy_imports: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{},
113lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
114114
115115locals_free_list: std.ArrayListUnmanaged(u32) = .{},
116116globals_free_list: std.ArrayListUnmanaged(u32) = .{},
......@@ -169,6 +169,17 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{},
169169/// rather than sitting in the global scope.
170170stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{},
171171
172pub const Import = struct {
173 /// MachO symbol table entry.
174 symbol: macho.nlist_64,
175
176 /// Id of the dynamic library where the specified entries can be found.
177 dylib_ordinal: i64,
178
179 /// Index of this import within the import list.
180 index: u32,
181};
182
172183pub const PieFixup = struct {
173184 /// Target address we wanted to address in absolute terms.
174185 address: u64,
......@@ -1285,9 +1296,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12851296 try self.writeStubInStubHelper(fixup.symbol);
12861297 try self.writeLazySymbolPointer(fixup.symbol);
12871298
1288 const extern_sym = &self.lazy_imports.items()[fixup.symbol].value;
1289 extern_sym.segment = self.data_segment_cmd_index.?;
1290 extern_sym.offset = fixup.symbol * @sizeOf(u64);
12911299 self.rebase_info_dirty = true;
12921300 self.lazy_binding_info_dirty = true;
12931301 }
......@@ -2065,7 +2073,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
20652073 const name = try self.base.allocator.dupe(u8, "dyld_stub_binder");
20662074 const offset = try self.makeString("dyld_stub_binder");
20672075 try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{
2068 .inner = .{
2076 .symbol = .{
20692077 .n_strx = offset,
20702078 .n_type = std.macho.N_UNDF | std.macho.N_EXT,
20712079 .n_sect = 0,
......@@ -2073,8 +2081,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
20732081 .n_value = 0,
20742082 },
20752083 .dylib_ordinal = 1, // TODO this is currently hardcoded.
2076 .segment = self.data_const_segment_cmd_index.?,
2077 .offset = index * @sizeOf(u64),
2084 .index = index,
20782085 });
20792086 self.binding_info_dirty = true;
20802087 }
......@@ -2238,7 +2245,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
22382245 const sym_name = try self.base.allocator.dupe(u8, name);
22392246 const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem.
22402247 try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{
2241 .inner = .{
2248 .symbol = .{
22422249 .n_strx = offset,
22432250 .n_type = macho.N_UNDF | macho.N_EXT,
22442251 .n_sect = 0,
......@@ -2246,6 +2253,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
22462253 .n_value = 0,
22472254 },
22482255 .dylib_ordinal = dylib_ordinal,
2256 .index = index,
22492257 });
22502258 log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal });
22512259 return index;
......@@ -2767,10 +2775,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
27672775 defer undefs.deinit();
27682776 try undefs.ensureCapacity(nundefs);
27692777 for (self.lazy_imports.items()) |entry| {
2770 undefs.appendAssumeCapacity(entry.value.inner);
2778 undefs.appendAssumeCapacity(entry.value.symbol);
27712779 }
27722780 for (self.nonlazy_imports.items()) |entry| {
2773 undefs.appendAssumeCapacity(entry.value.inner);
2781 undefs.appendAssumeCapacity(entry.value.symbol);
27742782 }
27752783
27762784 const locals_off = symtab.symoff;
......@@ -2832,20 +2840,20 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
28322840 var writer = stream.writer();
28332841
28342842 stubs.reserved1 = 0;
2835 for (self.lazy_imports.items()) |_, i| {
2843 for (lazy) |_, i| {
28362844 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
28372845 try writer.writeIntLittle(u32, symtab_idx);
28382846 }
28392847
28402848 const base_id = @intCast(u32, lazy.len);
28412849 got.reserved1 = base_id;
2842 for (self.nonlazy_imports.items()) |_, i| {
2850 for (nonlazy) |_, i| {
28432851 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);
28442852 try writer.writeIntLittle(u32, symtab_idx);
28452853 }
28462854
28472855 la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len);
2848 for (self.lazy_imports.items()) |_, i| {
2856 for (lazy) |_, i| {
28492857 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
28502858 try writer.writeIntLittle(u32, symtab_idx);
28512859 }
......@@ -2962,14 +2970,33 @@ fn writeRebaseInfoTable(self: *MachO) !void {
29622970 const tracy = trace(@src());
29632971 defer tracy.end();
29642972
2965 const size = try rebaseInfoSize(self.lazy_imports.items());
2973 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
2974 defer pointers.deinit();
2975
2976 if (self.la_symbol_ptr_section_index) |idx| {
2977 try pointers.ensureCapacity(pointers.items.len + self.lazy_imports.items().len);
2978 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2979 const sect = seg.sections.items[idx];
2980 const base_offset = sect.addr - seg.inner.vmaddr;
2981 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
2982
2983 for (self.lazy_imports.items()) |entry| {
2984 pointers.appendAssumeCapacity(.{
2985 .offset = base_offset + entry.value.index * @sizeOf(u64),
2986 .segment_id = segment_id,
2987 });
2988 }
2989 }
2990
2991 std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);
2992
2993 const size = try bind.rebaseInfoSize(pointers.items);
29662994 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
29672995 defer self.base.allocator.free(buffer);
29682996
29692997 var stream = std.io.fixedBufferStream(buffer);
2970 try writeRebaseInfo(self.lazy_imports.items(), stream.writer());
2998 try bind.writeRebaseInfo(pointers.items, stream.writer());
29712999
2972 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
29733000 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
29743001 const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off);
29753002 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
......@@ -2994,14 +3021,33 @@ fn writeBindingInfoTable(self: *MachO) !void {
29943021 const tracy = trace(@src());
29953022 defer tracy.end();
29963023
2997 const size = try bindInfoSize(self.nonlazy_imports.items());
3024 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
3025 defer pointers.deinit();
3026
3027 if (self.data_got_section_index) |idx| {
3028 try pointers.ensureCapacity(pointers.items.len + self.nonlazy_imports.items().len);
3029 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
3030 const sect = seg.sections.items[idx];
3031 const base_offset = sect.addr - seg.inner.vmaddr;
3032 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
3033
3034 for (self.nonlazy_imports.items()) |entry| {
3035 pointers.appendAssumeCapacity(.{
3036 .offset = base_offset + entry.value.index * @sizeOf(u64),
3037 .segment_id = segment_id,
3038 .dylib_ordinal = entry.value.dylib_ordinal,
3039 .name = entry.key,
3040 });
3041 }
3042 }
3043
3044 const size = try bind.bindInfoSize(pointers.items);
29983045 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
29993046 defer self.base.allocator.free(buffer);
30003047
30013048 var stream = std.io.fixedBufferStream(buffer);
3002 try writeBindInfo(self.nonlazy_imports.items(), stream.writer());
3049 try bind.writeBindInfo(pointers.items, stream.writer());
30033050
3004 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
30053051 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
30063052 const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off);
30073053 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
......@@ -3023,14 +3069,36 @@ fn writeBindingInfoTable(self: *MachO) !void {
30233069fn writeLazyBindingInfoTable(self: *MachO) !void {
30243070 if (!self.lazy_binding_info_dirty) return;
30253071
3026 const size = try lazyBindInfoSize(self.lazy_imports.items());
3072 const tracy = trace(@src());
3073 defer tracy.end();
3074
3075 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
3076 defer pointers.deinit();
3077
3078 if (self.la_symbol_ptr_section_index) |idx| {
3079 try pointers.ensureCapacity(self.lazy_imports.items().len);
3080 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
3081 const sect = seg.sections.items[idx];
3082 const base_offset = sect.addr - seg.inner.vmaddr;
3083 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
3084
3085 for (self.lazy_imports.items()) |entry| {
3086 pointers.appendAssumeCapacity(.{
3087 .offset = base_offset + entry.value.index * @sizeOf(u64),
3088 .segment_id = segment_id,
3089 .dylib_ordinal = entry.value.dylib_ordinal,
3090 .name = entry.key,
3091 });
3092 }
3093 }
3094
3095 const size = try bind.lazyBindInfoSize(pointers.items);
30273096 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
30283097 defer self.base.allocator.free(buffer);
30293098
30303099 var stream = std.io.fixedBufferStream(buffer);
3031 try writeLazyBindInfo(self.lazy_imports.items(), stream.writer());
3100 try bind.writeLazyBindInfo(pointers.items, stream.writer());
30323101
3033 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
30343102 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
30353103 const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off);
30363104 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
src/link/MachO/bind.zig created+145
......@@ -0,0 +1,145 @@
1const std = @import("std");
2const leb = std.leb;
3const macho = std.macho;
4
5pub const Pointer = struct {
6 offset: u64,
7 segment_id: u16,
8 dylib_ordinal: ?i64 = null,
9 name: ?[]const u8 = null,
10};
11
12pub fn pointerCmp(context: void, a: Pointer, b: Pointer) bool {
13 if (a.segment_id < b.segment_id) return true;
14 if (a.segment_id == b.segment_id) {
15 return a.offset < b.offset;
16 }
17 return false;
18}
19
20pub fn rebaseInfoSize(pointers: []const Pointer) !u64 {
21 var stream = std.io.countingWriter(std.io.null_writer);
22 var writer = stream.writer();
23 var size: u64 = 0;
24
25 for (pointers) |pointer| {
26 size += 2;
27 try leb.writeILEB128(writer, pointer.offset);
28 size += 1;
29 }
30
31 size += 1 + stream.bytes_written;
32 return size;
33}
34
35pub fn writeRebaseInfo(pointers: []const Pointer, writer: anytype) !void {
36 for (pointers) |pointer| {
37 try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.REBASE_TYPE_POINTER));
38 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id));
39
40 try leb.writeILEB128(writer, pointer.offset);
41 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @truncate(u4, 1));
42 }
43 try writer.writeByte(macho.REBASE_OPCODE_DONE);
44}
45
46pub fn bindInfoSize(pointers: []const Pointer) !u64 {
47 var stream = std.io.countingWriter(std.io.null_writer);
48 var writer = stream.writer();
49 var size: u64 = 0;
50
51 for (pointers) |pointer| {
52 size += 1;
53 if (pointer.dylib_ordinal.? > 15) {
54 try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?));
55 }
56 size += 1;
57
58 size += 1;
59 size += pointer.name.?.len;
60 size += 1;
61
62 size += 1;
63
64 try leb.writeILEB128(writer, pointer.offset);
65 size += 1;
66 }
67
68 size += stream.bytes_written + 1;
69 return size;
70}
71
72pub fn writeBindInfo(pointers: []const Pointer, writer: anytype) !void {
73 for (pointers) |pointer| {
74 if (pointer.dylib_ordinal.? > 15) {
75 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
76 try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?));
77 } else if (pointer.dylib_ordinal.? > 0) {
78 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
79 } else {
80 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
81 }
82 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.BIND_TYPE_POINTER));
83
84 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags.
85 try writer.writeAll(pointer.name.?);
86 try writer.writeByte(0);
87
88 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id));
89
90 try leb.writeILEB128(writer, pointer.offset);
91 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
92 }
93
94 try writer.writeByte(macho.BIND_OPCODE_DONE);
95}
96
97pub fn lazyBindInfoSize(pointers: []const Pointer) !u64 {
98 var stream = std.io.countingWriter(std.io.null_writer);
99 var writer = stream.writer();
100 var size: u64 = 0;
101
102 for (pointers) |pointer| {
103 size += 1;
104
105 try leb.writeILEB128(writer, pointer.offset);
106
107 size += 1;
108 if (pointer.dylib_ordinal.? > 15) {
109 try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?));
110 }
111
112 size += 1;
113 size += pointer.name.?.len;
114 size += 1;
115
116 size += 2;
117 }
118
119 size += stream.bytes_written;
120 return size;
121}
122
123pub fn writeLazyBindInfo(pointers: []const Pointer, writer: anytype) !void {
124 for (pointers) |pointer| {
125 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id));
126
127 try leb.writeILEB128(writer, pointer.offset);
128
129 if (pointer.dylib_ordinal.? > 15) {
130 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
131 try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?));
132 } else if (pointer.dylib_ordinal.? > 0) {
133 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
134 } else {
135 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
136 }
137
138 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags.
139 try writer.writeAll(pointer.name.?);
140 try writer.writeByte(0);
141
142 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
143 try writer.writeByte(macho.BIND_OPCODE_DONE);
144 }
145}
src/link/MachO/imports.zig deleted-152
......@@ -1,152 +0,0 @@
1const std = @import("std");
2const leb = std.leb;
3const macho = std.macho;
4const mem = std.mem;
5
6const assert = std.debug.assert;
7const Allocator = mem.Allocator;
8
9pub const ExternSymbol = struct {
10 /// MachO symbol table entry.
11 inner: macho.nlist_64,
12
13 /// Id of the dynamic library where the specified entries can be found.
14 /// Id of 0 means self.
15 /// TODO this should really be an id into the table of all defined
16 /// dylibs.
17 dylib_ordinal: i64 = 0,
18
19 /// Id of the segment where this symbol is defined (will have its address
20 /// resolved).
21 segment: u16 = 0,
22
23 /// Offset relative to the start address of the `segment`.
24 offset: u32 = 0,
25};
26
27pub fn rebaseInfoSize(symbols: anytype) !u64 {
28 var stream = std.io.countingWriter(std.io.null_writer);
29 var writer = stream.writer();
30 var size: u64 = 0;
31
32 for (symbols) |entry| {
33 size += 2;
34 try leb.writeILEB128(writer, entry.value.offset);
35 size += 1;
36 }
37
38 size += 1 + stream.bytes_written;
39 return size;
40}
41
42pub fn writeRebaseInfo(symbols: anytype, writer: anytype) !void {
43 for (symbols) |entry| {
44 const symbol = entry.value;
45 try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.REBASE_TYPE_POINTER));
46 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
47 try leb.writeILEB128(writer, symbol.offset);
48 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @truncate(u4, 1));
49 }
50 try writer.writeByte(macho.REBASE_OPCODE_DONE);
51}
52
53pub fn bindInfoSize(symbols: anytype) !u64 {
54 var stream = std.io.countingWriter(std.io.null_writer);
55 var writer = stream.writer();
56 var size: u64 = 0;
57
58 for (symbols) |entry| {
59 const symbol = entry.value;
60
61 size += 1;
62 if (symbol.dylib_ordinal > 15) {
63 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
64 }
65 size += 1;
66
67 size += 1;
68 size += entry.key.len;
69 size += 1;
70
71 size += 1;
72 try leb.writeILEB128(writer, symbol.offset);
73 size += 2;
74 }
75
76 size += stream.bytes_written;
77 return size;
78}
79
80pub fn writeBindInfo(symbols: anytype, writer: anytype) !void {
81 for (symbols) |entry| {
82 const symbol = entry.value;
83
84 if (symbol.dylib_ordinal > 15) {
85 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
86 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
87 } else if (symbol.dylib_ordinal > 0) {
88 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal)));
89 } else {
90 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal)));
91 }
92 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.BIND_TYPE_POINTER));
93
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);
97
98 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
99 try leb.writeILEB128(writer, symbol.offset);
100 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
101 try writer.writeByte(macho.BIND_OPCODE_DONE);
102 }
103}
104
105pub fn lazyBindInfoSize(symbols: anytype) !u64 {
106 var stream = std.io.countingWriter(std.io.null_writer);
107 var writer = stream.writer();
108 var size: u64 = 0;
109
110 for (symbols) |entry| {
111 const symbol = entry.value;
112 size += 1;
113 try leb.writeILEB128(writer, symbol.offset);
114 size += 1;
115 if (symbol.dylib_ordinal > 15) {
116 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
117 }
118
119 size += 1;
120 size += entry.key.len;
121 size += 1;
122
123 size += 2;
124 }
125
126 size += stream.bytes_written;
127 return size;
128}
129
130pub fn writeLazyBindInfo(symbols: anytype, writer: anytype) !void {
131 for (symbols) |entry| {
132 const symbol = entry.value;
133 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
134 try leb.writeILEB128(writer, symbol.offset);
135
136 if (symbol.dylib_ordinal > 15) {
137 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
138 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
139 } else if (symbol.dylib_ordinal > 0) {
140 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal)));
141 } else {
142 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal)));
143 }
144
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);
148
149 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
150 try writer.writeByte(macho.BIND_OPCODE_DONE);
151 }
152}