macho: parse binding info into a table of entries

This commit is contained in:
Jakub Konka 2020-12-12 15:58:54 +01:00
parent 77e545892e
commit 46b2a08d06

View File

@ -811,6 +811,20 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
try self.parseSymbolTable();
try self.parseStringTable();
std.debug.print("Undef symbols\n", .{});
for (self.undef_symbols.items) |sym| {
const name = self.string_table.items[sym.n_strx..];
const len = blk: {
var end: usize = 0;
while (true) {
if (name[end] == @as(u8, 0)) break;
end += 1;
}
break :blk end;
};
std.debug.print("name={},sym={}\n", .{ name[0..len], sym });
}
// Parse dyld info
try self.parseBindingInfo();
try self.parseLazyBindingInfo();
@ -2090,6 +2104,9 @@ fn parseBindingInfo(self: *MachO) !void {
defer self.base.allocator.free(buffer);
const nread = try self.base.file.?.preadAll(buffer, dyld_info.bind_off);
assert(nread == buffer.len);
try parseBindingInfos(self, buffer);
if (try parseAndFixupBindingInfoBuffer(self.base.allocator, buffer)) {
try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
}
@ -2101,6 +2118,9 @@ fn parseLazyBindingInfo(self: *MachO) !void {
defer self.base.allocator.free(buffer);
const nread = try self.base.file.?.preadAll(buffer, dyld_info.lazy_bind_off);
assert(nread == buffer.len);
try parseBindingInfos(self, buffer);
if (try parseAndFixupBindingInfoBuffer(self.base.allocator, buffer)) {
try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
}
@ -2155,3 +2175,105 @@ fn parseAndFixupBindingInfoBuffer(allocator: *Allocator, buffer: []u8) !bool {
return buffer_dirty;
}
const BindingEntry = struct {
symbol: ?u16 = null,
offset: i64,
dylib_ordinal: ?i64 = null,
segment: u8,
bind_type: u8,
};
fn parseBindingInfos(self: *MachO, buffer: []u8) !void {
var symbolsByName = std.StringHashMap(u16).init(self.base.allocator);
defer symbolsByName.deinit();
try symbolsByName.ensureCapacity(@intCast(u32, self.undef_symbols.items.len));
for (self.undef_symbols.items) |sym, i| {
const name = self.string_table.items[sym.n_strx..];
const len = blk: {
var end: usize = 0;
while (true) {
if (name[end] == @as(u8, 0)) break;
end += 1;
}
break :blk end;
};
symbolsByName.putAssumeCapacityNoClobber(name[0..len], @intCast(u16, i));
}
var stream = std.io.fixedBufferStream(buffer);
var reader = stream.reader();
var done = false;
var name = std.ArrayList(u8).init(self.base.allocator);
defer name.deinit();
var entries = std.ArrayList(BindingEntry).init(self.base.allocator);
defer entries.deinit();
var dylib_ordinal: i64 = 0;
var entry: BindingEntry = .{
.offset = 0,
.segment = 0,
.bind_type = 0,
};
while (true) {
const inst = reader.readByte() catch |err| switch (err) {
error.EndOfStream => break,
else => return err,
};
const imm: u8 = inst & macho.BIND_IMMEDIATE_MASK;
const opcode: u8 = inst & macho.BIND_OPCODE_MASK;
switch (opcode) {
macho.BIND_OPCODE_DO_BIND => {
if (entry.dylib_ordinal == null) {
entry.dylib_ordinal = dylib_ordinal;
}
try entries.append(entry);
entry = .{
.offset = 0,
.segment = 0,
.bind_type = 0,
};
},
macho.BIND_OPCODE_DONE => {
done = true;
},
macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
name.shrinkRetainingCapacity(0);
var next = try reader.readByte();
while (next != @as(u8, 0)) {
try name.append(next);
next = try reader.readByte();
}
std.debug.print("name={}\n", .{name.items});
entry.symbol = symbolsByName.get(name.items[0..]);
},
macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {
entry.segment = imm;
entry.offset = try std.leb.readILEB128(i64, reader);
},
macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => {
entry.dylib_ordinal = imm;
},
macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => {
dylib_ordinal = try std.leb.readILEB128(i64, reader);
entry.dylib_ordinal = dylib_ordinal;
},
macho.BIND_OPCODE_SET_TYPE_IMM => {
entry.bind_type = imm;
},
else => {
std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode});
},
}
}
assert(done);
for (entries.items) |e| {
std.debug.print("entry={}\n", .{e});
}
}