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 rebaseInfoSize(pointers: []const Pointer) !u64 { 13 var stream = std.io.countingWriter(std.io.null_writer); 14 var writer = stream.writer(); 15 var size: u64 = 0; 16 17 for (pointers) |pointer| { 18 size += 2; 19 try leb.writeILEB128(writer, pointer.offset); 20 size += 1; 21 } 22 23 size += 1 + stream.bytes_written; 24 return size; 25} 26 27pub fn writeRebaseInfo(pointers: []const Pointer, writer: anytype) !void { 28 for (pointers) |pointer| { 29 try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.REBASE_TYPE_POINTER)); 30 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id)); 31 32 try leb.writeILEB128(writer, pointer.offset); 33 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @truncate(u4, 1)); 34 } 35 try writer.writeByte(macho.REBASE_OPCODE_DONE); 36} 37 38pub fn bindInfoSize(pointers: []const Pointer) !u64 { 39 var stream = std.io.countingWriter(std.io.null_writer); 40 var writer = stream.writer(); 41 var size: u64 = 0; 42 43 for (pointers) |pointer| { 44 size += 1; 45 if (pointer.dylib_ordinal.? > 15) { 46 try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?)); 47 } 48 size += 1; 49 50 size += 1; 51 size += pointer.name.?.len; 52 size += 1; 53 54 size += 1; 55 56 try leb.writeILEB128(writer, pointer.offset); 57 size += 1; 58 } 59 60 size += stream.bytes_written + 1; 61 return size; 62} 63 64pub fn writeBindInfo(pointers: []const Pointer, writer: anytype) !void { 65 for (pointers) |pointer| { 66 if (pointer.dylib_ordinal.? > 15) { 67 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); 68 try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?)); 69 } else if (pointer.dylib_ordinal.? > 0) { 70 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?))); 71 } else { 72 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?))); 73 } 74 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.BIND_TYPE_POINTER)); 75 76 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags. 77 try writer.writeAll(pointer.name.?); 78 try writer.writeByte(0); 79 80 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id)); 81 82 try leb.writeILEB128(writer, pointer.offset); 83 try writer.writeByte(macho.BIND_OPCODE_DO_BIND); 84 } 85 86 try writer.writeByte(macho.BIND_OPCODE_DONE); 87} 88 89pub fn lazyBindInfoSize(pointers: []const Pointer) !u64 { 90 var stream = std.io.countingWriter(std.io.null_writer); 91 var writer = stream.writer(); 92 var size: u64 = 0; 93 94 for (pointers) |pointer| { 95 size += 1; 96 97 try leb.writeILEB128(writer, pointer.offset); 98 99 size += 1; 100 if (pointer.dylib_ordinal.? > 15) { 101 try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?)); 102 } 103 104 size += 1; 105 size += pointer.name.?.len; 106 size += 1; 107 108 size += 2; 109 } 110 111 size += stream.bytes_written; 112 return size; 113} 114 115pub fn writeLazyBindInfo(pointers: []const Pointer, writer: anytype) !void { 116 for (pointers) |pointer| { 117 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id)); 118 119 try leb.writeILEB128(writer, pointer.offset); 120 121 if (pointer.dylib_ordinal.? > 15) { 122 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); 123 try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?)); 124 } else if (pointer.dylib_ordinal.? > 0) { 125 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?))); 126 } else { 127 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?))); 128 } 129 130 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM); // TODO Sometimes we might want to add flags. 131 try writer.writeAll(pointer.name.?); 132 try writer.writeByte(0); 133 134 try writer.writeByte(macho.BIND_OPCODE_DO_BIND); 135 try writer.writeByte(macho.BIND_OPCODE_DONE); 136 } 137} 138