| ... | ... | @@ -2505,7 +2505,7 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| 2505 | 2505 | const displacement = @intCast(i32, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - stub_size); |
| 2506 | 2506 | // pushq |
| 2507 | 2507 | code[0] = 0x68; |
| 2508 | | mem.writeIntLittle(u32, code[1..][0..4], index * 0xd); // TODO |
| 2508 | mem.writeIntLittle(u32, code[1..][0..4], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 2509 | 2509 | // jmpq |
| 2510 | 2510 | code[5] = 0xe9; |
| 2511 | 2511 | mem.writeIntLittle(u32, code[6..][0..4], @bitCast(u32, displacement)); |
| ... | ... | @@ -2516,7 +2516,7 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| 2516 | 2516 | .literal = 0x2, |
| 2517 | 2517 | }).toU32()); |
| 2518 | 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 | 2521 | else => unreachable, |
| 2522 | 2522 | } |
| ... | ... | @@ -2630,6 +2630,7 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2630 | 2630 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 2631 | 2631 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 2632 | 2632 | dysymtab.nindirectsyms = 0; |
| 2633 | // TODO check if we have allocated enough size. |
| 2633 | 2634 | |
| 2634 | 2635 | var buf: [@sizeOf(u32)]u8 = undefined; |
| 2635 | 2636 | var off = dysymtab.indirectsymoff; |
| ... | ... | @@ -2868,10 +2869,78 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2868 | 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 }); |
| 2869 | 2870 | |
| 2870 | 2871 | try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); |
| 2872 | try self.populateLazyBindOffsetsInStubHelper(buffer); |
| 2871 | 2873 | self.load_commands_dirty = true; |
| 2872 | 2874 | self.lazy_binding_info_dirty = false; |
| 2873 | 2875 | } |
| 2874 | 2876 | |
| 2877 | fn 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 | |
| 2875 | 2944 | fn writeStringTable(self: *MachO) !void { |
| 2876 | 2945 | if (!self.string_table_dirty) return; |
| 2877 | 2946 | |
| ... | ... | @@ -2979,8 +3048,6 @@ fn writeHeader(self: *MachO) !void { |
| 2979 | 3048 | } |
| 2980 | 3049 | |
| 2981 | 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. |
| 2984 | 3051 | fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 2985 | 3052 | self.base.file = file; |
| 2986 | 3053 | var reader = file.reader(); |