authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-12 15:58:54+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-17 10:04:53+01:00
log46b2a08d067fd9e4a0b499e1da69bd0be29aaa5a
treee1fdaf55a01c118702e8c1ed2176c6df263ce899
parent77e545892e316da57649268f55326e215f3491ca

macho: parse binding info into a table of entries


1 files changed, 122 insertions(+), 0 deletions(-)

src/link/MachO.zig+122
......@@ -811,6 +811,20 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
811811 try self.parseSymbolTable();
812812 try self.parseStringTable();
813813
814 std.debug.print("Undef symbols\n", .{});
815 for (self.undef_symbols.items) |sym| {
816 const name = self.string_table.items[sym.n_strx..];
817 const len = blk: {
818 var end: usize = 0;
819 while (true) {
820 if (name[end] == @as(u8, 0)) break;
821 end += 1;
822 }
823 break :blk end;
824 };
825 std.debug.print("name={},sym={}\n", .{ name[0..len], sym });
826 }
827
814828 // Parse dyld info
815829 try self.parseBindingInfo();
816830 try self.parseLazyBindingInfo();
......@@ -2090,6 +2104,9 @@ fn parseBindingInfo(self: *MachO) !void {
20902104 defer self.base.allocator.free(buffer);
20912105 const nread = try self.base.file.?.preadAll(buffer, dyld_info.bind_off);
20922106 assert(nread == buffer.len);
2107
2108 try parseBindingInfos(self, buffer);
2109
20932110 if (try parseAndFixupBindingInfoBuffer(self.base.allocator, buffer)) {
20942111 try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
20952112 }
......@@ -2101,6 +2118,9 @@ fn parseLazyBindingInfo(self: *MachO) !void {
21012118 defer self.base.allocator.free(buffer);
21022119 const nread = try self.base.file.?.preadAll(buffer, dyld_info.lazy_bind_off);
21032120 assert(nread == buffer.len);
2121
2122 try parseBindingInfos(self, buffer);
2123
21042124 if (try parseAndFixupBindingInfoBuffer(self.base.allocator, buffer)) {
21052125 try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
21062126 }
......@@ -2155,3 +2175,105 @@ fn parseAndFixupBindingInfoBuffer(allocator: *Allocator, buffer: []u8) !bool {
21552175
21562176 return buffer_dirty;
21572177}
2178
2179const BindingEntry = struct {
2180 symbol: ?u16 = null,
2181 offset: i64,
2182 dylib_ordinal: ?i64 = null,
2183 segment: u8,
2184 bind_type: u8,
2185};
2186
2187fn parseBindingInfos(self: *MachO, buffer: []u8) !void {
2188 var symbolsByName = std.StringHashMap(u16).init(self.base.allocator);
2189 defer symbolsByName.deinit();
2190 try symbolsByName.ensureCapacity(@intCast(u32, self.undef_symbols.items.len));
2191
2192 for (self.undef_symbols.items) |sym, i| {
2193 const name = self.string_table.items[sym.n_strx..];
2194 const len = blk: {
2195 var end: usize = 0;
2196 while (true) {
2197 if (name[end] == @as(u8, 0)) break;
2198 end += 1;
2199 }
2200 break :blk end;
2201 };
2202 symbolsByName.putAssumeCapacityNoClobber(name[0..len], @intCast(u16, i));
2203 }
2204
2205 var stream = std.io.fixedBufferStream(buffer);
2206 var reader = stream.reader();
2207 var done = false;
2208
2209 var name = std.ArrayList(u8).init(self.base.allocator);
2210 defer name.deinit();
2211
2212 var entries = std.ArrayList(BindingEntry).init(self.base.allocator);
2213 defer entries.deinit();
2214 var dylib_ordinal: i64 = 0;
2215
2216 var entry: BindingEntry = .{
2217 .offset = 0,
2218 .segment = 0,
2219 .bind_type = 0,
2220 };
2221
2222 while (true) {
2223 const inst = reader.readByte() catch |err| switch (err) {
2224 error.EndOfStream => break,
2225 else => return err,
2226 };
2227 const imm: u8 = inst & macho.BIND_IMMEDIATE_MASK;
2228 const opcode: u8 = inst & macho.BIND_OPCODE_MASK;
2229
2230 switch (opcode) {
2231 macho.BIND_OPCODE_DO_BIND => {
2232 if (entry.dylib_ordinal == null) {
2233 entry.dylib_ordinal = dylib_ordinal;
2234 }
2235 try entries.append(entry);
2236 entry = .{
2237 .offset = 0,
2238 .segment = 0,
2239 .bind_type = 0,
2240 };
2241 },
2242 macho.BIND_OPCODE_DONE => {
2243 done = true;
2244 },
2245 macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
2246 name.shrinkRetainingCapacity(0);
2247 var next = try reader.readByte();
2248 while (next != @as(u8, 0)) {
2249 try name.append(next);
2250 next = try reader.readByte();
2251 }
2252 std.debug.print("name={}\n", .{name.items});
2253 entry.symbol = symbolsByName.get(name.items[0..]);
2254 },
2255 macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {
2256 entry.segment = imm;
2257 entry.offset = try std.leb.readILEB128(i64, reader);
2258 },
2259 macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => {
2260 entry.dylib_ordinal = imm;
2261 },
2262 macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => {
2263 dylib_ordinal = try std.leb.readILEB128(i64, reader);
2264 entry.dylib_ordinal = dylib_ordinal;
2265 },
2266 macho.BIND_OPCODE_SET_TYPE_IMM => {
2267 entry.bind_type = imm;
2268 },
2269 else => {
2270 std.log.warn("unhandled BIND_OPCODE_: 0x{x}", .{opcode});
2271 },
2272 }
2273 }
2274 assert(done);
2275
2276 for (entries.items) |e| {
2277 std.debug.print("entry={}\n", .{e});
2278 }
2279}