authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-10 21:06:56+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-13 23:55:48+01:00
log2ea0901dd639a98f182b71f7da7fde988fdcd91b
tree7b43b8dc794e6163d3354702410e578c65a51bc7
parentf0d7ec6f33634edb0ddb3ba5d5b306e9f2de5418

macho: properly populate offset into lazy bind info


1 files changed, 71 insertions(+), 4 deletions(-)

src/link/MachO.zig+71-4
...@@ -2505,7 +2505,7 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void {...@@ -2505,7 +2505,7 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void {
2505 const displacement = @intCast(i32, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - stub_size);2505 const displacement = @intCast(i32, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - stub_size);
2506 // pushq2506 // pushq
2507 code[0] = 0x68;2507 code[0] = 0x68;
2508 mem.writeIntLittle(u32, code[1..][0..4], index * 0xd); // TODO2508 mem.writeIntLittle(u32, code[1..][0..4], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.
2509 // jmpq2509 // jmpq
2510 code[5] = 0xe9;2510 code[5] = 0xe9;
2511 mem.writeIntLittle(u32, code[6..][0..4], @bitCast(u32, displacement));2511 mem.writeIntLittle(u32, code[6..][0..4], @bitCast(u32, displacement));
...@@ -2516,7 +2516,7 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void {...@@ -2516,7 +2516,7 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void {
2516 .literal = 0x2,2516 .literal = 0x2,
2517 }).toU32());2517 }).toU32());
2518 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(@intCast(i28, displacement)).toU32());2518 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(@intCast(i28, displacement)).toU32());
2519 mem.writeIntLittle(u32, code[8..12], index * 0xd); // TODO This is the size of lazy binding opcode block.2519 mem.writeIntLittle(u32, code[8..12], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.
2520 },2520 },
2521 else => unreachable,2521 else => unreachable,
2522 }2522 }
...@@ -2630,6 +2630,7 @@ fn writeIndirectSymbolTable(self: *MachO) !void {...@@ -2630,6 +2630,7 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
2630 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];2630 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
2631 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;2631 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
2632 dysymtab.nindirectsyms = 0;2632 dysymtab.nindirectsyms = 0;
2633 // TODO check if we have allocated enough size.
26332634
2634 var buf: [@sizeOf(u32)]u8 = undefined;2635 var buf: [@sizeOf(u32)]u8 = undefined;
2635 var off = dysymtab.indirectsymoff;2636 var off = dysymtab.indirectsymoff;
...@@ -2868,10 +2869,78 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {...@@ -2868,10 +2869,78 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
2868 log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size });2869 log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size });
28692870
2870 try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);2871 try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
2872 try self.populateLazyBindOffsetsInStubHelper(buffer);
2871 self.load_commands_dirty = true;2873 self.load_commands_dirty = true;
2872 self.lazy_binding_info_dirty = false;2874 self.lazy_binding_info_dirty = false;
2873}2875}
28742876
2877fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
2878 if (self.extern_lazy_symbols.items().len == 0) return;
2879
2880 var stream = std.io.fixedBufferStream(buffer);
2881 var reader = stream.reader();
2882 var offsets = std.ArrayList(u32).init(self.base.allocator);
2883 try offsets.append(0);
2884 defer offsets.deinit();
2885 var valid_block = false;
2886
2887 while (true) {
2888 const inst = reader.readByte() catch |err| switch (err) {
2889 error.EndOfStream => break,
2890 else => return err,
2891 };
2892 const imm: u8 = inst & macho.BIND_IMMEDIATE_MASK;
2893 const opcode: u8 = inst & macho.BIND_OPCODE_MASK;
2894
2895 switch (opcode) {
2896 macho.BIND_OPCODE_DO_BIND => {
2897 valid_block = true;
2898 },
2899 macho.BIND_OPCODE_DONE => {
2900 if (valid_block) {
2901 const offset = try stream.getPos();
2902 try offsets.append(@intCast(u32, offset));
2903 }
2904 valid_block = false;
2905 },
2906 macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
2907 var next = try reader.readByte();
2908 while (next != @as(u8, 0)) {
2909 next = try reader.readByte();
2910 }
2911 },
2912 macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {
2913 _ = try std.leb.readULEB128(u64, reader);
2914 },
2915 macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => {
2916 _ = try std.leb.readULEB128(u64, reader);
2917 },
2918 macho.BIND_OPCODE_SET_ADDEND_SLEB => {
2919 _ = try std.leb.readILEB128(i64, reader);
2920 },
2921 else => {},
2922 }
2923 }
2924 assert(self.extern_lazy_symbols.items().len <= offsets.items.len);
2925
2926 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
2927 .x86_64 => 10,
2928 .aarch64 => 3 * @sizeOf(u32),
2929 else => unreachable,
2930 };
2931 const off: u4 = switch (self.base.options.target.cpu.arch) {
2932 .x86_64 => 1,
2933 .aarch64 => 2 * @sizeOf(u32),
2934 else => unreachable,
2935 };
2936 var buf: [@sizeOf(u32)]u8 = undefined;
2937 for (self.extern_lazy_symbols.items()) |_, i| {
2938 const placeholder_off = self.stub_helper_stubs_start_off.? + i * stub_size + off;
2939 mem.writeIntLittle(u32, &buf, offsets.items[i]);
2940 try self.base.file.?.pwriteAll(&buf, placeholder_off);
2941 }
2942}
2943
2875fn writeStringTable(self: *MachO) !void {2944fn writeStringTable(self: *MachO) !void {
2876 if (!self.string_table_dirty) return;2945 if (!self.string_table_dirty) return;
28772946
...@@ -2979,8 +3048,6 @@ fn writeHeader(self: *MachO) !void {...@@ -2979,8 +3048,6 @@ fn writeHeader(self: *MachO) !void {
2979}3048}
29803049
2981/// Parse MachO contents from existing binary file.3050/// Parse MachO contents from existing binary file.
2982/// TODO This method is incomplete and currently parses only the header
2983/// plus the load commands.
2984fn parseFromFile(self: *MachO, file: fs.File) !void {3051fn parseFromFile(self: *MachO, file: fs.File) !void {
2985 self.base.file = file;3052 self.base.file = file;
2986 var reader = file.reader();3053 var reader = file.reader();