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");...@@ -12,6 +12,7 @@ const aarch64 = @import("../codegen/aarch64.zig");
12const math = std.math;12const math = std.math;
13const mem = std.mem;13const mem = std.mem;
1414
15const bind = @import("MachO/bind.zig");
15const trace = @import("../tracy.zig").trace;16const trace = @import("../tracy.zig").trace;
16const build_options = @import("build_options");17const build_options = @import("build_options");
17const Module = @import("../Module.zig");18const Module = @import("../Module.zig");
...@@ -26,7 +27,6 @@ const Trie = @import("MachO/Trie.zig");...@@ -26,7 +27,6 @@ const Trie = @import("MachO/Trie.zig");
26const CodeSignature = @import("MachO/CodeSignature.zig");27const CodeSignature = @import("MachO/CodeSignature.zig");
2728
28usingnamespace @import("MachO/commands.zig");29usingnamespace @import("MachO/commands.zig");
29usingnamespace @import("MachO/imports.zig");
3030
31pub const base_tag: File.Tag = File.Tag.macho;31pub const base_tag: File.Tag = File.Tag.macho;
3232
...@@ -108,9 +108,9 @@ locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},...@@ -108,9 +108,9 @@ locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
108/// Table of all global symbols108/// Table of all global symbols
109globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},109globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
110/// Table of all extern nonlazy symbols, indexed by name.110/// Table of all extern nonlazy symbols, indexed by name.
111nonlazy_imports: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{},111nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
112/// Table of all extern lazy symbols, indexed by name.112/// Table of all extern lazy symbols, indexed by name.
113lazy_imports: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{},113lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
114114
115locals_free_list: std.ArrayListUnmanaged(u32) = .{},115locals_free_list: std.ArrayListUnmanaged(u32) = .{},
116globals_free_list: std.ArrayListUnmanaged(u32) = .{},116globals_free_list: std.ArrayListUnmanaged(u32) = .{},
...@@ -169,6 +169,17 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{},...@@ -169,6 +169,17 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{},
169/// rather than sitting in the global scope.169/// rather than sitting in the global scope.
170stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{},170stub_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
172pub const PieFixup = struct {183pub const PieFixup = struct {
173 /// Target address we wanted to address in absolute terms.184 /// Target address we wanted to address in absolute terms.
174 address: u64,185 address: u64,
...@@ -1285,9 +1296,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1285,9 +1296,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1285 try self.writeStubInStubHelper(fixup.symbol);1296 try self.writeStubInStubHelper(fixup.symbol);
1286 try self.writeLazySymbolPointer(fixup.symbol);1297 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);
1291 self.rebase_info_dirty = true;1299 self.rebase_info_dirty = true;
1292 self.lazy_binding_info_dirty = true;1300 self.lazy_binding_info_dirty = true;
1293 }1301 }
...@@ -2065,7 +2073,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -2065,7 +2073,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
2065 const name = try self.base.allocator.dupe(u8, "dyld_stub_binder");2073 const name = try self.base.allocator.dupe(u8, "dyld_stub_binder");
2066 const offset = try self.makeString("dyld_stub_binder");2074 const offset = try self.makeString("dyld_stub_binder");
2067 try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{2075 try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{
2068 .inner = .{2076 .symbol = .{
2069 .n_strx = offset,2077 .n_strx = offset,
2070 .n_type = std.macho.N_UNDF | std.macho.N_EXT,2078 .n_type = std.macho.N_UNDF | std.macho.N_EXT,
2071 .n_sect = 0,2079 .n_sect = 0,
...@@ -2073,8 +2081,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -2073,8 +2081,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
2073 .n_value = 0,2081 .n_value = 0,
2074 },2082 },
2075 .dylib_ordinal = 1, // TODO this is currently hardcoded.2083 .dylib_ordinal = 1, // TODO this is currently hardcoded.
2076 .segment = self.data_const_segment_cmd_index.?,2084 .index = index,
2077 .offset = index * @sizeOf(u64),
2078 });2085 });
2079 self.binding_info_dirty = true;2086 self.binding_info_dirty = true;
2080 }2087 }
...@@ -2238,7 +2245,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {...@@ -2238,7 +2245,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
2238 const sym_name = try self.base.allocator.dupe(u8, name);2245 const sym_name = try self.base.allocator.dupe(u8, name);
2239 const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem.2246 const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem.
2240 try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{2247 try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{
2241 .inner = .{2248 .symbol = .{
2242 .n_strx = offset,2249 .n_strx = offset,
2243 .n_type = macho.N_UNDF | macho.N_EXT,2250 .n_type = macho.N_UNDF | macho.N_EXT,
2244 .n_sect = 0,2251 .n_sect = 0,
...@@ -2246,6 +2253,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {...@@ -2246,6 +2253,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
2246 .n_value = 0,2253 .n_value = 0,
2247 },2254 },
2248 .dylib_ordinal = dylib_ordinal,2255 .dylib_ordinal = dylib_ordinal,
2256 .index = index,
2249 });2257 });
2250 log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal });2258 log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal });
2251 return index;2259 return index;
...@@ -2767,10 +2775,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {...@@ -2767,10 +2775,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
2767 defer undefs.deinit();2775 defer undefs.deinit();
2768 try undefs.ensureCapacity(nundefs);2776 try undefs.ensureCapacity(nundefs);
2769 for (self.lazy_imports.items()) |entry| {2777 for (self.lazy_imports.items()) |entry| {
2770 undefs.appendAssumeCapacity(entry.value.inner);2778 undefs.appendAssumeCapacity(entry.value.symbol);
2771 }2779 }
2772 for (self.nonlazy_imports.items()) |entry| {2780 for (self.nonlazy_imports.items()) |entry| {
2773 undefs.appendAssumeCapacity(entry.value.inner);2781 undefs.appendAssumeCapacity(entry.value.symbol);
2774 }2782 }
27752783
2776 const locals_off = symtab.symoff;2784 const locals_off = symtab.symoff;
...@@ -2832,20 +2840,20 @@ fn writeIndirectSymbolTable(self: *MachO) !void {...@@ -2832,20 +2840,20 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
2832 var writer = stream.writer();2840 var writer = stream.writer();
28332841
2834 stubs.reserved1 = 0;2842 stubs.reserved1 = 0;
2835 for (self.lazy_imports.items()) |_, i| {2843 for (lazy) |_, i| {
2836 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);2844 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
2837 try writer.writeIntLittle(u32, symtab_idx);2845 try writer.writeIntLittle(u32, symtab_idx);
2838 }2846 }
28392847
2840 const base_id = @intCast(u32, lazy.len);2848 const base_id = @intCast(u32, lazy.len);
2841 got.reserved1 = base_id;2849 got.reserved1 = base_id;
2842 for (self.nonlazy_imports.items()) |_, i| {2850 for (nonlazy) |_, i| {
2843 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);2851 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);
2844 try writer.writeIntLittle(u32, symtab_idx);2852 try writer.writeIntLittle(u32, symtab_idx);
2845 }2853 }
28462854
2847 la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len);2855 la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len);
2848 for (self.lazy_imports.items()) |_, i| {2856 for (lazy) |_, i| {
2849 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);2857 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
2850 try writer.writeIntLittle(u32, symtab_idx);2858 try writer.writeIntLittle(u32, symtab_idx);
2851 }2859 }
...@@ -2962,14 +2970,33 @@ fn writeRebaseInfoTable(self: *MachO) !void {...@@ -2962,14 +2970,33 @@ fn writeRebaseInfoTable(self: *MachO) !void {
2962 const tracy = trace(@src());2970 const tracy = trace(@src());
2963 defer tracy.end();2971 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);
2966 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));2994 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
2967 defer self.base.allocator.free(buffer);2995 defer self.base.allocator.free(buffer);
29682996
2969 var stream = std.io.fixedBufferStream(buffer);2997 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;
2973 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;3000 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
2974 const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off);3001 const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off);
2975 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));3002 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
...@@ -2994,14 +3021,33 @@ fn writeBindingInfoTable(self: *MachO) !void {...@@ -2994,14 +3021,33 @@ fn writeBindingInfoTable(self: *MachO) !void {
2994 const tracy = trace(@src());3021 const tracy = trace(@src());
2995 defer tracy.end();3022 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);
2998 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));3045 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
2999 defer self.base.allocator.free(buffer);3046 defer self.base.allocator.free(buffer);
30003047
3001 var stream = std.io.fixedBufferStream(buffer);3048 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;
3005 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;3051 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3006 const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off);3052 const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off);
3007 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));3053 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
...@@ -3023,14 +3069,36 @@ fn writeBindingInfoTable(self: *MachO) !void {...@@ -3023,14 +3069,36 @@ fn writeBindingInfoTable(self: *MachO) !void {
3023fn writeLazyBindingInfoTable(self: *MachO) !void {3069fn writeLazyBindingInfoTable(self: *MachO) !void {
3024 if (!self.lazy_binding_info_dirty) return;3070 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);
3027 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));3096 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
3028 defer self.base.allocator.free(buffer);3097 defer self.base.allocator.free(buffer);
30293098
3030 var stream = std.io.fixedBufferStream(buffer);3099 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;
3034 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;3102 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3035 const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off);3103 const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off);
3036 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));3104 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}