diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2020-11-24 18:46:43 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2020-11-26 11:50:09 +0100 |
| commit | ef5132c508f89ed8392143f6e8d03e8a2f121ba9 (patch) | |
| tree | 350ef2bf4e2a78e2a4ba3c33c644c164d16e88c7 /src | |
| parent | 80b1041c21599f5d444373dd35eafe2dc68e3887 (diff) | |
| download | zig-ef5132c508f89ed8392143f6e8d03e8a2f121ba9.tar.gz zig-ef5132c508f89ed8392143f6e8d03e8a2f121ba9.zip | |
stage2 macho: first, rough draft at trampolining
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen.zig | 63 | ||||
| -rw-r--r-- | src/link/MachO.zig | 109 | ||||
| -rw-r--r-- | src/link/MachO/CodeSignature.zig | 2 |
3 files changed, 88 insertions, 86 deletions
diff --git a/src/codegen.zig b/src/codegen.zig index 6cef7d8d0a..85b039069a 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -2767,24 +2767,51 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { // For MachO, the binary, with the exception of object files, has to be a PIE. // Therefore, we cannot load an absolute address. assert(x > math.maxInt(u32)); // 32bit direct addressing is not supported by MachO. - // The plan here is to use RIP-relative addressing, but leaving the actual displacement - // information empty (0-padded) and fixing it up later in the linker. - try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{ - .address = x, - .start = self.code.items.len, - .len = 7, - }); - try self.code.ensureCapacity(self.code.items.len + 9); - // leaq %r, [rip + disp] - self.code.appendSliceAssumeCapacity(&[_]u8{ - 0x48, - 0x8d, - 0x05 | (@as(u8, reg.id() & 0b111) << 3), // R - 0x0, - 0x0, - 0x0, - 0x0, - }); + // The plan here is to use unconditional relative jump to GOT entry, where we store + // pre-calculated and stored effective address to load into the target register. + // We leave the actual displacement information empty (0-padded) and fixing it up + // later in the linker. + if (reg.id() == 0) { // %rax is special-cased + try self.code.ensureCapacity(self.code.items.len + 5); + try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{ + .address = x, + .start = self.code.items.len, + .len = 5, + }); + // call [label] + self.code.appendSliceAssumeCapacity(&[_]u8{ + 0xE8, + 0x0, + 0x0, + 0x0, + 0x0, + }); + } else { + try self.code.ensureCapacity(self.code.items.len + 10); + // push %rax + self.code.appendSliceAssumeCapacity(&[_]u8{0x50}); + try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{ + .address = x, + .start = self.code.items.len, + .len = 5, + }); + // call [label] + self.code.appendSliceAssumeCapacity(&[_]u8{ + 0xE8, + 0x0, + 0x0, + 0x0, + 0x0, + }); + // mov %r, %rax + self.code.appendSliceAssumeCapacity(&[_]u8{ + 0x48, + 0x89, + 0xC0 | @as(u8, reg.id()), + }); + // pop %rax + self.code.appendSliceAssumeCapacity(&[_]u8{0x58}); + } } else if (x <= math.maxInt(u32)) { // Moving from memory to a register is a variant of `8B /r`. // Since we're using 64-bit moves, we require a REX. diff --git a/src/link/MachO.zig b/src/link/MachO.zig index dc6acfca48..bb4813a9df 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -1020,8 +1020,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { const target_addr = rip.address; // const got_addr = got_section.addr + decl.link.macho.offset_table_index * @sizeOf(u64); const this_addr = symbol.n_value + rip.start; - std.debug.print("target_addr=0x{x},this_addr=0x{x}\n", .{target_addr, this_addr}); - const displacement = @intCast(u32, target_addr - this_addr + rip.len); + std.debug.print("target_addr=0x{x},this_addr=0x{x}\n", .{ target_addr, this_addr }); + const displacement = @intCast(u32, target_addr - this_addr - rip.len); std.debug.print("displacement=0x{x}\n", .{displacement}); var placeholder = code_buffer.items[rip.start + rip.len - @sizeOf(u32) ..][0..@sizeOf(u32)]; mem.writeIntSliceLittle(u32, placeholder, displacement); @@ -1201,7 +1201,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { .addr = text_segment.vmaddr + off, .size = file_size, .offset = off, - .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 1, // 2^2 for aarch64, 2^1 for x86_64 + .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, // 2^2 for aarch64, 2^0 for x86_64 .reloff = 0, .nreloc = 0, .flags = flags, @@ -1214,48 +1214,23 @@ pub fn populateMissingMetadata(self: *MachO) !void { text_segment.filesize = file_size + off; self.cmd_table_dirty = true; } - if (self.data_segment_cmd_index == null) { - self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); - const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; - const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; - const initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE; - try self.load_commands.append(self.base.allocator, .{ - .Segment = .{ - .cmd = macho.LC_SEGMENT_64, - .cmdsize = @sizeOf(macho.segment_command_64), - .segname = makeStaticString("__DATA"), - .vmaddr = text_segment.vmaddr + text_segment.vmsize, - .vmsize = 0, - .fileoff = text_segment.fileoff + text_segment.filesize, - .filesize = 0, - .maxprot = maxprot, - .initprot = initprot, - .nsects = 0, - .flags = 0, - }, - }); - self.cmd_table_dirty = true; - } if (self.got_section_index == null) { + const text_section = &self.sections.items[self.text_section_index.?]; self.got_section_index = @intCast(u16, self.sections.items.len); - const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; - data_segment.cmdsize += @sizeOf(macho.section_64); - data_segment.nsects += 1; const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; // TODO looking for free space should be done *within* a segment it belongs to - // const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); - const off = @intCast(u32, data_segment.fileoff); + const off = @intCast(u32, text_section.offset + text_section.size); log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); try self.sections.append(self.base.allocator, .{ - .sectname = makeStaticString("__got"), - .segname = makeStaticString("__DATA"), - .addr = data_segment.vmaddr, + .sectname = makeStaticString("__ziggot"), + .segname = makeStaticString("__TEXT"), + .addr = text_section.addr + text_section.size, .size = file_size, .offset = off, - .@"align" = 3, // 2^3 = 8 + .@"align" = if (self.base.options.target.cpu.arch == .aarch64) 2 else 0, .reloff = 0, .nreloc = 0, .flags = macho.S_REGULAR, @@ -1264,23 +1239,26 @@ pub fn populateMissingMetadata(self: *MachO) !void { .reserved3 = 0, }); - const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size); - data_segment.vmsize = segment_size; - data_segment.filesize = segment_size; + const added_size = mem.alignForwardGeneric(u64, file_size, self.page_size); + const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; + text_segment.vmsize += added_size; + text_segment.filesize += added_size; + text_segment.cmdsize += @sizeOf(macho.section_64); + text_segment.nsects += 1; self.cmd_table_dirty = true; } if (self.linkedit_segment_cmd_index == null) { self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); - const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; + const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; const initprot = macho.VM_PROT_READ; - const off = data_segment.fileoff + data_segment.filesize; + const off = text_segment.fileoff + text_segment.filesize; try self.load_commands.append(self.base.allocator, .{ .Segment = .{ .cmd = macho.LC_SEGMENT_64, .cmdsize = @sizeOf(macho.segment_command_64), .segname = makeStaticString("__LINKEDIT"), - .vmaddr = data_segment.vmaddr + data_segment.vmsize, + .vmaddr = text_segment.vmaddr + text_segment.vmsize, .vmsize = 0, .fileoff = off, .filesize = 0, @@ -1671,11 +1649,24 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u16) u64 { fn writeOffsetTableEntry(self: *MachO, index: usize) !void { const sect = &self.sections.items[self.got_section_index.?]; const endian = self.base.options.target.cpu.arch.endian(); - var buf: [@sizeOf(u64)]u8 = undefined; - mem.writeInt(u64, &buf, self.offset_table.items[index], endian); + const off = sect.offset + @sizeOf(u64) * index; + const vmaddr = sect.addr + @sizeOf(u64) * index; + const pos_symbol_off = @truncate(u31, vmaddr - self.offset_table.items[index] + 7); + const symbol_off = @intCast(i32, pos_symbol_off) * -1; + std.debug.print("vmaddr=0x{x},item=0x{x}\n", .{vmaddr, self.offset_table.items[index]}); + std.debug.print("posSymbolOff=0x{x},symbolOff=0x{x}\n", .{pos_symbol_off, @bitCast(u32, symbol_off)}); + + var code: [8]u8 = undefined; + // lea %rax, [rip - disp] + code[0] = 0x48; + code[1] = 0x8D; + code[2] = 0x5; + mem.writeInt(u32, code[3..7], @bitCast(u32, symbol_off), endian); + // ret + code[7] = 0xC3; log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off }); - try self.base.file.?.pwriteAll(&buf, off); + try self.base.file.?.pwriteAll(&code, off); } fn writeSymbolTable(self: *MachO) !void { @@ -1791,7 +1782,7 @@ fn writeExportTrie(self: *MachO) !void { if (export_size > buffer.items.len) { // Pad out to align(8). - try self.base.file.?.pwriteAll(&[_]u8{ 0 }, dyld_info.export_off + export_size); + try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.export_off + export_size); } try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off); @@ -1816,7 +1807,7 @@ fn writeStringTable(self: *MachO) !void { if (symtab.strsize > needed_size) { // Pad out to align(8); - try self.base.file.?.pwriteAll(&[_]u8{ 0 }, symtab.stroff + symtab.strsize); + try self.base.file.?.pwriteAll(&[_]u8{0}, symtab.stroff + symtab.strsize); } try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); @@ -1843,7 +1834,6 @@ fn writeCmdHeaders(self: *MachO) !void { last_cmd_offset += cmd.cmdsize(); } { - // write __text section header const off = if (self.text_segment_cmd_index) |text_segment_index| blk: { var i: usize = 0; var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64); @@ -1856,27 +1846,14 @@ fn writeCmdHeaders(self: *MachO) !void { // only one, noname segment to append this section header to. return error.TODOImplementWritingObjFiles; }; - const idx = self.text_section_index.?; + // write __text section header + const id1 = self.text_section_index.?; log.debug("writing text section header at 0x{x}\n", .{off}); - try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off); - } - { - // write __got section header - const off = if (self.data_segment_cmd_index) |data_segment_index| blk: { - var i: usize = 0; - var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64); - while (i < data_segment_index) : (i += 1) { - cmdsize += self.load_commands.items[i].cmdsize(); - } - break :blk cmdsize; - } else { - // If we've landed in here, we are building a MachO object file, so we have - // only one, noname segment to append this section header to. - return error.TODOImplementWritingObjFiles; - }; - const idx = self.got_section_index.?; - log.debug("writing got section header at 0x{x}\n", .{off}); - try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off); + try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[id1 .. id1 + 1]), off); + // write __ziggot section header + const id2 = self.got_section_index.?; + log.debug("writing got section header at 0x{x}\n", .{off + @sizeOf(macho.section_64)}); + try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[id2 .. id2 + 1]), off + @sizeOf(macho.section_64)); } } diff --git a/src/link/MachO/CodeSignature.zig b/src/link/MachO/CodeSignature.zig index a7097d4cc0..6262315eb8 100644 --- a/src/link/MachO/CodeSignature.zig +++ b/src/link/MachO/CodeSignature.zig @@ -67,8 +67,6 @@ pub fn init(alloc: *Allocator) CodeSignature { pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void { const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment; - const data_segment = bin_file.load_commands.items[bin_file.data_segment_cmd_index.?].Segment; - const linkedit_segment = bin_file.load_commands.items[bin_file.linkedit_segment_cmd_index.?].Segment; const code_sig_cmd = bin_file.load_commands.items[bin_file.code_signature_cmd_index.?].LinkeditData; const execSegBase: u64 = text_segment.fileoff; |
