| author | |
| committer | |
| log | ae535111a40ad0a5fe87304e171fd093a575494e |
| tree | efa2d1c03dbf676e9bc8f61121b86503ae63dfc0 |
| parent | 5e913c9c2c41e44620911ffce0ebc20d9af041ca |
3 files changed, 267 insertions(+), 93 deletions(-)
src/link/MachO.zig+112-35| ... | ... | @@ -810,47 +810,50 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 810 | 810 | if (self.symtab_cmd_index == null or self.dysymtab_cmd_index == null) { |
| 811 | 811 | std.log.err("Incomplete Mach-O binary: no LC_SYMTAB or LC_DYSYMTAB load command found!", .{}); |
| 812 | 812 | std.log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{}); |
| 813 | return error.NoSymbolTable; | |
| 813 | return error.NoSymbolTableFound; | |
| 814 | 814 | } |
| 815 | 815 | |
| 816 | 816 | // Parse symbol and string tables. |
| 817 | 817 | try self.parseSymbolTable(); |
| 818 | 818 | try self.parseStringTable(); |
| 819 | 819 | |
| 820 | std.debug.print("Undef symbols\n", .{}); | |
| 821 | for (self.undef_symbols.items) |sym| { | |
| 822 | const name = self.string_table.items[sym.n_strx..]; | |
| 823 | const len = blk: { | |
| 824 | var end: usize = 0; | |
| 825 | while (true) { | |
| 826 | if (name[end] == @as(u8, 0)) break; | |
| 827 | end += 1; | |
| 828 | } | |
| 829 | break :blk end; | |
| 830 | }; | |
| 831 | std.debug.print("name={},sym={}\n", .{ name[0..len], sym }); | |
| 820 | // Parse dyld info | |
| 821 | try self.parseBindingInfoTable(); | |
| 822 | try self.parseLazyBindingInfoTable(); | |
| 823 | ||
| 824 | // Update the dylib ordinals. | |
| 825 | self.binding_info_table.dylib_ordinal = next_ordinal; | |
| 826 | for (self.lazy_binding_info_table.symbols.items) |*symbol| { | |
| 827 | symbol.dylib_ordinal = next_ordinal; | |
| 832 | 828 | } |
| 833 | 829 | |
| 834 | // Parse dyld info | |
| 835 | var symbols_by_name = std.StringHashMap(u16).init(self.base.allocator); | |
| 836 | defer symbols_by_name.deinit(); | |
| 837 | try symbols_by_name.ensureCapacity(@intCast(u32, self.undef_symbols.items.len)); | |
| 838 | ||
| 839 | for (self.undef_symbols.items) |sym, i| { | |
| 840 | const name = self.string_table.items[sym.n_strx..]; | |
| 841 | const len = blk: { | |
| 842 | var end: usize = 0; | |
| 843 | while (true) { | |
| 844 | if (name[end] == @as(u8, 0)) break; | |
| 845 | end += 1; | |
| 846 | } | |
| 847 | break :blk end; | |
| 848 | }; | |
| 849 | symbols_by_name.putAssumeCapacityNoClobber(name[0..len], @intCast(u16, i)); | |
| 830 | // Write update dyld info | |
| 831 | const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | |
| 832 | { | |
| 833 | const size = self.binding_info_table.calcSize(); | |
| 834 | assert(dyld_info.bind_size == size); | |
| 835 | ||
| 836 | var buffer = try self.base.allocator.alloc(u8, size); | |
| 837 | defer self.base.allocator.free(buffer); | |
| 838 | ||
| 839 | var stream = std.io.fixedBufferStream(buffer); | |
| 840 | try self.binding_info_table.write(stream.writer()); | |
| 841 | ||
| 842 | try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); | |
| 843 | } | |
| 844 | { | |
| 845 | const size = self.lazy_binding_info_table.calcSize(); | |
| 846 | assert(dyld_info.lazy_bind_size == size); | |
| 847 | ||
| 848 | var buffer = try self.base.allocator.alloc(u8, size); | |
| 849 | defer self.base.allocator.free(buffer); | |
| 850 | ||
| 851 | var stream = std.io.fixedBufferStream(buffer); | |
| 852 | try self.lazy_binding_info_table.write(stream.writer()); | |
| 853 | ||
| 854 | try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); | |
| 850 | 855 | } |
| 851 | 856 | |
| 852 | try self.parseBindingInfoTable(symbols_by_name); | |
| 853 | try self.parseLazyBindingInfoTable(symbols_by_name); | |
| 854 | 857 | // Write updated load commands and the header |
| 855 | 858 | try self.writeLoadCommands(); |
| 856 | 859 | try self.writeHeader(); |
| ... | ... | @@ -1952,6 +1955,68 @@ fn writeExportTrie(self: *MachO) !void { |
| 1952 | 1955 | self.cmd_table_dirty = true; |
| 1953 | 1956 | } |
| 1954 | 1957 | |
| 1958 | fn writeBindingInfoTable(self: *MachO) !void { | |
| 1959 | const size = self.binding_info_table.calcSize(); | |
| 1960 | var buffer = try self.base.allocator.alloc(u8, size); | |
| 1961 | defer self.base.allocator.free(buffer); | |
| 1962 | ||
| 1963 | var stream = std.io.fixedBufferStream(buffer); | |
| 1964 | try self.binding_info_table.write(stream.writer()); | |
| 1965 | ||
| 1966 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | |
| 1967 | const bind_size = @intCast(u32, mem.alignForward(buffer.len, @sizeOf(u64))); | |
| 1968 | dyld_info.bind_off = self.linkedit_segment_next_offset.?; | |
| 1969 | dyld_info.bind_size = bind_size; | |
| 1970 | ||
| 1971 | log.debug("writing binding info table from 0x{x} to 0x{x}\n", .{ dyld_info.bind_off, dyld_info.bind_off + bind_size }); | |
| 1972 | ||
| 1973 | if (bind_size > buffer.len) { | |
| 1974 | // Pad out to align(8). | |
| 1975 | try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.bind_off + bind_size); | |
| 1976 | } | |
| 1977 | try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); | |
| 1978 | ||
| 1979 | self.linkedit_segment_next_offset = dyld_info.bind_off + dyld_info.bind_size; | |
| 1980 | // Advance size of __LINKEDIT segment | |
| 1981 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 1982 | linkedit.inner.filesize += dyld_info.bind_size; | |
| 1983 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { | |
| 1984 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); | |
| 1985 | } | |
| 1986 | self.cmd_table_dirty = true; | |
| 1987 | } | |
| 1988 | ||
| 1989 | fn writeLazyBindingInfoTable(self: *MachO) !void { | |
| 1990 | const size = self.lazy_binding_info_table.calcSize(); | |
| 1991 | var buffer = try self.base.allocator.alloc(u8, size); | |
| 1992 | defer self.base.allocator.free(buffer); | |
| 1993 | ||
| 1994 | var stream = std.io.fixedBufferStream(buffer); | |
| 1995 | try self.lazy_binding_info_table.write(stream.writer()); | |
| 1996 | ||
| 1997 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | |
| 1998 | const bind_size = @intCast(u32, mem.alignForward(buffer.len, @sizeOf(u64))); | |
| 1999 | dyld_info.lazy_bind_off = self.linkedit_segment_next_offset.?; | |
| 2000 | dyld_info.lazy_bind_size = bind_size; | |
| 2001 | ||
| 2002 | log.debug("writing lazy binding info table from 0x{x} to 0x{x}\n", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + bind_size }); | |
| 2003 | ||
| 2004 | if (bind_size > buffer.len) { | |
| 2005 | // Pad out to align(8). | |
| 2006 | try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.lazy_bind_off + bind_size); | |
| 2007 | } | |
| 2008 | try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); | |
| 2009 | ||
| 2010 | self.linkedit_segment_next_offset = dyld_info.lazy_bind_off + dyld_info.lazy_bind_size; | |
| 2011 | // Advance size of __LINKEDIT segment | |
| 2012 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 2013 | linkedit.inner.filesize += dyld_info.lazy_bind_size; | |
| 2014 | if (linkedit.inner.vmsize < linkedit.inner.filesize) { | |
| 2015 | linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size); | |
| 2016 | } | |
| 2017 | self.cmd_table_dirty = true; | |
| 2018 | } | |
| 2019 | ||
| 1955 | 2020 | fn writeStringTable(self: *MachO) !void { |
| 1956 | 2021 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1957 | 2022 | const needed_size = self.string_table.items.len; |
| ... | ... | @@ -2122,7 +2187,7 @@ fn parseStringTable(self: *MachO) !void { |
| 2122 | 2187 | self.string_table.appendSliceAssumeCapacity(buffer); |
| 2123 | 2188 | } |
| 2124 | 2189 | |
| 2125 | fn parseBindingInfoTable(self: *MachO, symbols_by_name: std.StringHashMap(u16)) !void { | |
| 2190 | fn parseBindingInfoTable(self: *MachO) !void { | |
| 2126 | 2191 | const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2127 | 2192 | var buffer = try self.base.allocator.alloc(u8, dyld_info.bind_size); |
| 2128 | 2193 | defer self.base.allocator.free(buffer); |
| ... | ... | @@ -2130,10 +2195,10 @@ fn parseBindingInfoTable(self: *MachO, symbols_by_name: std.StringHashMap(u16)) |
| 2130 | 2195 | assert(nread == buffer.len); |
| 2131 | 2196 | |
| 2132 | 2197 | var stream = std.io.fixedBufferStream(buffer); |
| 2133 | try self.binding_info_table.read(self.base.allocator, symbols_by_name, stream.reader()); | |
| 2198 | try self.binding_info_table.read(stream.reader(), self.base.allocator); | |
| 2134 | 2199 | } |
| 2135 | 2200 | |
| 2136 | fn parseLazyBindingInfoTable(self: *MachO, symbols_by_name: std.StringHashMap(u16)) !void { | |
| 2201 | fn parseLazyBindingInfoTable(self: *MachO) !void { | |
| 2137 | 2202 | const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2138 | 2203 | var buffer = try self.base.allocator.alloc(u8, dyld_info.lazy_bind_size); |
| 2139 | 2204 | defer self.base.allocator.free(buffer); |
| ... | ... | @@ -2141,5 +2206,17 @@ fn parseLazyBindingInfoTable(self: *MachO, symbols_by_name: std.StringHashMap(u1 |
| 2141 | 2206 | assert(nread == buffer.len); |
| 2142 | 2207 | |
| 2143 | 2208 | var stream = std.io.fixedBufferStream(buffer); |
| 2144 | try self.lazy_binding_info_table.read(self.base.allocator, symbols_by_name, stream.reader()); | |
| 2209 | try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator); | |
| 2210 | } | |
| 2211 | ||
| 2212 | /// Calculates number of bytes in LEB128 encoding of value. | |
| 2213 | pub fn sizeLEB128(value: anytype) usize { | |
| 2214 | var res: usize = 0; | |
| 2215 | var v = value; | |
| 2216 | while (true) { | |
| 2217 | v = v >> 7; | |
| 2218 | res += 1; | |
| 2219 | if (v == 0) break; | |
| 2220 | } | |
| 2221 | return res; | |
| 2145 | 2222 | } |
src/link/MachO/Trie.zig+6-19| ... | ... | @@ -38,6 +38,7 @@ const macho = std.macho; |
| 38 | 38 | const testing = std.testing; |
| 39 | 39 | const assert = std.debug.assert; |
| 40 | 40 | const Allocator = mem.Allocator; |
| 41 | const sizeLEB128 = @import("../MachO.zig").sizeLEB128; | |
| 41 | 42 | |
| 42 | 43 | pub const Node = struct { |
| 43 | 44 | base: *Trie, |
| ... | ... | @@ -244,9 +245,9 @@ pub const Node = struct { |
| 244 | 245 | fn finalize(self: *Node, offset_in_trie: usize) FinalizeResult { |
| 245 | 246 | var node_size: usize = 0; |
| 246 | 247 | if (self.terminal_info) |info| { |
| 247 | node_size += sizeULEB128Mem(info.export_flags); | |
| 248 | node_size += sizeULEB128Mem(info.vmaddr_offset); | |
| 249 | node_size += sizeULEB128Mem(node_size); | |
| 248 | node_size += sizeLEB128(info.export_flags); | |
| 249 | node_size += sizeLEB128(info.vmaddr_offset); | |
| 250 | node_size += sizeLEB128(node_size); | |
| 250 | 251 | } else { |
| 251 | 252 | node_size += 1; // 0x0 for non-terminal nodes |
| 252 | 253 | } |
| ... | ... | @@ -254,7 +255,7 @@ pub const Node = struct { |
| 254 | 255 | |
| 255 | 256 | for (self.edges.items) |edge| { |
| 256 | 257 | const next_node_offset = edge.to.trie_offset orelse 0; |
| 257 | node_size += edge.label.len + 1 + sizeULEB128Mem(next_node_offset); | |
| 258 | node_size += edge.label.len + 1 + sizeLEB128(next_node_offset); | |
| 258 | 259 | } |
| 259 | 260 | |
| 260 | 261 | const trie_offset = self.trie_offset orelse 0; |
| ... | ... | @@ -264,18 +265,6 @@ pub const Node = struct { |
| 264 | 265 | |
| 265 | 266 | return .{ .node_size = node_size, .updated = updated }; |
| 266 | 267 | } |
| 267 | ||
| 268 | /// Calculates number of bytes in ULEB128 encoding of value. | |
| 269 | fn sizeULEB128Mem(value: u64) usize { | |
| 270 | var res: usize = 0; | |
| 271 | var v = value; | |
| 272 | while (true) { | |
| 273 | v = v >> 7; | |
| 274 | res += 1; | |
| 275 | if (v == 0) break; | |
| 276 | } | |
| 277 | return res; | |
| 278 | } | |
| 279 | 268 | }; |
| 280 | 269 | |
| 281 | 270 | /// The root node of the trie. |
| ... | ... | @@ -380,9 +369,7 @@ pub fn read(self: *Trie, reader: anytype) ReadError!usize { |
| 380 | 369 | } |
| 381 | 370 | |
| 382 | 371 | /// Write the trie to a byte stream. |
| 383 | /// Caller owns the memory and needs to free it. | |
| 384 | /// Panics if the trie was not finalized using `finalize` | |
| 385 | /// before calling this method. | |
| 372 | /// Panics if the trie was not finalized using `finalize` before calling this method. | |
| 386 | 373 | pub fn write(self: Trie, writer: anytype) !usize { |
| 387 | 374 | assert(!self.trie_dirty); |
| 388 | 375 | var counting_writer = std.io.countingWriter(writer); |
src/link/MachO/imports.zig+149-39| ... | ... | @@ -5,16 +5,22 @@ const mem = std.mem; |
| 5 | 5 | |
| 6 | 6 | const assert = std.debug.assert; |
| 7 | 7 | const Allocator = mem.Allocator; |
| 8 | const sizeLEB128 = @import("../MachO.zig").sizeLEB128; | |
| 8 | 9 | |
| 10 | /// Table of binding info entries used to tell the dyld which | |
| 11 | /// symbols to bind at loading time. | |
| 9 | 12 | pub const BindingInfoTable = struct { |
| 13 | /// Id of the dynamic library where the specified entries can be found. | |
| 10 | 14 | dylib_ordinal: i64 = 0, |
| 15 | ||
| 16 | /// Binding type; defaults to pointer type. | |
| 11 | 17 | binding_type: u8 = macho.BIND_TYPE_POINTER, |
| 12 | entries: std.ArrayListUnmanaged(Entry) = .{}, | |
| 13 | 18 | |
| 14 | pub const Entry = struct { | |
| 15 | /// Id of the symbol in the undef symbol table. | |
| 16 | /// Can be null. | |
| 17 | symbol: ?u16 = null, | |
| 19 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | |
| 20 | ||
| 21 | pub const Symbol = struct { | |
| 22 | /// Symbol name. | |
| 23 | name: ?[]u8 = null, | |
| 18 | 24 | |
| 19 | 25 | /// Id of the segment where to bind this symbol to. |
| 20 | 26 | segment: u8, |
| ... | ... | @@ -24,14 +30,17 @@ pub const BindingInfoTable = struct { |
| 24 | 30 | }; |
| 25 | 31 | |
| 26 | 32 | pub fn deinit(self: *BindingInfoTable, allocator: *Allocator) void { |
| 27 | self.entries.deinit(allocator); | |
| 33 | for (self.symbols.items) |*symbol| { | |
| 34 | if (symbol.name) |name| { | |
| 35 | allocator.free(name); | |
| 36 | } | |
| 37 | } | |
| 38 | self.symbols.deinit(allocator); | |
| 28 | 39 | } |
| 29 | 40 | |
| 30 | pub fn read(self: *BindingInfoTable, allocator: *Allocator, symbols_by_name: anytype, reader: anytype) !void { | |
| 31 | var name = std.ArrayList(u8).init(allocator); | |
| 32 | defer name.deinit(); | |
| 33 | ||
| 34 | var entry: Entry = .{ | |
| 41 | /// Parse the binding info table from byte stream. | |
| 42 | pub fn read(self: *BindingInfoTable, reader: anytype, allocator: *Allocator) !void { | |
| 43 | var symbol: Symbol = .{ | |
| 35 | 44 | .segment = 0, |
| 36 | 45 | .offset = 0, |
| 37 | 46 | }; |
| ... | ... | @@ -48,8 +57,8 @@ pub const BindingInfoTable = struct { |
| 48 | 57 | |
| 49 | 58 | switch (opcode) { |
| 50 | 59 | macho.BIND_OPCODE_DO_BIND => { |
| 51 | try self.entries.append(allocator, entry); | |
| 52 | entry = .{ | |
| 60 | try self.symbols.append(allocator, symbol); | |
| 61 | symbol = .{ | |
| 53 | 62 | .segment = 0, |
| 54 | 63 | .offset = 0, |
| 55 | 64 | }; |
| ... | ... | @@ -59,17 +68,17 @@ pub const BindingInfoTable = struct { |
| 59 | 68 | break; |
| 60 | 69 | }, |
| 61 | 70 | macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => { |
| 62 | name.shrinkRetainingCapacity(0); | |
| 71 | var name = std.ArrayList(u8).init(allocator); | |
| 63 | 72 | var next = try reader.readByte(); |
| 64 | 73 | while (next != @as(u8, 0)) { |
| 65 | 74 | try name.append(next); |
| 66 | 75 | next = try reader.readByte(); |
| 67 | 76 | } |
| 68 | entry.symbol = symbols_by_name.get(name.items[0..]); | |
| 77 | symbol.name = name.toOwnedSlice(); | |
| 69 | 78 | }, |
| 70 | 79 | macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => { |
| 71 | entry.segment = imm; | |
| 72 | entry.offset = try leb.readILEB128(i64, reader); | |
| 80 | symbol.segment = imm; | |
| 81 | symbol.offset = try leb.readILEB128(i64, reader); | |
| 73 | 82 | }, |
| 74 | 83 | macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => { |
| 75 | 84 | assert(!dylib_ordinal_set); |
| ... | ... | @@ -90,15 +99,69 @@ pub const BindingInfoTable = struct { |
| 90 | 99 | assert(done); |
| 91 | 100 | } |
| 92 | 101 | |
| 93 | pub fn write(self: BindingInfoTable, writer: anytype) !void {} | |
| 102 | /// Write the binding info table to byte stream. | |
| 103 | pub fn write(self: BindingInfoTable, writer: anytype) !void { | |
| 104 | if (self.dylib_ordinal > 15) { | |
| 105 | try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); | |
| 106 | try leb.writeULEB128(writer, @bitCast(u64, self.dylib_ordinal)); | |
| 107 | } else if (self.dylib_ordinal > 0) { | |
| 108 | try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, self.dylib_ordinal))); | |
| 109 | } else { | |
| 110 | try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, self.dylib_ordinal))); | |
| 111 | } | |
| 112 | try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, self.binding_type)); | |
| 113 | ||
| 114 | for (self.symbols.items) |symbol| { | |
| 115 | if (symbol.name) |name| { | |
| 116 | try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags. | |
| 117 | try writer.writeAll(name); | |
| 118 | try writer.writeByte(0); | |
| 119 | } | |
| 120 | ||
| 121 | try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment)); | |
| 122 | try leb.writeILEB128(writer, symbol.offset); | |
| 123 | ||
| 124 | try writer.writeByte(macho.BIND_OPCODE_DO_BIND); | |
| 125 | } | |
| 126 | ||
| 127 | try writer.writeByte(macho.BIND_OPCODE_DONE); | |
| 128 | } | |
| 129 | ||
| 130 | /// Calculate size in bytes of this binding info table. | |
| 131 | pub fn calcSize(self: *BindingInfoTable) usize { | |
| 132 | var size: usize = 1; | |
| 133 | if (self.dylib_ordinal > 15) { | |
| 134 | size += sizeLEB128(self.dylib_ordinal); | |
| 135 | } | |
| 136 | ||
| 137 | size += 1; | |
| 138 | ||
| 139 | for (self.symbols.items) |symbol| { | |
| 140 | if (symbol.name) |name| { | |
| 141 | size += 1; | |
| 142 | size += name.len; | |
| 143 | size += 1; | |
| 144 | } | |
| 145 | ||
| 146 | size += 1; | |
| 147 | size += sizeLEB128(symbol.offset); | |
| 148 | ||
| 149 | size += 1; | |
| 150 | } | |
| 151 | ||
| 152 | size += 1; | |
| 153 | return size; | |
| 154 | } | |
| 94 | 155 | }; |
| 95 | 156 | |
| 157 | /// Table of lazy binding info entries used to tell the dyld which | |
| 158 | /// symbols to lazily bind at first load of a dylib. | |
| 96 | 159 | pub const LazyBindingInfoTable = struct { |
| 97 | entries: std.ArrayListUnmanaged(Entry) = .{}, | |
| 160 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | |
| 98 | 161 | |
| 99 | pub const Entry = struct { | |
| 100 | /// Id of the symbol in the undef symbol table. | |
| 101 | symbol: u16, | |
| 162 | pub const Symbol = struct { | |
| 163 | /// Symbol name. | |
| 164 | name: ?[]u8 = null, | |
| 102 | 165 | |
| 103 | 166 | /// Offset of this symbol wrt to the segment id encoded in `segment`. |
| 104 | 167 | offset: i64, |
| ... | ... | @@ -113,15 +176,17 @@ pub const LazyBindingInfoTable = struct { |
| 113 | 176 | }; |
| 114 | 177 | |
| 115 | 178 | pub fn deinit(self: *LazyBindingInfoTable, allocator: *Allocator) void { |
| 116 | self.entries.deinit(allocator); | |
| 179 | for (self.symbols.items) |*symbol| { | |
| 180 | if (symbol.name) |name| { | |
| 181 | allocator.free(name); | |
| 182 | } | |
| 183 | } | |
| 184 | self.symbols.deinit(allocator); | |
| 117 | 185 | } |
| 118 | 186 | |
| 119 | pub fn read(self: *LazyBindingInfoTable, allocator: *Allocator, symbols_by_name: anytype, reader: anytype) !void { | |
| 120 | var name = std.ArrayList(u8).init(allocator); | |
| 121 | defer name.deinit(); | |
| 122 | ||
| 123 | var entry: Entry = .{ | |
| 124 | .symbol = 0, | |
| 187 | /// Parse the binding info table from byte stream. | |
| 188 | pub fn read(self: *LazyBindingInfoTable, reader: anytype, allocator: *Allocator) !void { | |
| 189 | var symbol: Symbol = .{ | |
| 125 | 190 | .offset = 0, |
| 126 | 191 | .segment = 0, |
| 127 | 192 | .dylib_ordinal = 0, |
| ... | ... | @@ -138,35 +203,34 @@ pub const LazyBindingInfoTable = struct { |
| 138 | 203 | |
| 139 | 204 | switch (opcode) { |
| 140 | 205 | macho.BIND_OPCODE_DO_BIND => { |
| 141 | try self.entries.append(allocator, entry); | |
| 206 | try self.symbols.append(allocator, symbol); | |
| 142 | 207 | }, |
| 143 | 208 | macho.BIND_OPCODE_DONE => { |
| 144 | 209 | done = true; |
| 145 | entry = .{ | |
| 146 | .symbol = 0, | |
| 210 | symbol = .{ | |
| 147 | 211 | .offset = 0, |
| 148 | 212 | .segment = 0, |
| 149 | 213 | .dylib_ordinal = 0, |
| 150 | 214 | }; |
| 151 | 215 | }, |
| 152 | 216 | macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => { |
| 153 | name.shrinkRetainingCapacity(0); | |
| 217 | var name = std.ArrayList(u8).init(allocator); | |
| 154 | 218 | var next = try reader.readByte(); |
| 155 | 219 | while (next != @as(u8, 0)) { |
| 156 | 220 | try name.append(next); |
| 157 | 221 | next = try reader.readByte(); |
| 158 | 222 | } |
| 159 | entry.symbol = symbols_by_name.get(name.items[0..]) orelse unreachable; | |
| 223 | symbol.name = name.toOwnedSlice(); | |
| 160 | 224 | }, |
| 161 | 225 | macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => { |
| 162 | entry.segment = imm; | |
| 163 | entry.offset = try leb.readILEB128(i64, reader); | |
| 226 | symbol.segment = imm; | |
| 227 | symbol.offset = try leb.readILEB128(i64, reader); | |
| 164 | 228 | }, |
| 165 | 229 | macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => { |
| 166 | entry.dylib_ordinal = imm; | |
| 230 | symbol.dylib_ordinal = imm; | |
| 167 | 231 | }, |
| 168 | 232 | macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => { |
| 169 | entry.dylib_ordinal = try leb.readILEB128(i64, reader); | |
| 233 | symbol.dylib_ordinal = try leb.readILEB128(i64, reader); | |
| 170 | 234 | }, |
| 171 | 235 | else => { |
| 172 | 236 | std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode}); |
| ... | ... | @@ -176,5 +240,51 @@ pub const LazyBindingInfoTable = struct { |
| 176 | 240 | assert(done); |
| 177 | 241 | } |
| 178 | 242 | |
| 179 | pub fn write(self: LazyBindingInfoTable, writer: anytype) !void {} | |
| 243 | /// Write the binding info table to byte stream. | |
| 244 | pub fn write(self: LazyBindingInfoTable, writer: anytype) !void { | |
| 245 | for (self.symbols.items) |symbol| { | |
| 246 | try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment)); | |
| 247 | try leb.writeILEB128(writer, symbol.offset); | |
| 248 | ||
| 249 | if (symbol.dylib_ordinal > 15) { | |
| 250 | try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); | |
| 251 | try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal)); | |
| 252 | } else if (symbol.dylib_ordinal > 0) { | |
| 253 | try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal))); | |
| 254 | } else { | |
| 255 | try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, symbol.dylib_ordinal))); | |
| 256 | } | |
| 257 | ||
| 258 | if (symbol.name) |name| { | |
| 259 | try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags. | |
| 260 | try writer.writeAll(name); | |
| 261 | try writer.writeByte(0); | |
| 262 | } | |
| 263 | ||
| 264 | try writer.writeByte(macho.BIND_OPCODE_DO_BIND); | |
| 265 | try writer.writeByte(macho.BIND_OPCODE_DONE); | |
| 266 | } | |
| 267 | } | |
| 268 | ||
| 269 | /// Calculate size in bytes of this binding info table. | |
| 270 | pub fn calcSize(self: *LazyBindingInfoTable) usize { | |
| 271 | var size: usize = 0; | |
| 272 | ||
| 273 | for (self.symbols.items) |symbol| { | |
| 274 | size += 1; | |
| 275 | size += sizeLEB128(symbol.offset); | |
| 276 | size += 1; | |
| 277 | if (symbol.dylib_ordinal > 15) { | |
| 278 | size += sizeLEB128(symbol.dylib_ordinal); | |
| 279 | } | |
| 280 | if (symbol.name) |name| { | |
| 281 | size += 1; | |
| 282 | size += name.len; | |
| 283 | size += 1; | |
| 284 | } | |
| 285 | size += 2; | |
| 286 | } | |
| 287 | ||
| 288 | return size; | |
| 289 | } | |
| 180 | 290 | }; |