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