1#!/usr/bin/env perl 2# Copyright (c) 2019, Google Inc. 3# 4# Permission to use, copy, modify, and/or distribute this software for any 5# purpose with or without fee is hereby granted, provided that the above 6# copyright notice and this permission notice appear in all copies. 7# 8# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 16# This file defines helper functions for crypto/test/abi_test.h on aarch64. See 17# that header for details on how to use this. 18# 19# For convenience, this file is linked into libcrypto, where consuming builds 20# already support architecture-specific sources. The static linker should drop 21# this code in non-test binaries. This includes a shared library build of 22# libcrypto, provided --gc-sections (ELF), -dead_strip (iOS), or equivalent is 23# used. 24# 25# References: 26# 27# AAPCS64: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf 28# iOS ARM64: https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html 29 30use strict; 31 32my $flavour = shift; 33my $output = shift; 34if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } 35 36$0 =~ m/(.*[\/\\])[^\/\\]+$/; 37my $dir = $1; 38my $xlate; 39( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or 40( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or 41die "can't locate arm-xlate.pl"; 42 43open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\""; 44*STDOUT = *OUT; 45 46my ($func, $state, $argv, $argc) = ("x0", "x1", "x2", "x3"); 47my $code = <<____; 48.text 49 50// abi_test_trampoline loads callee-saved registers from |state|, calls |func| 51// with |argv|, then saves the callee-saved registers into |state|. It returns 52// the result of |func|. The |unwind| argument is unused. 53// uint64_t abi_test_trampoline(void (*func)(...), CallerState *state, 54// const uint64_t *argv, size_t argc, 55// uint64_t unwind); 56.type abi_test_trampoline, %function 57.globl abi_test_trampoline 58.align 4 59abi_test_trampoline: 60.Labi_test_trampoline_begin: 61 // Stack layout (low to high addresses) 62 // x29,x30 (16 bytes) 63 // d8-d15 (64 bytes) 64 // x19-x28 (80 bytes) 65 // $state (8 bytes) 66 // padding (8 bytes) 67 stp x29, x30, [sp, #-176]! 68 mov x29, sp 69 70 // Saved callee-saved registers and |state|. 71 stp d8, d9, [sp, #16] 72 stp d10, d11, [sp, #32] 73 stp d12, d13, [sp, #48] 74 stp d14, d15, [sp, #64] 75 stp x19, x20, [sp, #80] 76 stp x21, x22, [sp, #96] 77 stp x23, x24, [sp, #112] 78 stp x25, x26, [sp, #128] 79 stp x27, x28, [sp, #144] 80 str $state, [sp, #160] 81 82 // Load registers from |state|, with the exception of x29. x29 is the 83 // frame pointer and also callee-saved, but AAPCS64 allows platforms to 84 // mandate that x29 always point to a frame. iOS64 does so, which means 85 // we cannot fill x29 with entropy without violating ABI rules 86 // ourselves. x29 is tested separately below. 87 ldp d8, d9, [$state], #16 88 ldp d10, d11, [$state], #16 89 ldp d12, d13, [$state], #16 90 ldp d14, d15, [$state], #16 91 ldp x19, x20, [$state], #16 92 ldp x21, x22, [$state], #16 93 ldp x23, x24, [$state], #16 94 ldp x25, x26, [$state], #16 95 ldp x27, x28, [$state], #16 96 97 // Move parameters into temporary registers. 98 mov x9, $func 99 mov x10, $argv 100 mov x11, $argc 101 102 // Load parameters into registers. 103 cbz x11, .Largs_done 104 ldr x0, [x10], #8 105 subs x11, x11, #1 106 b.eq .Largs_done 107 ldr x1, [x10], #8 108 subs x11, x11, #1 109 b.eq .Largs_done 110 ldr x2, [x10], #8 111 subs x11, x11, #1 112 b.eq .Largs_done 113 ldr x3, [x10], #8 114 subs x11, x11, #1 115 b.eq .Largs_done 116 ldr x4, [x10], #8 117 subs x11, x11, #1 118 b.eq .Largs_done 119 ldr x5, [x10], #8 120 subs x11, x11, #1 121 b.eq .Largs_done 122 ldr x6, [x10], #8 123 subs x11, x11, #1 124 b.eq .Largs_done 125 ldr x7, [x10], #8 126 127.Largs_done: 128 blr x9 129 130 // Reload |state| and store registers. 131 ldr $state, [sp, #160] 132 stp d8, d9, [$state], #16 133 stp d10, d11, [$state], #16 134 stp d12, d13, [$state], #16 135 stp d14, d15, [$state], #16 136 stp x19, x20, [$state], #16 137 stp x21, x22, [$state], #16 138 stp x23, x24, [$state], #16 139 stp x25, x26, [$state], #16 140 stp x27, x28, [$state], #16 141 142 // |func| is required to preserve x29, the frame pointer. We cannot load 143 // random values into x29 (see comment above), so compare it against the 144 // expected value and zero the field of |state| if corrupted. 145 mov x9, sp 146 cmp x29, x9 147 b.eq .Lx29_ok 148 str xzr, [$state] 149 150.Lx29_ok: 151 // Restore callee-saved registers. 152 ldp d8, d9, [sp, #16] 153 ldp d10, d11, [sp, #32] 154 ldp d12, d13, [sp, #48] 155 ldp d14, d15, [sp, #64] 156 ldp x19, x20, [sp, #80] 157 ldp x21, x22, [sp, #96] 158 ldp x23, x24, [sp, #112] 159 ldp x25, x26, [sp, #128] 160 ldp x27, x28, [sp, #144] 161 162 ldp x29, x30, [sp], #176 163 ret 164.size abi_test_trampoline,.-abi_test_trampoline 165____ 166 167# abi_test_clobber_* zeros the corresponding register. These are used to test 168# the ABI-testing framework. 169foreach (0..29) { 170 # x18 is the platform register and off limits. 171 next if ($_ == 18); 172 $code .= <<____; 173.type abi_test_clobber_x$_, %function 174.globl abi_test_clobber_x$_ 175.align 4 176abi_test_clobber_x$_: 177 mov x$_, xzr 178 ret 179.size abi_test_clobber_x$_,.-abi_test_clobber_x$_ 180____ 181} 182foreach (0..31) { 183 $code .= <<____; 184.type abi_test_clobber_d$_, %function 185.globl abi_test_clobber_d$_ 186.align 4 187abi_test_clobber_d$_: 188 fmov d$_, xzr 189 ret 190.size abi_test_clobber_d$_,.-abi_test_clobber_d$_ 191____ 192} 193 194# abi_test_clobber_v*_upper clobbers only the upper half of v*. AAPCS64 only 195# requires the lower half (d*) be preserved. 196foreach (8..15) { 197 $code .= <<____; 198.type abi_test_clobber_v${_}_upper, %function 199.globl abi_test_clobber_v${_}_upper 200.align 4 201abi_test_clobber_v${_}_upper: 202 fmov v${_}.d[1], xzr 203 ret 204.size abi_test_clobber_v${_}_upper,.-abi_test_clobber_v${_}_upper 205____ 206} 207 208print $code; 209close STDOUT; 210