aboutsummaryrefslogtreecommitdiff
path: root/src/link/aarch64.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2024-02-21 22:48:19 +0100
committerJakub Konka <kubkon@jakubkonka.com>2024-02-21 22:48:19 +0100
commit9fd112804fbdeb288b90cf8323d3ebefaa26372f (patch)
tree937d9c1192d8b3e67cefba78792756cd8bdbbbe2 /src/link/aarch64.zig
parent8ba31ed39a84ba00e85c456e74d0ea4d682d86c0 (diff)
downloadzig-9fd112804fbdeb288b90cf8323d3ebefaa26372f.tar.gz
zig-9fd112804fbdeb288b90cf8323d3ebefaa26372f.zip
link: commit missing files
Diffstat (limited to 'src/link/aarch64.zig')
-rw-r--r--src/link/aarch64.zig106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/link/aarch64.zig b/src/link/aarch64.zig
new file mode 100644
index 0000000000..a9295026d2
--- /dev/null
+++ b/src/link/aarch64.zig
@@ -0,0 +1,106 @@
+pub inline fn isArithmeticOp(inst: *const [4]u8) bool {
+ const group_decode = @as(u5, @truncate(inst[3]));
+ return ((group_decode >> 2) == 4);
+}
+
+pub const PageOffsetInstKind = enum {
+ arithmetic,
+ load_store_8,
+ load_store_16,
+ load_store_32,
+ load_store_64,
+ load_store_128,
+};
+
+pub fn classifyInst(code: *const [4]u8) PageOffsetInstKind {
+ if (isArithmeticOp(code)) return .arithmetic;
+ const inst = Instruction{
+ .load_store_register = mem.bytesToValue(std.meta.TagPayload(
+ Instruction,
+ Instruction.load_store_register,
+ ), code),
+ };
+ return switch (inst.load_store_register.size) {
+ 0 => if (inst.load_store_register.v == 1) .load_store_128 else .load_store_8,
+ 1 => .load_store_16,
+ 2 => .load_store_32,
+ 3 => .load_store_64,
+ };
+}
+
+pub fn calcPageOffset(kind: PageOffsetInstKind, taddr: u64) !u12 {
+ const narrowed = @as(u12, @truncate(taddr));
+ return switch (kind) {
+ .arithmetic, .load_store_8 => narrowed,
+ .load_store_16 => try math.divExact(u12, narrowed, 2),
+ .load_store_32 => try math.divExact(u12, narrowed, 4),
+ .load_store_64 => try math.divExact(u12, narrowed, 8),
+ .load_store_128 => try math.divExact(u12, narrowed, 16),
+ };
+}
+
+pub fn writePageOffset(kind: PageOffsetInstKind, taddr: u64, code: *[4]u8) !void {
+ const value = try calcPageOffset(kind, taddr);
+ switch (kind) {
+ .arithmetic => {
+ var inst = Instruction{
+ .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
+ Instruction,
+ Instruction.add_subtract_immediate,
+ ), code),
+ };
+ inst.add_subtract_immediate.imm12 = value;
+ mem.writeInt(u32, code, inst.toU32(), .little);
+ },
+ else => {
+ var inst: Instruction = .{
+ .load_store_register = mem.bytesToValue(std.meta.TagPayload(
+ Instruction,
+ Instruction.load_store_register,
+ ), code),
+ };
+ inst.load_store_register.offset = value;
+ mem.writeInt(u32, code, inst.toU32(), .little);
+ },
+ }
+}
+
+pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 {
+ const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow;
+ const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow;
+ const pages = math.cast(i21, tpage - spage) orelse return error.Overflow;
+ return pages;
+}
+
+pub fn writePages(pages: u21, code: *[4]u8) !void {
+ var inst = Instruction{
+ .pc_relative_address = mem.bytesToValue(std.meta.TagPayload(
+ Instruction,
+ Instruction.pc_relative_address,
+ ), code),
+ };
+ inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
+ inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
+ mem.writeInt(u32, code, inst.toU32(), .little);
+}
+
+pub fn writeBranchImm(disp: i28, code: *[4]u8) !void {
+ var inst = Instruction{
+ .unconditional_branch_immediate = mem.bytesToValue(std.meta.TagPayload(
+ Instruction,
+ Instruction.unconditional_branch_immediate,
+ ), code),
+ };
+ inst.unconditional_branch_immediate.imm26 = @as(u26, @truncate(@as(u28, @bitCast(disp >> 2))));
+ mem.writeInt(u32, code, inst.toU32(), .little);
+}
+
+const assert = std.debug.assert;
+const bits = @import("../arch/aarch64/bits.zig");
+const builtin = @import("builtin");
+const math = std.math;
+const mem = std.mem;
+const std = @import("std");
+
+pub const Instruction = bits.Instruction;
+pub const Register = bits.Register;