diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-01-10 21:06:56 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-01-13 23:55:48 +0100 |
| commit | 2ea0901dd639a98f182b71f7da7fde988fdcd91b (patch) | |
| tree | 7b43b8dc794e6163d3354702410e578c65a51bc7 /src/link | |
| parent | f0d7ec6f33634edb0ddb3ba5d5b306e9f2de5418 (diff) | |
| download | zig-2ea0901dd639a98f182b71f7da7fde988fdcd91b.tar.gz zig-2ea0901dd639a98f182b71f7da7fde988fdcd91b.zip | |
macho: properly populate offset into lazy bind info
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/MachO.zig | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index fed3ee7836..27c395da95 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2505,7 +2505,7 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { const displacement = @intCast(i32, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - stub_size); // pushq code[0] = 0x68; - mem.writeIntLittle(u32, code[1..][0..4], index * 0xd); // TODO + mem.writeIntLittle(u32, code[1..][0..4], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. // jmpq code[5] = 0xe9; mem.writeIntLittle(u32, code[6..][0..4], @bitCast(u32, displacement)); @@ -2516,7 +2516,7 @@ fn writeStubInStubHelper(self: *MachO, index: u32) !void { .literal = 0x2, }).toU32()); mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(@intCast(i28, displacement)).toU32()); - mem.writeIntLittle(u32, code[8..12], index * 0xd); // TODO This is the size of lazy binding opcode block. + mem.writeIntLittle(u32, code[8..12], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. }, else => unreachable, } @@ -2630,6 +2630,7 @@ fn writeIndirectSymbolTable(self: *MachO) !void { const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; dysymtab.nindirectsyms = 0; + // TODO check if we have allocated enough size. var buf: [@sizeOf(u32)]u8 = undefined; var off = dysymtab.indirectsymoff; @@ -2868,10 +2869,78 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { 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 }); try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); + try self.populateLazyBindOffsetsInStubHelper(buffer); self.load_commands_dirty = true; self.lazy_binding_info_dirty = false; } +fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { + if (self.extern_lazy_symbols.items().len == 0) return; + + var stream = std.io.fixedBufferStream(buffer); + var reader = stream.reader(); + var offsets = std.ArrayList(u32).init(self.base.allocator); + try offsets.append(0); + defer offsets.deinit(); + var valid_block = false; + + 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 => { + valid_block = true; + }, + macho.BIND_OPCODE_DONE => { + if (valid_block) { + const offset = try stream.getPos(); + try offsets.append(@intCast(u32, offset)); + } + valid_block = false; + }, + macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => { + var next = try reader.readByte(); + while (next != @as(u8, 0)) { + next = try reader.readByte(); + } + }, + macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => { + _ = try std.leb.readULEB128(u64, reader); + }, + macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => { + _ = try std.leb.readULEB128(u64, reader); + }, + macho.BIND_OPCODE_SET_ADDEND_SLEB => { + _ = try std.leb.readILEB128(i64, reader); + }, + else => {}, + } + } + assert(self.extern_lazy_symbols.items().len <= offsets.items.len); + + const stub_size: u4 = switch (self.base.options.target.cpu.arch) { + .x86_64 => 10, + .aarch64 => 3 * @sizeOf(u32), + else => unreachable, + }; + const off: u4 = switch (self.base.options.target.cpu.arch) { + .x86_64 => 1, + .aarch64 => 2 * @sizeOf(u32), + else => unreachable, + }; + var buf: [@sizeOf(u32)]u8 = undefined; + for (self.extern_lazy_symbols.items()) |_, i| { + const placeholder_off = self.stub_helper_stubs_start_off.? + i * stub_size + off; + mem.writeIntLittle(u32, &buf, offsets.items[i]); + try self.base.file.?.pwriteAll(&buf, placeholder_off); + } +} + fn writeStringTable(self: *MachO) !void { if (!self.string_table_dirty) return; @@ -2979,8 +3048,6 @@ fn writeHeader(self: *MachO) !void { } /// Parse MachO contents from existing binary file. -/// TODO This method is incomplete and currently parses only the header -/// plus the load commands. fn parseFromFile(self: *MachO, file: fs.File) !void { self.base.file = file; var reader = file.reader(); |
