From b25cf7db0253f331f44b279fcbcdf71faa1afb92 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 17 Jan 2021 11:26:02 +0100 Subject: [PATCH] stage2 aarch64: add basic function pro/epilogue Fix typo in `nop` implementation. Simplify `aarch64` macOS tests. --- src/codegen.zig | 66 +++++++++++++++++++++++++- src/codegen/aarch64.zig | 2 +- test/stage2/aarch64.zig | 101 +++++++++------------------------------- 3 files changed, 88 insertions(+), 81 deletions(-) diff --git a/src/codegen.zig b/src/codegen.zig index e491178549..1478ede6ff 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -637,6 +637,67 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { try self.dbgSetEpilogueBegin(); } }, + .aarch64, .aarch64_be, .aarch64_32 => { + const cc = self.fn_type.fnCallingConvention(); + if (cc != .Naked) { + // TODO Finish function prologue and epilogue for aarch64. + // Reserve the stack for local variables, etc. + + // stp fp, lr, [sp, #-16]! + writeInt(u32, try self.code.addManyAsArray(4), Instruction.stp( + .x29, + .x30, + Register.sp, + Instruction.LoadStorePairOffset.pre_index(-16), + ).toU32()); + + try self.dbgSetPrologueEnd(); + + try self.genBody(self.mod_fn.body); + + try self.dbgSetEpilogueBegin(); + + // exitlude jumps + if (self.exitlude_jump_relocs.items.len == 1) { + // There is only one relocation. Hence, + // this relocation must be at the end of + // the code. Therefore, we can just delete + // the space initially reserved for the + // jump + self.code.items.len -= 4; + } else for (self.exitlude_jump_relocs.items) |jmp_reloc| { + const amt = @intCast(i32, self.code.items.len) - @intCast(i32, jmp_reloc + 8); + if (amt == -4) { + // This return is at the end of the + // code block. We can't just delete + // the space because there may be + // other jumps we already relocated to + // the address. Instead, insert a nop + writeInt(u32, self.code.items[jmp_reloc..][0..4], Instruction.nop().toU32()); + } else { + if (math.cast(i28, amt)) |offset| { + writeInt(u32, self.code.items[jmp_reloc..][0..4], Instruction.b(offset).toU32()); + } else |err| { + return self.failSymbol("exitlude jump is too large", .{}); + } + } + } + + // ldp fp, lr, [sp], #16 + writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldp( + .x29, + .x30, + Register.sp, + Instruction.LoadStorePairOffset.post_index(16), + ).toU32()); + // ret lr + writeInt(u32, try self.code.addManyAsArray(4), Instruction.ret(null).toU32()); + } else { + try self.dbgSetPrologueEnd(); + try self.genBody(self.mod_fn.body); + try self.dbgSetEpilogueBegin(); + } + }, else => { try self.dbgSetPrologueEnd(); try self.genBody(self.mod_fn.body); @@ -1962,8 +2023,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4); }, .aarch64 => { - // TODO: relocations - writeInt(u32, try self.code.addManyAsArray(4), Instruction.ret(null).toU32()); + // Just add space for an instruction, patch this later + try self.code.resize(self.code.items.len + 4); + try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4); }, else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}), } diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig index 5fba1ea7e1..5999f8888c 100644 --- a/src/codegen/aarch64.zig +++ b/src/codegen/aarch64.zig @@ -814,7 +814,7 @@ pub const Instruction = union(enum) { // Nop pub fn nop() Instruction { - return Instruction{ .NoOperation = {} }; + return Instruction{ .NoOperation = .{} }; } // Logical (shifted register) diff --git a/test/stage2/aarch64.zig b/test/stage2/aarch64.zig index fb2b240c4d..6c283f8e9f 100644 --- a/test/stage2/aarch64.zig +++ b/test/stage2/aarch64.zig @@ -17,97 +17,60 @@ pub fn addCases(ctx: *TestContext) !void { // Regular old hello world case.addCompareOutput( + \\extern "c" fn write(usize, usize, usize) void; + \\extern "c" fn exit(usize) noreturn; + \\ \\export fn _start() noreturn { \\ print(); \\ - \\ exit(); + \\ exit(0); \\} \\ \\fn print() void { - \\ asm volatile ("svc #0x80" - \\ : - \\ : [number] "{x16}" (4), - \\ [arg1] "{x0}" (1), - \\ [arg2] "{x1}" (@ptrToInt("Hello, World!\n")), - \\ [arg3] "{x2}" (14) - \\ : "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("svc #0x80" - \\ : - \\ : [number] "{x16}" (1), - \\ [arg1] "{x0}" (0) - \\ : "memory" - \\ ); - \\ unreachable; + \\ const msg = @ptrToInt("Hello, World!\n"); + \\ const len = 14; + \\ write(1, msg, len); \\} , "Hello, World!\n", ); + // Now change the message only case.addCompareOutput( + \\extern "c" fn write(usize, usize, usize) void; + \\extern "c" fn exit(usize) noreturn; + \\ \\export fn _start() noreturn { \\ print(); \\ - \\ exit(); + \\ exit(0); \\} \\ \\fn print() void { - \\ asm volatile ("svc #0x80" - \\ : - \\ : [number] "{x16}" (4), - \\ [arg1] "{x0}" (1), - \\ [arg2] "{x1}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), - \\ [arg3] "{x2}" (104) - \\ : "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("svc #0x80" - \\ : - \\ : [number] "{x16}" (1), - \\ [arg1] "{x0}" (0) - \\ : "memory" - \\ ); - \\ unreachable; + \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n"); + \\ const len = 104; + \\ write(1, msg, len); \\} , "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", ); + // Now we print it twice. case.addCompareOutput( + \\extern "c" fn write(usize, usize, usize) void; + \\extern "c" fn exit(usize) noreturn; + \\ \\export fn _start() noreturn { \\ print(); \\ print(); \\ - \\ exit(); + \\ exit(0); \\} \\ \\fn print() void { - \\ asm volatile ("svc #0x80" - \\ : - \\ : [number] "{x16}" (4), - \\ [arg1] "{x0}" (1), - \\ [arg2] "{x1}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), - \\ [arg3] "{x2}" (104) - \\ : "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("svc #0x80" - \\ : - \\ : [number] "{x16}" (1), - \\ [arg1] "{x0}" (0) - \\ : "memory" - \\ ); - \\ unreachable; + \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n"); + \\ const len = 104; + \\ write(1, msg, len); \\} , \\What is up? This is a longer message that will force the data to be relocated in virtual address space. @@ -200,24 +163,6 @@ pub fn addCases(ctx: *TestContext) !void { ); } - { - var case = ctx.exe("hello world linked to libc", macos_aarch64); - - // TODO rewrite this test once we handle more int conversions and return args. - case.addCompareOutput( - \\extern "c" fn write(usize, usize, usize) void; - \\extern "c" fn exit(usize) noreturn; - \\ - \\export fn _start() noreturn { - \\ write(1, @ptrToInt("Hello,"), 6); - \\ write(1, @ptrToInt(" World!\n,"), 8); - \\ exit(0); - \\} - , - "Hello, World!\n", - ); - } - { var case = ctx.exe("only libc exit", macos_aarch64);