| ... | @@ -115,6 +115,7 @@ global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | ... | @@ -115,6 +115,7 @@ global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 115 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, | 115 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 116 | | 116 | |
| 117 | dyld_stub_binder_index: ?u16 = null, | 117 | dyld_stub_binder_index: ?u16 = null, |
| | 118 | next_stub_helper_off: ?u64 = null, |
| 118 | | 119 | |
| 119 | /// Table of symbol names aka the string table. | 120 | /// Table of symbol names aka the string table. |
| 120 | string_table: std.ArrayListUnmanaged(u8) = .{}, | 121 | string_table: std.ArrayListUnmanaged(u8) = .{}, |
| ... | @@ -162,6 +163,14 @@ last_text_block: ?*TextBlock = null, | ... | @@ -162,6 +163,14 @@ last_text_block: ?*TextBlock = null, |
| 162 | /// rather than sitting in the global scope. | 163 | /// rather than sitting in the global scope. |
| 163 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, | 164 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 164 | | 165 | |
| | 166 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, |
| | 167 | |
| | 168 | pub const StubFixup = struct { |
| | 169 | symbol: usize, |
| | 170 | start: usize, |
| | 171 | len: usize, |
| | 172 | }; |
| | 173 | |
| 165 | pub const PieFixup = struct { | 174 | pub const PieFixup = struct { |
| 166 | /// Target address we wanted to address in absolute terms. | 175 | /// Target address we wanted to address in absolute terms. |
| 167 | address: u64, | 176 | address: u64, |
| ... | @@ -1223,7 +1232,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1223,7 +1232,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1223 | } | 1232 | } |
| 1224 | | 1233 | |
| 1225 | // Perform PIE fixups (if any) | 1234 | // Perform PIE fixups (if any) |
| 1226 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1235 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1227 | const got_section = text_segment.sections.items[self.got_section_index.?]; | 1236 | const got_section = text_segment.sections.items[self.got_section_index.?]; |
| 1228 | while (self.pie_fixups.popOrNull()) |fixup| { | 1237 | while (self.pie_fixups.popOrNull()) |fixup| { |
| 1229 | const target_addr = fixup.address; | 1238 | const target_addr = fixup.address; |
| ... | @@ -1243,6 +1252,45 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1243,6 +1252,45 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1243 | } | 1252 | } |
| 1244 | } | 1253 | } |
| 1245 | | 1254 | |
| | 1255 | // Resolve stubs (if any) |
| | 1256 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; |
| | 1257 | const stub_h = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| | 1258 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 1259 | const la_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| | 1260 | while (self.stub_fixups.popOrNull()) |fixup| { |
| | 1261 | // TODO increment offset for stub writing |
| | 1262 | const stub_addr = stubs.addr; |
| | 1263 | const text_addr = symbol.n_value + fixup.start; |
| | 1264 | const displacement = @intCast(u32, stub_addr - text_addr); |
| | 1265 | var placeholder = code_buffer.items[fixup.start..][0..fixup.len]; |
| | 1266 | mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32()); |
| | 1267 | |
| | 1268 | const end = stub_h.addr + self.next_stub_helper_off.? - stub_h.offset; |
| | 1269 | var buf: [@sizeOf(u64)]u8 = undefined; |
| | 1270 | mem.writeIntLittle(u64, &buf, end); |
| | 1271 | try self.base.file.?.pwriteAll(&buf, la_ptr.offset); |
| | 1272 | |
| | 1273 | const displacement2 = la_ptr.addr - stubs.addr; |
| | 1274 | var ccode: [2 * @sizeOf(u32)]u8 = undefined; |
| | 1275 | mem.writeIntLittle(u32, ccode[0..4], aarch64.Instruction.ldr(.x16, .{ |
| | 1276 | .literal = @intCast(u19, displacement2 / 4), |
| | 1277 | }).toU32()); |
| | 1278 | mem.writeIntLittle(u32, ccode[4..8], aarch64.Instruction.br(.x16).toU32()); |
| | 1279 | try self.base.file.?.pwriteAll(&ccode, stubs.offset); |
| | 1280 | stubs.size = 2 * @sizeOf(u32); |
| | 1281 | stubs.reserved2 = 2 * @sizeOf(u32); |
| | 1282 | |
| | 1283 | const displacement3 = @intCast(i64, stub_h.addr) - @intCast(i64, end + 4); |
| | 1284 | var cccode: [3 * @sizeOf(u32)]u8 = undefined; |
| | 1285 | mem.writeIntLittle(u32, cccode[0..4], aarch64.Instruction.ldr(.w16, .{ |
| | 1286 | .literal = 0x2, |
| | 1287 | }).toU32()); |
| | 1288 | mem.writeIntLittle(u32, cccode[4..8], aarch64.Instruction.b(@intCast(i28, displacement3)).toU32()); |
| | 1289 | mem.writeIntLittle(u32, cccode[8..12], 0); |
| | 1290 | try self.base.file.?.pwriteAll(&cccode, self.next_stub_helper_off.?); |
| | 1291 | self.next_stub_helper_off = self.next_stub_helper_off.? + 3 * @sizeOf(u32); |
| | 1292 | } |
| | 1293 | |
| 1246 | const text_section = text_segment.sections.items[self.text_section_index.?]; | 1294 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 1247 | const section_offset = symbol.n_value - text_section.addr; | 1295 | const section_offset = symbol.n_value - text_section.addr; |
| 1248 | const file_offset = text_section.offset + section_offset; | 1296 | const file_offset = text_section.offset + section_offset; |
| ... | @@ -1555,7 +1603,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1555,7 +1603,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1555 | .sectname = makeStaticString("__stubs"), | 1603 | .sectname = makeStaticString("__stubs"), |
| 1556 | .segname = makeStaticString("__TEXT"), | 1604 | .segname = makeStaticString("__TEXT"), |
| 1557 | .addr = text_segment.inner.vmaddr + off, | 1605 | .addr = text_segment.inner.vmaddr + off, |
| 1558 | .size = 0, // This will be populated later in tandem with .reserved2 field. | 1606 | .size = needed_size, |
| 1559 | .offset = @intCast(u32, off), | 1607 | .offset = @intCast(u32, off), |
| 1560 | .@"align" = alignment, | 1608 | .@"align" = alignment, |
| 1561 | .reloff = 0, | 1609 | .reloff = 0, |
| ... | @@ -1582,7 +1630,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1582,7 +1630,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1582 | const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad); | 1630 | const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad); |
| 1583 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. | 1631 | assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. |
| 1584 | | 1632 | |
| 1585 | log.debug("found __stubs section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); | 1633 | log.debug("found __stub_helper section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 1586 | | 1634 | |
| 1587 | try text_segment.addSection(self.base.allocator, .{ | 1635 | try text_segment.addSection(self.base.allocator, .{ |
| 1588 | .sectname = makeStaticString("__stub_helper"), | 1636 | .sectname = makeStaticString("__stub_helper"), |
| ... | @@ -1987,6 +2035,30 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1987,6 +2035,30 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1987 | .n_value = 0, | 2035 | .n_value = 0, |
| 1988 | }); | 2036 | }); |
| 1989 | } | 2037 | } |
| | 2038 | if (self.next_stub_helper_off == null) { |
| | 2039 | const text = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| | 2040 | const sh = &text.sections.items[self.stub_helper_section_index.?]; |
| | 2041 | const data = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 2042 | const data_data = &data.sections.items[self.data_section_index.?]; |
| | 2043 | const displacement = data_data.addr - sh.addr; |
| | 2044 | var code: [4 * @sizeOf(u32)]u8 = undefined; |
| | 2045 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, @intCast(i21, displacement)).toU32()); |
| | 2046 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.stp( |
| | 2047 | .x16, |
| | 2048 | .x17, |
| | 2049 | aarch64.Register.sp, |
| | 2050 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), |
| | 2051 | ).toU32()); |
| | 2052 | const dc = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| | 2053 | const got = &dc.sections.items[self.data_got_section_index.?]; |
| | 2054 | const displacement2 = got.addr - sh.addr - 2 * @sizeOf(u32); |
| | 2055 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.ldr(.x16, .{ |
| | 2056 | .literal = @intCast(u19, displacement2 / 4), |
| | 2057 | }).toU32()); |
| | 2058 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.br(.x16).toU32()); |
| | 2059 | self.next_stub_helper_off = sh.offset + 4 * @sizeOf(u32); |
| | 2060 | try self.base.file.?.pwriteAll(&code, sh.offset); |
| | 2061 | } |
| 1990 | } | 2062 | } |
| 1991 | | 2063 | |
| 1992 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 2064 | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| ... | @@ -2101,7 +2173,7 @@ pub fn makeStaticString(comptime bytes: []const u8) [16]u8 { | ... | @@ -2101,7 +2173,7 @@ pub fn makeStaticString(comptime bytes: []const u8) [16]u8 { |
| 2101 | return buf; | 2173 | return buf; |
| 2102 | } | 2174 | } |
| 2103 | | 2175 | |
| 2104 | fn makeString(self: *MachO, bytes: []const u8) !u32 { | 2176 | pub fn makeString(self: *MachO, bytes: []const u8) !u32 { |
| 2105 | try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1); | 2177 | try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1); |
| 2106 | const result = @intCast(u32, self.string_table.items.len); | 2178 | const result = @intCast(u32, self.string_table.items.len); |
| 2107 | self.string_table.appendSliceAssumeCapacity(bytes); | 2179 | self.string_table.appendSliceAssumeCapacity(bytes); |