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 {
826826 // Write update dyld info
827827 const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
828828 {
829 const size = self.binding_info_table.calcSize();
829 const size = try self.binding_info_table.calcSize();
830830 assert(dyld_info.bind_size >= size);
831831
832832 var buffer = try self.base.allocator.alloc(u8, size);
......@@ -838,7 +838,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
838838 try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
839839 }
840840 {
841 const size = self.lazy_binding_info_table.calcSize();
841 const size = try self.lazy_binding_info_table.calcSize();
842842 assert(dyld_info.lazy_bind_size >= size);
843843
844844 var buffer = try self.base.allocator.alloc(u8, size);
......@@ -2204,15 +2204,3 @@ fn parseLazyBindingInfoTable(self: *MachO) !void {
22042204 var stream = std.io.fixedBufferStream(buffer);
22052205 try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator);
22062206}
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;
3838const testing = std.testing;
3939const assert = std.debug.assert;
4040const Allocator = mem.Allocator;
41const sizeLEB128 = @import("../MachO.zig").sizeLEB128;
4241
4342pub const Node = struct {
4443 base: *Trie,
......@@ -242,12 +241,15 @@ pub const Node = struct {
242241 };
243242
244243 /// 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
246248 var node_size: usize = 0;
247249 if (self.terminal_info) |info| {
248 node_size += sizeLEB128(info.export_flags);
249 node_size += sizeLEB128(info.vmaddr_offset);
250 node_size += sizeLEB128(node_size);
250 try leb.writeULEB128(writer, info.export_flags);
251 try leb.writeULEB128(writer, info.vmaddr_offset);
252 try leb.writeULEB128(writer, stream.bytes_written);
251253 } else {
252254 node_size += 1; // 0x0 for non-terminal nodes
253255 }
......@@ -255,15 +257,17 @@ pub const Node = struct {
255257
256258 for (self.edges.items) |edge| {
257259 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);
259262 }
260263
261264 const trie_offset = self.trie_offset orelse 0;
262265 const updated = offset_in_trie != trie_offset;
263266 self.trie_offset = offset_in_trie;
264267 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 };
267271 }
268272};
269273
......@@ -347,7 +351,7 @@ pub fn finalize(self: *Trie) !void {
347351 self.size = 0;
348352 more = false;
349353 for (self.ordered_nodes.items) |node| {
350 const res = node.finalize(self.size);
354 const res = try node.finalize(self.size);
351355 self.size += res.node_size;
352356 if (res.updated) more = true;
353357 }
src/link/MachO/imports.zig+46-8
......@@ -5,7 +5,6 @@ const mem = std.mem;
55
66const assert = std.debug.assert;
77const Allocator = mem.Allocator;
8const sizeLEB128 = @import("../MachO.zig").sizeLEB128;
98
109/// Table of binding info entries used to tell the dyld which
1110/// symbols to bind at loading time.
......@@ -27,6 +26,9 @@ pub const BindingInfoTable = struct {
2726
2827 /// Offset of this symbol wrt to the segment id encoded in `segment`.
2928 offset: i64,
29
30 /// Addend value (if any).
31 addend: ?i64 = null,
3032 };
3133
3234 pub fn deinit(self: *BindingInfoTable, allocator: *Allocator) void {
......@@ -91,6 +93,9 @@ pub const BindingInfoTable = struct {
9193 macho.BIND_OPCODE_SET_TYPE_IMM => {
9294 self.binding_type = imm;
9395 },
96 macho.BIND_OPCODE_SET_ADDEND_SLEB => {
97 symbol.addend = try leb.readILEB128(i64, reader);
98 },
9499 else => {
95100 std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode});
96101 },
......@@ -121,6 +126,11 @@ pub const BindingInfoTable = struct {
121126 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
122127 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
124134 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
125135 }
126136
......@@ -128,10 +138,13 @@ pub const BindingInfoTable = struct {
128138 }
129139
130140 /// 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();
132144 var size: usize = 1;
145
133146 if (self.dylib_ordinal > 15) {
134 size += sizeLEB128(self.dylib_ordinal);
147 try leb.writeULEB128(writer, @bitCast(u64, self.dylib_ordinal));
135148 }
136149
137150 size += 1;
......@@ -144,12 +157,17 @@ pub const BindingInfoTable = struct {
144157 }
145158
146159 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
149167 size += 1;
150168 }
151169
152 size += 1;
170 size += 1 + stream.bytes_written;
153171 return size;
154172 }
155173};
......@@ -173,6 +191,9 @@ pub const LazyBindingInfoTable = struct {
173191
174192 /// Id of the segment where to bind this symbol to.
175193 segment: u8,
194
195 /// Addend value (if any).
196 addend: ?i64 = null,
176197 };
177198
178199 pub fn deinit(self: *LazyBindingInfoTable, allocator: *Allocator) void {
......@@ -232,6 +253,9 @@ pub const LazyBindingInfoTable = struct {
232253 macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => {
233254 symbol.dylib_ordinal = try leb.readILEB128(i64, reader);
234255 },
256 macho.BIND_OPCODE_SET_ADDEND_SLEB => {
257 symbol.addend = try leb.readILEB128(i64, reader);
258 },
235259 else => {
236260 std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode});
237261 },
......@@ -246,6 +270,11 @@ pub const LazyBindingInfoTable = struct {
246270 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
247271 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
249278 if (symbol.dylib_ordinal > 15) {
250279 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
251280 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
......@@ -267,15 +296,23 @@ pub const LazyBindingInfoTable = struct {
267296 }
268297
269298 /// 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();
271302 var size: usize = 0;
272303
273304 for (self.symbols.items) |symbol| {
274305 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
276313 size += 1;
277314 if (symbol.dylib_ordinal > 15) {
278 size += sizeLEB128(symbol.dylib_ordinal);
315 try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
279316 }
280317 if (symbol.name) |name| {
281318 size += 1;
......@@ -285,6 +322,7 @@ pub const LazyBindingInfoTable = struct {
285322 size += 2;
286323 }
287324
325 size += stream.bytes_written;
288326 return size;
289327 }
290328};