authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-24 18:46:43+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-26 11:50:09+01:00
logef5132c508f89ed8392143f6e8d03e8a2f121ba9
tree350ef2bf4e2a78e2a4ba3c33c644c164d16e88c7
parent80b1041c21599f5d444373dd35eafe2dc68e3887

stage2 macho: first, rough draft at trampolining


3 files changed, 88 insertions(+), 86 deletions(-)

src/codegen.zig+45-18
...@@ -2767,24 +2767,51 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2767,24 +2767,51 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2767 // For MachO, the binary, with the exception of object files, has to be a PIE.2767 // For MachO, the binary, with the exception of object files, has to be a PIE.
2768 // Therefore, we cannot load an absolute address.2768 // Therefore, we cannot load an absolute address.
2769 assert(x > math.maxInt(u32)); // 32bit direct addressing is not supported by MachO.2769 assert(x > math.maxInt(u32)); // 32bit direct addressing is not supported by MachO.
2770 // The plan here is to use RIP-relative addressing, but leaving the actual displacement2770 // The plan here is to use unconditional relative jump to GOT entry, where we store
2771 // information empty (0-padded) and fixing it up later in the linker.2771 // pre-calculated and stored effective address to load into the target register.
2772 try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{2772 // We leave the actual displacement information empty (0-padded) and fixing it up
2773 .address = x,2773 // later in the linker.
2774 .start = self.code.items.len,2774 if (reg.id() == 0) { // %rax is special-cased
2775 .len = 7,2775 try self.code.ensureCapacity(self.code.items.len + 5);
2776 });2776 try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{
2777 try self.code.ensureCapacity(self.code.items.len + 9);2777 .address = x,
2778 // leaq %r, [rip + disp]2778 .start = self.code.items.len,
2779 self.code.appendSliceAssumeCapacity(&[_]u8{2779 .len = 5,
2780 0x48,2780 });
2781 0x8d,2781 // call [label]
2782 0x05 | (@as(u8, reg.id() & 0b111) << 3), // R2782 self.code.appendSliceAssumeCapacity(&[_]u8{
2783 0x0,2783 0xE8,
2784 0x0,2784 0x0,
2785 0x0,2785 0x0,
2786 0x0,2786 0x0,
2787 });2787 0x0,
2788 });
2789 } else {
2790 try self.code.ensureCapacity(self.code.items.len + 10);
2791 // push %rax
2792 self.code.appendSliceAssumeCapacity(&[_]u8{0x50});
2793 try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{
2794 .address = x,
2795 .start = self.code.items.len,
2796 .len = 5,
2797 });
2798 // call [label]
2799 self.code.appendSliceAssumeCapacity(&[_]u8{
2800 0xE8,
2801 0x0,
2802 0x0,
2803 0x0,
2804 0x0,
2805 });
2806 // mov %r, %rax
2807 self.code.appendSliceAssumeCapacity(&[_]u8{
2808 0x48,
2809 0x89,
2810 0xC0 | @as(u8, reg.id()),
2811 });
2812 // pop %rax
2813 self.code.appendSliceAssumeCapacity(&[_]u8{0x58});
2814 }
2788 } else if (x <= math.maxInt(u32)) {2815 } else if (x <= math.maxInt(u32)) {
2789 // Moving from memory to a register is a variant of `8B /r`.2816 // Moving from memory to a register is a variant of `8B /r`.
2790 // Since we're using 64-bit moves, we require a REX.2817 // Since we're using 64-bit moves, we require a REX.
src/link/MachO.zig+43-66
...@@ -1020,8 +1020,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1020,8 +1020,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1020 const target_addr = rip.address;1020 const target_addr = rip.address;
1021 // const got_addr = got_section.addr + decl.link.macho.offset_table_index * @sizeOf(u64);1021 // const got_addr = got_section.addr + decl.link.macho.offset_table_index * @sizeOf(u64);
1022 const this_addr = symbol.n_value + rip.start;1022 const this_addr = symbol.n_value + rip.start;
1023 std.debug.print("target_addr=0x{x},this_addr=0x{x}\n", .{target_addr, this_addr});1023 std.debug.print("target_addr=0x{x},this_addr=0x{x}\n", .{ target_addr, this_addr });
1024 const displacement = @intCast(u32, target_addr - this_addr + rip.len);1024 const displacement = @intCast(u32, target_addr - this_addr - rip.len);
1025 std.debug.print("displacement=0x{x}\n", .{displacement});1025 std.debug.print("displacement=0x{x}\n", .{displacement});
1026 var placeholder = code_buffer.items[rip.start + rip.len - @sizeOf(u32) ..][0..@sizeOf(u32)];1026 var placeholder = code_buffer.items[rip.start + rip.len - @sizeOf(u32) ..][0..@sizeOf(u32)];
1027 mem.writeIntSliceLittle(u32, placeholder, displacement);1027 mem.writeIntSliceLittle(u32, placeholder, displacement);
...@@ -1201,7 +1201,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1201,7 +1201,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1201 .addr = text_segment.vmaddr + off,1201 .addr = text_segment.vmaddr + off,
1202 .size = file_size,1202 .size = file_size,
1203 .offset = off,1203 .offset = off,
1204 .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 1, // 2^2 for aarch64, 2^1 for x86_641204 .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, // 2^2 for aarch64, 2^0 for x86_64
1205 .reloff = 0,1205 .reloff = 0,
1206 .nreloc = 0,1206 .nreloc = 0,
1207 .flags = flags,1207 .flags = flags,
...@@ -1214,48 +1214,23 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1214,48 +1214,23 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1214 text_segment.filesize = file_size + off;1214 text_segment.filesize = file_size + off;
1215 self.cmd_table_dirty = true;1215 self.cmd_table_dirty = true;
1216 }1216 }
1217 if (self.data_segment_cmd_index == null) {
1218 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
1219 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1220 const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE;
1221 const initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE;
1222 try self.load_commands.append(self.base.allocator, .{
1223 .Segment = .{
1224 .cmd = macho.LC_SEGMENT_64,
1225 .cmdsize = @sizeOf(macho.segment_command_64),
1226 .segname = makeStaticString("__DATA"),
1227 .vmaddr = text_segment.vmaddr + text_segment.vmsize,
1228 .vmsize = 0,
1229 .fileoff = text_segment.fileoff + text_segment.filesize,
1230 .filesize = 0,
1231 .maxprot = maxprot,
1232 .initprot = initprot,
1233 .nsects = 0,
1234 .flags = 0,
1235 },
1236 });
1237 self.cmd_table_dirty = true;
1238 }
1239 if (self.got_section_index == null) {1217 if (self.got_section_index == null) {
1218 const text_section = &self.sections.items[self.text_section_index.?];
1240 self.got_section_index = @intCast(u16, self.sections.items.len);1219 self.got_section_index = @intCast(u16, self.sections.items.len);
1241 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1242 data_segment.cmdsize += @sizeOf(macho.section_64);
1243 data_segment.nsects += 1;
12441220
1245 const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint;1221 const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
1246 // TODO looking for free space should be done *within* a segment it belongs to1222 // TODO looking for free space should be done *within* a segment it belongs to
1247 // const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size));1223 const off = @intCast(u32, text_section.offset + text_section.size);
1248 const off = @intCast(u32, data_segment.fileoff);
12491224
1250 log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size });1225 log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
12511226
1252 try self.sections.append(self.base.allocator, .{1227 try self.sections.append(self.base.allocator, .{
1253 .sectname = makeStaticString("__got"),1228 .sectname = makeStaticString("__ziggot"),
1254 .segname = makeStaticString("__DATA"),1229 .segname = makeStaticString("__TEXT"),
1255 .addr = data_segment.vmaddr,1230 .addr = text_section.addr + text_section.size,
1256 .size = file_size,1231 .size = file_size,
1257 .offset = off,1232 .offset = off,
1258 .@"align" = 3, // 2^3 = 81233 .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0,
1259 .reloff = 0,1234 .reloff = 0,
1260 .nreloc = 0,1235 .nreloc = 0,
1261 .flags = macho.S_REGULAR,1236 .flags = macho.S_REGULAR,
...@@ -1264,23 +1239,26 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1264,23 +1239,26 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1264 .reserved3 = 0,1239 .reserved3 = 0,
1265 });1240 });
12661241
1267 const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size);1242 const added_size = mem.alignForwardGeneric(u64, file_size, self.page_size);
1268 data_segment.vmsize = segment_size;1243 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1269 data_segment.filesize = segment_size;1244 text_segment.vmsize += added_size;
1245 text_segment.filesize += added_size;
1246 text_segment.cmdsize += @sizeOf(macho.section_64);
1247 text_segment.nsects += 1;
1270 self.cmd_table_dirty = true;1248 self.cmd_table_dirty = true;
1271 }1249 }
1272 if (self.linkedit_segment_cmd_index == null) {1250 if (self.linkedit_segment_cmd_index == null) {
1273 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);1251 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
1274 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;1252 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1275 const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE;1253 const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE;
1276 const initprot = macho.VM_PROT_READ;1254 const initprot = macho.VM_PROT_READ;
1277 const off = data_segment.fileoff + data_segment.filesize;1255 const off = text_segment.fileoff + text_segment.filesize;
1278 try self.load_commands.append(self.base.allocator, .{1256 try self.load_commands.append(self.base.allocator, .{
1279 .Segment = .{1257 .Segment = .{
1280 .cmd = macho.LC_SEGMENT_64,1258 .cmd = macho.LC_SEGMENT_64,
1281 .cmdsize = @sizeOf(macho.segment_command_64),1259 .cmdsize = @sizeOf(macho.segment_command_64),
1282 .segname = makeStaticString("__LINKEDIT"),1260 .segname = makeStaticString("__LINKEDIT"),
1283 .vmaddr = data_segment.vmaddr + data_segment.vmsize,1261 .vmaddr = text_segment.vmaddr + text_segment.vmsize,
1284 .vmsize = 0,1262 .vmsize = 0,
1285 .fileoff = off,1263 .fileoff = off,
1286 .filesize = 0,1264 .filesize = 0,
...@@ -1671,11 +1649,24 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u16) u64 {...@@ -1671,11 +1649,24 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u16) u64 {
1671fn writeOffsetTableEntry(self: *MachO, index: usize) !void {1649fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1672 const sect = &self.sections.items[self.got_section_index.?];1650 const sect = &self.sections.items[self.got_section_index.?];
1673 const endian = self.base.options.target.cpu.arch.endian();1651 const endian = self.base.options.target.cpu.arch.endian();
1674 var buf: [@sizeOf(u64)]u8 = undefined;1652
1675 mem.writeInt(u64, &buf, self.offset_table.items[index], endian);
1676 const off = sect.offset + @sizeOf(u64) * index;1653 const off = sect.offset + @sizeOf(u64) * index;
1654 const vmaddr = sect.addr + @sizeOf(u64) * index;
1655 const pos_symbol_off = @truncate(u31, vmaddr - self.offset_table.items[index] + 7);
1656 const symbol_off = @intCast(i32, pos_symbol_off) * -1;
1657 std.debug.print("vmaddr=0x{x},item=0x{x}\n", .{vmaddr, self.offset_table.items[index]});
1658 std.debug.print("posSymbolOff=0x{x},symbolOff=0x{x}\n", .{pos_symbol_off, @bitCast(u32, symbol_off)});
1659
1660 var code: [8]u8 = undefined;
1661 // lea %rax, [rip - disp]
1662 code[0] = 0x48;
1663 code[1] = 0x8D;
1664 code[2] = 0x5;
1665 mem.writeInt(u32, code[3..7], @bitCast(u32, symbol_off), endian);
1666 // ret
1667 code[7] = 0xC3;
1677 log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });1668 log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });
1678 try self.base.file.?.pwriteAll(&buf, off);1669 try self.base.file.?.pwriteAll(&code, off);
1679}1670}
16801671
1681fn writeSymbolTable(self: *MachO) !void {1672fn writeSymbolTable(self: *MachO) !void {
...@@ -1791,7 +1782,7 @@ fn writeExportTrie(self: *MachO) !void {...@@ -1791,7 +1782,7 @@ fn writeExportTrie(self: *MachO) !void {
17911782
1792 if (export_size > buffer.items.len) {1783 if (export_size > buffer.items.len) {
1793 // Pad out to align(8).1784 // Pad out to align(8).
1794 try self.base.file.?.pwriteAll(&[_]u8{ 0 }, dyld_info.export_off + export_size);1785 try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.export_off + export_size);
1795 }1786 }
1796 try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off);1787 try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off);
17971788
...@@ -1816,7 +1807,7 @@ fn writeStringTable(self: *MachO) !void {...@@ -1816,7 +1807,7 @@ fn writeStringTable(self: *MachO) !void {
18161807
1817 if (symtab.strsize > needed_size) {1808 if (symtab.strsize > needed_size) {
1818 // Pad out to align(8);1809 // Pad out to align(8);
1819 try self.base.file.?.pwriteAll(&[_]u8{ 0 }, symtab.stroff + symtab.strsize);1810 try self.base.file.?.pwriteAll(&[_]u8{0}, symtab.stroff + symtab.strsize);
1820 }1811 }
1821 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);1812 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
18221813
...@@ -1843,7 +1834,6 @@ fn writeCmdHeaders(self: *MachO) !void {...@@ -1843,7 +1834,6 @@ fn writeCmdHeaders(self: *MachO) !void {
1843 last_cmd_offset += cmd.cmdsize();1834 last_cmd_offset += cmd.cmdsize();
1844 }1835 }
1845 {1836 {
1846 // write __text section header
1847 const off = if (self.text_segment_cmd_index) |text_segment_index| blk: {1837 const off = if (self.text_segment_cmd_index) |text_segment_index| blk: {
1848 var i: usize = 0;1838 var i: usize = 0;
1849 var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64);1839 var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64);
...@@ -1856,27 +1846,14 @@ fn writeCmdHeaders(self: *MachO) !void {...@@ -1856,27 +1846,14 @@ fn writeCmdHeaders(self: *MachO) !void {
1856 // only one, noname segment to append this section header to.1846 // only one, noname segment to append this section header to.
1857 return error.TODOImplementWritingObjFiles;1847 return error.TODOImplementWritingObjFiles;
1858 };1848 };
1859 const idx = self.text_section_index.?;1849 // write __text section header
1850 const id1 = self.text_section_index.?;
1860 log.debug("writing text section header at 0x{x}\n", .{off});1851 log.debug("writing text section header at 0x{x}\n", .{off});
1861 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off);1852 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[id1 .. id1 + 1]), off);
1862 }1853 // write __ziggot section header
1863 {1854 const id2 = self.got_section_index.?;
1864 // write __got section header1855 log.debug("writing got section header at 0x{x}\n", .{off + @sizeOf(macho.section_64)});
1865 const off = if (self.data_segment_cmd_index) |data_segment_index| blk: {1856 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[id2 .. id2 + 1]), off + @sizeOf(macho.section_64));
1866 var i: usize = 0;
1867 var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64);
1868 while (i < data_segment_index) : (i += 1) {
1869 cmdsize += self.load_commands.items[i].cmdsize();
1870 }
1871 break :blk cmdsize;
1872 } else {
1873 // If we've landed in here, we are building a MachO object file, so we have
1874 // only one, noname segment to append this section header to.
1875 return error.TODOImplementWritingObjFiles;
1876 };
1877 const idx = self.got_section_index.?;
1878 log.debug("writing got section header at 0x{x}\n", .{off});
1879 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off);
1880 }1857 }
1881}1858}
18821859
src/link/MachO/CodeSignature.zig-2
...@@ -67,8 +67,6 @@ pub fn init(alloc: *Allocator) CodeSignature {...@@ -67,8 +67,6 @@ pub fn init(alloc: *Allocator) CodeSignature {
6767
68pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void {68pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void {
69 const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment;69 const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment;
70 const data_segment = bin_file.load_commands.items[bin_file.data_segment_cmd_index.?].Segment;
71 const linkedit_segment = bin_file.load_commands.items[bin_file.linkedit_segment_cmd_index.?].Segment;
72 const code_sig_cmd = bin_file.load_commands.items[bin_file.code_signature_cmd_index.?].LinkeditData;70 const code_sig_cmd = bin_file.load_commands.items[bin_file.code_signature_cmd_index.?].LinkeditData;
7371
74 const execSegBase: u64 = text_segment.fileoff;72 const execSegBase: u64 = text_segment.fileoff;