| ... | @@ -1643,61 +1643,64 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1643,61 +1643,64 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1643 | else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}), | 1643 | else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}), |
| 1644 | } | 1644 | } |
| 1645 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 1645 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 1646 | switch (arch) { | 1646 | for (info.args) |mc_arg, arg_i| { |
| 1647 | .x86_64 => { | 1647 | const arg = inst.args[arg_i]; |
| 1648 | for (info.args) |mc_arg, arg_i| { | 1648 | const arg_mcv = try self.resolveInst(inst.args[arg_i]); |
| 1649 | const arg = inst.args[arg_i]; | 1649 | // Here we do not use setRegOrMem even though the logic is similar, because |
| 1650 | const arg_mcv = try self.resolveInst(inst.args[arg_i]); | 1650 | // the function call will move the stack pointer, so the offsets are different. |
| 1651 | // Here we do not use setRegOrMem even though the logic is similar, because | 1651 | switch (mc_arg) { |
| 1652 | // the function call will move the stack pointer, so the offsets are different. | 1652 | .none => continue, |
| 1653 | switch (mc_arg) { | 1653 | .register => |reg| { |
| 1654 | .none => continue, | 1654 | try self.genSetReg(arg.src, reg, arg_mcv); |
| 1655 | .register => |reg| { | 1655 | // TODO interact with the register allocator to mark the instruction as moved. |
| 1656 | try self.genSetReg(arg.src, reg, arg_mcv); | 1656 | }, |
| 1657 | // TODO interact with the register allocator to mark the instruction as moved. | 1657 | .stack_offset => { |
| 1658 | }, | 1658 | // Here we need to emit instructions like this: |
| 1659 | .stack_offset => { | 1659 | // mov qword ptr [rsp + stack_offset], x |
| 1660 | // Here we need to emit instructions like this: | 1660 | return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); |
| 1661 | // mov qword ptr [rsp + stack_offset], x | 1661 | }, |
| 1662 | return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); | 1662 | .ptr_stack_offset => { |
| 1663 | }, | 1663 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| 1664 | .ptr_stack_offset => { | 1664 | }, |
| 1665 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 1665 | .ptr_embedded_in_code => { |
| 1666 | }, | 1666 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); |
| 1667 | .ptr_embedded_in_code => { | 1667 | }, |
| 1668 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); | 1668 | .undef => unreachable, |
| 1669 | }, | 1669 | .immediate => unreachable, |
| 1670 | .undef => unreachable, | 1670 | .unreach => unreachable, |
| 1671 | .immediate => unreachable, | 1671 | .dead => unreachable, |
| 1672 | .unreach => unreachable, | 1672 | .embedded_in_code => unreachable, |
| 1673 | .dead => unreachable, | 1673 | .memory => unreachable, |
| 1674 | .embedded_in_code => unreachable, | 1674 | .compare_flags_signed => unreachable, |
| 1675 | .memory => unreachable, | 1675 | .compare_flags_unsigned => unreachable, |
| 1676 | .compare_flags_signed => unreachable, | 1676 | } |
| 1677 | .compare_flags_unsigned => unreachable, | 1677 | } |
| 1678 | } | | |
| 1679 | } | | |
| 1680 | | 1678 | |
| 1681 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { | 1679 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { |
| 1682 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | 1680 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { |
| 1683 | const func = func_val.func; | 1681 | const func = func_val.func; |
| 1684 | const got = &macho_file.sections.items[macho_file.got_section_index.?]; | 1682 | const got = &macho_file.sections.items[macho_file.got_section_index.?]; |
| 1685 | const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64); | 1683 | const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64); |
| | 1684 | switch (arch) { |
| | 1685 | .x86_64 => { |
| 1686 | // Here, we store the got address in %rax, and then call %rax | 1686 | // Here, we store the got address in %rax, and then call %rax |
| 1687 | // movabsq [addr], %rax | 1687 | // movabsq [addr], %rax |
| 1688 | try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr }); | 1688 | try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr }); |
| 1689 | // callq *%rax | 1689 | // callq *%rax |
| 1690 | try self.code.ensureCapacity(self.code.items.len + 2); | 1690 | try self.code.ensureCapacity(self.code.items.len + 2); |
| 1691 | self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 }); | 1691 | self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 }); |
| 1692 | } else { | 1692 | }, |
| 1693 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | 1693 | .aarch64 => { |
| 1694 | } | 1694 | try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr }); |
| 1695 | } else { | 1695 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); |
| 1696 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | 1696 | }, |
| | 1697 | else => unreachable, // unsupported architecture on MachO |
| 1697 | } | 1698 | } |
| 1698 | }, | 1699 | } else { |
| 1699 | .aarch64 => return self.fail(inst.base.src, "TODO implement codegen for call when linking with MachO for aarch64 arch", .{}), | 1700 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); |
| 1700 | else => unreachable, | 1701 | } |
| | 1702 | } else { |
| | 1703 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); |
| 1701 | } | 1704 | } |
| 1702 | } else { | 1705 | } else { |
| 1703 | unreachable; | 1706 | unreachable; |