authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-14 17:40:27+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-17 10:04:53+01:00
logb42ef0e6ea0fed8e592e474bd09e070e10fca920
tree7141feb2c606fc78fe548e0b897e4ca4ccb9a540
parent3e9e79378d4776323bb37a3bc1ebf6506efac88d

macho: refactor calculating LEB128 sizes


3 files changed, 60 insertions(+), 30 deletions(-)

src/link/MachO.zig+2-14
...@@ -826,7 +826,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -826,7 +826,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
826 // Write update dyld info826 // Write update dyld info
827 const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;827 const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
828 {828 {
829 const size = self.binding_info_table.calcSize();829 const size = try self.binding_info_table.calcSize();
830 assert(dyld_info.bind_size >= size);830 assert(dyld_info.bind_size >= size);
831831
832 var buffer = try self.base.allocator.alloc(u8, size);832 var buffer = try self.base.allocator.alloc(u8, size);
...@@ -838,7 +838,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -838,7 +838,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
838 try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);838 try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
839 }839 }
840 {840 {
841 const size = self.lazy_binding_info_table.calcSize();841 const size = try self.lazy_binding_info_table.calcSize();
842 assert(dyld_info.lazy_bind_size >= size);842 assert(dyld_info.lazy_bind_size >= size);
843843
844 var buffer = try self.base.allocator.alloc(u8, size);844 var buffer = try self.base.allocator.alloc(u8, size);
...@@ -2204,15 +2204,3 @@ fn parseLazyBindingInfoTable(self: *MachO) !void {...@@ -2204,15 +2204,3 @@ fn parseLazyBindingInfoTable(self: *MachO) !void {
2204 var stream = std.io.fixedBufferStream(buffer);2204 var stream = std.io.fixedBufferStream(buffer);
2205 try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator);2205 try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator);
2206}2206}
2207
2208/// Calculates number of bytes in LEB128 encoding of value.
2209pub fn sizeLEB128(value: anytype) usize {
2210 var res: usize = 0;
2211 var v = value;
2212 while (true) {
2213 v = v >> 7;
2214 res += 1;
2215 if (v == 0) break;
2216 }
2217 return res;
2218}
src/link/MachO/Trie.zig+12-8
...@@ -38,7 +38,6 @@ const macho = std.macho;...@@ -38,7 +38,6 @@ const macho = std.macho;
38const testing = std.testing;38const testing = std.testing;
39const assert = std.debug.assert;39const assert = std.debug.assert;
40const Allocator = mem.Allocator;40const Allocator = mem.Allocator;
41const sizeLEB128 = @import("../MachO.zig").sizeLEB128;
4241
43pub const Node = struct {42pub const Node = struct {
44 base: *Trie,43 base: *Trie,
...@@ -242,12 +241,15 @@ pub const Node = struct {...@@ -242,12 +241,15 @@ pub const Node = struct {
242 };241 };
243242
244 /// Updates offset of this node in the output byte stream.243 /// Updates offset of this node in the output byte stream.
245 fn finalize(self: *Node, offset_in_trie: usize) FinalizeResult {244 fn finalize(self: *Node, offset_in_trie: usize) !FinalizeResult {
245 var stream = std.io.countingWriter(std.io.null_writer);
246 var writer = stream.writer();
247
246 var node_size: usize = 0;248 var node_size: usize = 0;
247 if (self.terminal_info) |info| {249 if (self.terminal_info) |info| {
248 node_size += sizeLEB128(info.export_flags);250 try leb.writeULEB128(writer, info.export_flags);
249 node_size += sizeLEB128(info.vmaddr_offset);251 try leb.writeULEB128(writer, info.vmaddr_offset);
250 node_size += sizeLEB128(node_size);252 try leb.writeULEB128(writer, stream.bytes_written);
251 } else {253 } else {
252 node_size += 1; // 0x0 for non-terminal nodes254 node_size += 1; // 0x0 for non-terminal nodes
253 }255 }
...@@ -255,15 +257,17 @@ pub const Node = struct {...@@ -255,15 +257,17 @@ pub const Node = struct {
255257
256 for (self.edges.items) |edge| {258 for (self.edges.items) |edge| {
257 const next_node_offset = edge.to.trie_offset orelse 0;259 const next_node_offset = edge.to.trie_offset orelse 0;
258 node_size += edge.label.len + 1 + sizeLEB128(next_node_offset);260 node_size += edge.label.len + 1;
261 try leb.writeULEB128(writer, next_node_offset);
259 }262 }
260263
261 const trie_offset = self.trie_offset orelse 0;264 const trie_offset = self.trie_offset orelse 0;
262 const updated = offset_in_trie != trie_offset;265 const updated = offset_in_trie != trie_offset;
263 self.trie_offset = offset_in_trie;266 self.trie_offset = offset_in_trie;
264 self.node_dirty = false;267 self.node_dirty = false;
268 node_size += stream.bytes_written;
265269
266 return .{ .node_size = node_size, .updated = updated };270 return FinalizeResult{ .node_size = node_size, .updated = updated };
267 }271 }
268};272};
269273
...@@ -347,7 +351,7 @@ pub fn finalize(self: *Trie) !void {...@@ -347,7 +351,7 @@ pub fn finalize(self: *Trie) !void {
347 self.size = 0;351 self.size = 0;
348 more = false;352 more = false;
349 for (self.ordered_nodes.items) |node| {353 for (self.ordered_nodes.items) |node| {
350 const res = node.finalize(self.size);354 const res = try node.finalize(self.size);
351 self.size += res.node_size;355 self.size += res.node_size;
352 if (res.updated) more = true;356 if (res.updated) more = true;
353 }357 }
src/link/MachO/imports.zig+46-8
...@@ -5,7 +5,6 @@ const mem = std.mem;...@@ -5,7 +5,6 @@ const mem = std.mem;
55
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const Allocator = mem.Allocator;7const Allocator = mem.Allocator;
8const sizeLEB128 = @import("../MachO.zig").sizeLEB128;
98
10/// Table of binding info entries used to tell the dyld which9/// Table of binding info entries used to tell the dyld which
11/// symbols to bind at loading time.10/// symbols to bind at loading time.
...@@ -27,6 +26,9 @@ pub const BindingInfoTable = struct {...@@ -27,6 +26,9 @@ pub const BindingInfoTable = struct {
2726
28 /// Offset of this symbol wrt to the segment id encoded in `segment`.27 /// Offset of this symbol wrt to the segment id encoded in `segment`.
29 offset: i64,28 offset: i64,
29
30 /// Addend value (if any).
31 addend: ?i64 = null,
30 };32 };
3133
32 pub fn deinit(self: *BindingInfoTable, allocator: *Allocator) void {34 pub fn deinit(self: *BindingInfoTable, allocator: *Allocator) void {
...@@ -91,6 +93,9 @@ pub const BindingInfoTable = struct {...@@ -91,6 +93,9 @@ pub const BindingInfoTable = struct {
91 macho.BIND_OPCODE_SET_TYPE_IMM => {93 macho.BIND_OPCODE_SET_TYPE_IMM => {
92 self.binding_type = imm;94 self.binding_type = imm;
93 },95 },
96 macho.BIND_OPCODE_SET_ADDEND_SLEB => {
97 symbol.addend = try leb.readILEB128(i64, reader);
98 },
94 else => {99 else => {
95 std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode});100 std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode});
96 },101 },
...@@ -121,6 +126,11 @@ pub const BindingInfoTable = struct {...@@ -121,6 +126,11 @@ pub const BindingInfoTable = struct {
121 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));126 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
122 try leb.writeILEB128(writer, symbol.offset);127 try leb.writeILEB128(writer, symbol.offset);
123128
129 if (symbol.addend) |addend| {
130 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
131 try leb.writeILEB128(writer, addend);
132 }
133
124 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);134 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
125 }135 }
126136
...@@ -128,10 +138,13 @@ pub const BindingInfoTable = struct {...@@ -128,10 +138,13 @@ pub const BindingInfoTable = struct {
128 }138 }
129139
130 /// Calculate size in bytes of this binding info table.140 /// Calculate size in bytes of this binding info table.
131 pub fn calcSize(self: *BindingInfoTable) usize {141 pub fn calcSize(self: *BindingInfoTable) !usize {
142 var stream = std.io.countingWriter(std.io.null_writer);
143 var writer = stream.writer();
132 var size: usize = 1;144 var size: usize = 1;
145
133 if (self.dylib_ordinal > 15) {146 if (self.dylib_ordinal > 15) {
134 size += sizeLEB128(self.dylib_ordinal);147 try leb.writeULEB128(writer, @bitCast(u64, self.dylib_ordinal));
135 }148 }
136149
137 size += 1;150 size += 1;
...@@ -144,12 +157,17 @@ pub const BindingInfoTable = struct {...@@ -144,12 +157,17 @@ pub const BindingInfoTable = struct {
144 }157 }
145158
146 size += 1;159 size += 1;
147 size += sizeLEB128(symbol.offset);160 try leb.writeILEB128(writer, symbol.offset);
161
162 if (symbol.addend) |addend| {
163 size += 1;
164 try leb.writeILEB128(writer, addend);
165 }
148166
149 size += 1;167 size += 1;
150 }168 }
151169
152 size += 1;170 size += 1 + stream.bytes_written;
153 return size;171 return size;
154 }172 }
155};173};
...@@ -173,6 +191,9 @@ pub const LazyBindingInfoTable = struct {...@@ -173,6 +191,9 @@ pub const LazyBindingInfoTable = struct {
173191
174 /// Id of the segment where to bind this symbol to.192 /// Id of the segment where to bind this symbol to.
175 segment: u8,193 segment: u8,
194
195 /// Addend value (if any).
196 addend: ?i64 = null,
176 };197 };
177198
178 pub fn deinit(self: *LazyBindingInfoTable, allocator: *Allocator) void {199 pub fn deinit(self: *LazyBindingInfoTable, allocator: *Allocator) void {
...@@ -232,6 +253,9 @@ pub const LazyBindingInfoTable = struct {...@@ -232,6 +253,9 @@ pub const LazyBindingInfoTable = struct {
232 macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => {253 macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => {
233 symbol.dylib_ordinal = try leb.readILEB128(i64, reader);254 symbol.dylib_ordinal = try leb.readILEB128(i64, reader);
234 },255 },
256 macho.BIND_OPCODE_SET_ADDEND_SLEB => {
257 symbol.addend = try leb.readILEB128(i64, reader);
258 },
235 else => {259 else => {
236 std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode});260 std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode});
237 },261 },
...@@ -246,6 +270,11 @@ pub const LazyBindingInfoTable = struct {...@@ -246,6 +270,11 @@ pub const LazyBindingInfoTable = struct {
246 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));270 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
247 try leb.writeILEB128(writer, symbol.offset);271 try leb.writeILEB128(writer, symbol.offset);
248272
273 if (symbol.addend) |addend| {
274 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
275 try leb.writeILEB128(writer, addend);
276 }
277
249 if (symbol.dylib_ordinal > 15) {278 if (symbol.dylib_ordinal > 15) {
250 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);279 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
251 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));280 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
...@@ -267,15 +296,23 @@ pub const LazyBindingInfoTable = struct {...@@ -267,15 +296,23 @@ pub const LazyBindingInfoTable = struct {
267 }296 }
268297
269 /// Calculate size in bytes of this binding info table.298 /// Calculate size in bytes of this binding info table.
270 pub fn calcSize(self: *LazyBindingInfoTable) usize {299 pub fn calcSize(self: *LazyBindingInfoTable) !usize {
300 var stream = std.io.countingWriter(std.io.null_writer);
301 var writer = stream.writer();
271 var size: usize = 0;302 var size: usize = 0;
272303
273 for (self.symbols.items) |symbol| {304 for (self.symbols.items) |symbol| {
274 size += 1;305 size += 1;
275 size += sizeLEB128(symbol.offset);306 try leb.writeILEB128(writer, symbol.offset);
307
308 if (symbol.addend) |addend| {
309 size += 1;
310 try leb.writeILEB128(writer, addend);
311 }
312
276 size += 1;313 size += 1;
277 if (symbol.dylib_ordinal > 15) {314 if (symbol.dylib_ordinal > 15) {
278 size += sizeLEB128(symbol.dylib_ordinal);315 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
279 }316 }
280 if (symbol.name) |name| {317 if (symbol.name) |name| {
281 size += 1;318 size += 1;
...@@ -285,6 +322,7 @@ pub const LazyBindingInfoTable = struct {...@@ -285,6 +322,7 @@ pub const LazyBindingInfoTable = struct {
285 size += 2;322 size += 2;
286 }323 }
287324
325 size += stream.bytes_written;
288 return size;326 return size;
289 }327 }
290};328};