authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-06 01:13:25+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-13 23:53:46+01:00
logf44732c1b0d7516c4a8169f7381cbcf55e1ae460
tree380f49b549149f3d5033e1a2d9f2ec9a1e64fa12
parent51a13f8ea6f1596a3163ac656e0ddb1156d1399a

macho: populate stubs and stub_helper


2 files changed, 96 insertions(+), 6 deletions(-)

src/codegen.zig+20-2
......@@ -1859,8 +1859,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18591859 },
18601860 else => unreachable, // unsupported architecture on MachO
18611861 }
1862 } else if (func_value.castTag(.extern_fn)) |_| {
1863 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
1862 } else if (func_value.castTag(.extern_fn)) |func_payload| {
1863 const decl = func_payload.data;
1864 const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name});
1865 defer self.bin_file.allocator.free(decl_name);
1866 const name = try macho_file.makeString(decl_name);
1867 const symbol = macho_file.undef_symbols.items.len;
1868 try macho_file.undef_symbols.append(self.bin_file.allocator, .{
1869 .n_strx = name,
1870 .n_type = std.macho.N_UNDF | std.macho.N_EXT,
1871 .n_sect = 0,
1872 .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER,
1873 .n_value = 0,
1874 });
1875 try macho_file.stub_fixups.append(self.bin_file.allocator, .{
1876 .symbol = symbol,
1877 .start = self.code.items.len,
1878 .len = 4,
1879 });
1880 // We mark the space and fix it up later.
1881 writeInt(u32, try self.code.addManyAsArray(4), 0);
18641882 } else {
18651883 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
18661884 }
src/link/MachO.zig+76-4
......@@ -115,6 +115,7 @@ global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{},
115115offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
116116
117117dyld_stub_binder_index: ?u16 = null,
118next_stub_helper_off: ?u64 = null,
118119
119120/// Table of symbol names aka the string table.
120121string_table: std.ArrayListUnmanaged(u8) = .{},
......@@ -162,6 +163,14 @@ last_text_block: ?*TextBlock = null,
162163/// rather than sitting in the global scope.
163164pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{},
164165
166stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{},
167
168pub const StubFixup = struct {
169 symbol: usize,
170 start: usize,
171 len: usize,
172};
173
165174pub const PieFixup = struct {
166175 /// Target address we wanted to address in absolute terms.
167176 address: u64,
......@@ -1223,7 +1232,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12231232 }
12241233
12251234 // 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;
12271236 const got_section = text_segment.sections.items[self.got_section_index.?];
12281237 while (self.pie_fixups.popOrNull()) |fixup| {
12291238 const target_addr = fixup.address;
......@@ -1243,6 +1252,45 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12431252 }
12441253 }
12451254
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
12461294 const text_section = text_segment.sections.items[self.text_section_index.?];
12471295 const section_offset = symbol.n_value - text_section.addr;
12481296 const file_offset = text_section.offset + section_offset;
......@@ -1555,7 +1603,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15551603 .sectname = makeStaticString("__stubs"),
15561604 .segname = makeStaticString("__TEXT"),
15571605 .addr = text_segment.inner.vmaddr + off,
1558 .size = 0, // This will be populated later in tandem with .reserved2 field.
1606 .size = needed_size,
15591607 .offset = @intCast(u32, off),
15601608 .@"align" = alignment,
15611609 .reloff = 0,
......@@ -1582,7 +1630,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15821630 const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad);
15831631 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
15841632
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 });
15861634
15871635 try text_segment.addSection(self.base.allocator, .{
15881636 .sectname = makeStaticString("__stub_helper"),
......@@ -1987,6 +2035,30 @@ pub fn populateMissingMetadata(self: *MachO) !void {
19872035 .n_value = 0,
19882036 });
19892037 }
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 }
19902062}
19912063
19922064fn 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 {
21012173 return buf;
21022174}
21032175
2104fn makeString(self: *MachO, bytes: []const u8) !u32 {
2176pub fn makeString(self: *MachO, bytes: []const u8) !u32 {
21052177 try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1);
21062178 const result = @intCast(u32, self.string_table.items.len);
21072179 self.string_table.appendSliceAssumeCapacity(bytes);