zig/src/link/MachO/bind.zig

139 lines
4.6 KiB
Zig

const std = @import("std");
const leb = std.leb;
const macho = std.macho;
pub const Pointer = struct {
offset: u64,
segment_id: u16,
dylib_ordinal: ?i64 = null,
name: ?[]const u8 = null,
bind_flags: u4 = 0,
};
pub fn rebaseInfoSize(pointers: []const Pointer) !u64 {
var stream = std.io.countingWriter(std.io.null_writer);
var writer = stream.writer();
var size: u64 = 0;
for (pointers) |pointer| {
size += 2;
try leb.writeILEB128(writer, pointer.offset);
size += 1;
}
size += 1 + stream.bytes_written;
return size;
}
pub fn writeRebaseInfo(pointers: []const Pointer, writer: anytype) !void {
for (pointers) |pointer| {
try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.REBASE_TYPE_POINTER));
try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id));
try leb.writeILEB128(writer, pointer.offset);
try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @truncate(u4, 1));
}
try writer.writeByte(macho.REBASE_OPCODE_DONE);
}
pub fn bindInfoSize(pointers: []const Pointer) !u64 {
var stream = std.io.countingWriter(std.io.null_writer);
var writer = stream.writer();
var size: u64 = 0;
for (pointers) |pointer| {
size += 1;
if (pointer.dylib_ordinal.? > 15) {
try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?));
}
size += 1;
size += 1;
size += pointer.name.?.len;
size += 1;
size += 1;
try leb.writeILEB128(writer, pointer.offset);
size += 1;
}
size += stream.bytes_written + 1;
return size;
}
pub fn writeBindInfo(pointers: []const Pointer, writer: anytype) !void {
for (pointers) |pointer| {
if (pointer.dylib_ordinal.? > 15) {
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?));
} else if (pointer.dylib_ordinal.? > 0) {
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
} else {
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
}
try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @truncate(u4, macho.BIND_TYPE_POINTER));
try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | pointer.bind_flags);
try writer.writeAll(pointer.name.?);
try writer.writeByte(0);
try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id));
try leb.writeILEB128(writer, pointer.offset);
try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
}
try writer.writeByte(macho.BIND_OPCODE_DONE);
}
pub fn lazyBindInfoSize(pointers: []const Pointer) !u64 {
var stream = std.io.countingWriter(std.io.null_writer);
var writer = stream.writer();
var size: u64 = 0;
for (pointers) |pointer| {
size += 1;
try leb.writeILEB128(writer, pointer.offset);
size += 1;
if (pointer.dylib_ordinal.? > 15) {
try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?));
}
size += 1;
size += pointer.name.?.len;
size += 1;
size += 2;
}
size += stream.bytes_written;
return size;
}
pub fn writeLazyBindInfo(pointers: []const Pointer, writer: anytype) !void {
for (pointers) |pointer| {
try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, pointer.segment_id));
try leb.writeILEB128(writer, pointer.offset);
if (pointer.dylib_ordinal.? > 15) {
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
try leb.writeULEB128(writer, @bitCast(u64, pointer.dylib_ordinal.?));
} else if (pointer.dylib_ordinal.? > 0) {
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
} else {
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @truncate(u4, @bitCast(u64, pointer.dylib_ordinal.?)));
}
try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | pointer.bind_flags);
try writer.writeAll(pointer.name.?);
try writer.writeByte(0);
try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
try writer.writeByte(macho.BIND_OPCODE_DONE);
}
}