| ... | @@ -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 | // pushq | 2506 | // pushq |
| 2507 | code[0] = 0x68; | 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 | // jmpq | 2509 | // 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. |
| 2633 | | 2634 | |
| 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 }); |
| 2869 | | 2870 | |
| 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 | } |
| 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 | fn writeStringTable(self: *MachO) !void { | 2944 | fn writeStringTable(self: *MachO) !void { |
| 2876 | if (!self.string_table_dirty) return; | 2945 | if (!self.string_table_dirty) return; |
| 2877 | | 2946 | |
| ... | @@ -2979,8 +3048,6 @@ fn writeHeader(self: *MachO) !void { | ... | @@ -2979,8 +3048,6 @@ fn writeHeader(self: *MachO) !void { |
| 2979 | } | 3048 | } |
| 2980 | | 3049 | |
| 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. | | |
| 2984 | fn parseFromFile(self: *MachO, file: fs.File) !void { | 3051 | fn 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(); |