| ... | ... | @@ -115,6 +115,7 @@ global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 115 | 115 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 116 | 116 | |
| 117 | 117 | dyld_stub_binder_index: ?u16 = null, |
| 118 | next_stub_helper_off: ?u64 = null, |
| 118 | 119 | |
| 119 | 120 | /// Table of symbol names aka the string table. |
| 120 | 121 | string_table: std.ArrayListUnmanaged(u8) = .{}, |
| ... | ... | @@ -162,6 +163,14 @@ last_text_block: ?*TextBlock = null, |
| 162 | 163 | /// rather than sitting in the global scope. |
| 163 | 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 | 174 | pub const PieFixup = struct { |
| 166 | 175 | /// Target address we wanted to address in absolute terms. |
| 167 | 176 | address: u64, |
| ... | ... | @@ -1223,7 +1232,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1223 | 1232 | } |
| 1224 | 1233 | |
| 1225 | 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 | 1236 | const got_section = text_segment.sections.items[self.got_section_index.?]; |
| 1228 | 1237 | while (self.pie_fixups.popOrNull()) |fixup| { |
| 1229 | 1238 | const target_addr = fixup.address; |
| ... | ... | @@ -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 | 1294 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 1247 | 1295 | const section_offset = symbol.n_value - text_section.addr; |
| 1248 | 1296 | const file_offset = text_section.offset + section_offset; |
| ... | ... | @@ -1555,7 +1603,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1555 | 1603 | .sectname = makeStaticString("__stubs"), |
| 1556 | 1604 | .segname = makeStaticString("__TEXT"), |
| 1557 | 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 | 1607 | .offset = @intCast(u32, off), |
| 1560 | 1608 | .@"align" = alignment, |
| 1561 | 1609 | .reloff = 0, |
| ... | ... | @@ -1582,7 +1630,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1582 | 1630 | const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad); |
| 1583 | 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 | 1635 | try text_segment.addSection(self.base.allocator, .{ |
| 1588 | 1636 | .sectname = makeStaticString("__stub_helper"), |
| ... | ... | @@ -1987,6 +2035,30 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1987 | 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 | 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 | 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 | 2177 | try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1); |
| 2106 | 2178 | const result = @intCast(u32, self.string_table.items.len); |
| 2107 | 2179 | self.string_table.appendSliceAssumeCapacity(bytes); |