mirror of
https://github.com/ziglang/zig.git
synced 2026-01-10 01:15:14 +00:00
stage2 macho: add orr and orn instructions
This commit is contained in:
parent
10942e3f86
commit
c749b78df5
@ -2588,17 +2588,64 @@ 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.
|
||||
// Instead, we need to make use of PC-relative addressing.
|
||||
// if (reg.id() == 0) { // x0 is special-cased
|
||||
// TODO This needs to be optimised in the stack usage (perhaps use a shadow stack
|
||||
// like described here:
|
||||
// https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/using-the-stack-in-aarch64-implementing-push-and-pop)
|
||||
// TODO As far as branching is concerned, instead of saving the return address
|
||||
// in a register, I'm thinking here of immitating x86_64, and having the address
|
||||
// passed on the stack.
|
||||
if (reg.id() == 0) { // x0 is special-cased
|
||||
// str x28, [sp, #-16]
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x28, Register.sp, .{
|
||||
.offset = Instruction.Offset.imm_pre_index(-16),
|
||||
}).toU32());
|
||||
// adr x28, #8
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());
|
||||
try self.mod_fn.owner_decl.link.macho.addPieFixup(self.bin_file.allocator, .{
|
||||
.address = addr,
|
||||
.start = self.code.items.len,
|
||||
.len = 4,
|
||||
});
|
||||
// bl [label]
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32());
|
||||
// } else {
|
||||
// unreachable; // TODO
|
||||
// }
|
||||
// b [label]
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.b(0).toU32());
|
||||
// mov r, x0
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(reg, .x0, Instruction.RegisterShift.none()).toU32());
|
||||
// ldr x28, [sp], #16
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
|
||||
.rn = Register.sp,
|
||||
.offset = Instruction.Offset.imm_post_index(16),
|
||||
}).toU32());
|
||||
} else {
|
||||
// str x28, [sp, #-16]
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x28, Register.sp, .{
|
||||
.offset = Instruction.Offset.imm_pre_index(-16),
|
||||
}).toU32());
|
||||
// str x0, [sp, #-16]
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x0, Register.sp, .{
|
||||
.offset = Instruction.Offset.imm_pre_index(-16),
|
||||
}).toU32());
|
||||
// adr x28, #8
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());
|
||||
try self.mod_fn.owner_decl.link.macho.addPieFixup(self.bin_file.allocator, .{
|
||||
.address = addr,
|
||||
.start = self.code.items.len,
|
||||
.len = 4,
|
||||
});
|
||||
// b [label]
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.b(0).toU32());
|
||||
// mov r, x0
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(reg, .x0, Instruction.RegisterShift.none()).toU32());
|
||||
// ldr x0, [sp], #16
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x0, .{
|
||||
.rn = Register.sp,
|
||||
.offset = Instruction.Offset.imm_post_index(16),
|
||||
}).toU32());
|
||||
// ldr x28, [sp], #16
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
|
||||
.rn = Register.sp,
|
||||
.offset = Instruction.Offset.imm_post_index(16),
|
||||
}).toU32());
|
||||
}
|
||||
} else {
|
||||
// The value is in memory at a hard-coded address.
|
||||
// If the type is a pointer, it means the pointer address is at this memory location.
|
||||
|
||||
@ -19,6 +19,8 @@ pub const Register = enum(u6) {
|
||||
w16, w17, w18, w19, w20, w21, w22, w23,
|
||||
w24, w25, w26, w27, w28, w29, w30, wzr,
|
||||
|
||||
pub const sp = .xzr;
|
||||
|
||||
pub fn id(self: Register) u5 {
|
||||
return @truncate(u5, @enumToInt(self));
|
||||
}
|
||||
@ -195,6 +197,17 @@ test "FloatingPointRegister.toX" {
|
||||
|
||||
/// Represents an instruction in the AArch64 instruction set
|
||||
pub const Instruction = union(enum) {
|
||||
OrShiftedRegister: packed struct {
|
||||
rd: u5,
|
||||
rn: u5,
|
||||
imm6: u6,
|
||||
rm: u5,
|
||||
n: u1,
|
||||
shift: u2,
|
||||
fixed: u5 = 0b01010,
|
||||
opc: u2 = 0b01,
|
||||
sf: u1,
|
||||
},
|
||||
MoveWideImmediate: packed struct {
|
||||
rd: u5,
|
||||
imm16: u16,
|
||||
@ -251,6 +264,7 @@ pub const Instruction = union(enum) {
|
||||
|
||||
pub fn toU32(self: Instruction) u32 {
|
||||
return switch (self) {
|
||||
.OrShiftedRegister => |v| @bitCast(u32, v),
|
||||
.MoveWideImmediate => |v| @bitCast(u32, v),
|
||||
.PCRelativeAddress => |v| @bitCast(u32, v),
|
||||
.LoadStoreRegister => |v| @bitCast(u32, v),
|
||||
@ -379,8 +393,65 @@ pub const Instruction = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
pub const RegisterShift = struct {
|
||||
rn: u5,
|
||||
imm6: u6,
|
||||
shift: enum(u2) {
|
||||
Lsl = 0,
|
||||
Lsr = 1,
|
||||
Asr = 2,
|
||||
Ror = 3,
|
||||
},
|
||||
|
||||
pub fn none() RegisterShift {
|
||||
return .{
|
||||
.rn = 0b11111,
|
||||
.imm6 = 0,
|
||||
.shift = .Lsl,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Helper functions for assembly syntax functions
|
||||
|
||||
fn orShiftedRegister(
|
||||
rd: Register,
|
||||
rm: Register,
|
||||
shift: RegisterShift,
|
||||
invert: bool,
|
||||
) Instruction {
|
||||
const n: u1 = if (invert) 1 else 0;
|
||||
switch (rd.size()) {
|
||||
32 => {
|
||||
return Instruction{
|
||||
.OrShiftedRegister = .{
|
||||
.rd = rd.id(),
|
||||
.rn = shift.rn,
|
||||
.imm6 = shift.imm6,
|
||||
.rm = rm.id(),
|
||||
.n = n,
|
||||
.shift = @enumToInt(shift.shift),
|
||||
.sf = 0,
|
||||
},
|
||||
};
|
||||
},
|
||||
64 => {
|
||||
return Instruction{
|
||||
.OrShiftedRegister = .{
|
||||
.rd = rd.id(),
|
||||
.rn = shift.rn,
|
||||
.imm6 = shift.imm6,
|
||||
.rm = rm.id(),
|
||||
.n = n,
|
||||
.shift = @enumToInt(shift.shift),
|
||||
.sf = 1,
|
||||
},
|
||||
};
|
||||
},
|
||||
else => unreachable, // unexpected register size
|
||||
}
|
||||
}
|
||||
|
||||
fn moveWideImmediate(
|
||||
opc: u2,
|
||||
rd: Register,
|
||||
@ -543,6 +614,16 @@ pub const Instruction = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
// Bitwise (inclusive) OR of a register value
|
||||
|
||||
pub fn orr(rd: Register, rm: Register, shift: RegisterShift) Instruction {
|
||||
return orShiftedRegister(rd, rm, shift, false);
|
||||
}
|
||||
|
||||
pub fn orn(rd: Register, rm: Register, shift: RegisterShift) Instruction {
|
||||
return orShiftedRegister(rd, rm, shift, true);
|
||||
}
|
||||
|
||||
// Move wide (immediate)
|
||||
|
||||
pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction {
|
||||
@ -653,6 +734,14 @@ test "serialize instructions" {
|
||||
};
|
||||
|
||||
const testcases = [_]Testcase{
|
||||
.{ // orr x0 x1
|
||||
.inst = Instruction.orr(.x0, .x1, Instruction.RegisterShift.none()),
|
||||
.expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
|
||||
},
|
||||
.{ // orn x0 x1
|
||||
.inst = Instruction.orn(.x0, .x1, Instruction.RegisterShift.none()),
|
||||
.expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
|
||||
},
|
||||
.{ // movz x1 #4
|
||||
.inst = Instruction.movz(.x1, 4, 0),
|
||||
.expected = 0b1_10_100101_00_0000000000000100_00001,
|
||||
|
||||
@ -1028,7 +1028,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
|
||||
} else {
|
||||
const displacement = @intCast(u27, target_addr - this_addr);
|
||||
var placeholder = code_buffer.items[fixup.start..][0..fixup.len];
|
||||
mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32());
|
||||
mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.b(@intCast(i28, displacement)).toU32());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1670,10 +1670,10 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
|
||||
} else {
|
||||
const pos_symbol_off = @intCast(u20, vmaddr - self.offset_table.items[index]);
|
||||
const symbol_off = @intCast(i21, pos_symbol_off) * -1;
|
||||
// adr .x0 [-disp]
|
||||
mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x1, symbol_off).toU32());
|
||||
// ret
|
||||
mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ret(null).toU32());
|
||||
// adr x0, #-disp
|
||||
mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x0, symbol_off).toU32());
|
||||
// ret x28
|
||||
mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ret(.x28).toU32());
|
||||
}
|
||||
log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });
|
||||
try self.base.file.?.pwriteAll(&code, off);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user