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#include <openssl/arm_arch.h> 49 50.text 51 52// abi_test_trampoline loads callee-saved registers from |state|, calls |func| 53// with |argv|, then saves the callee-saved registers into |state|. It returns 54// the result of |func|. The |unwind| argument is unused. 55// uint64_t abi_test_trampoline(void (*func)(...), CallerState *state, 56// const uint64_t *argv, size_t argc, 57// uint64_t unwind); 58.type abi_test_trampoline, %function 59.globl abi_test_trampoline 60.align 4 61abi_test_trampoline: 62.Labi_test_trampoline_begin: 63 AARCH64_SIGN_LINK_REGISTER 64 // Stack layout (low to high addresses) 65 // x29,x30 (16 bytes) 66 // d8-d15 (64 bytes) 67 // x19-x28 (80 bytes) 68 // $state (8 bytes) 69 // padding (8 bytes) 70 stp x29, x30, [sp, #-176]! 71 mov x29, sp 72 73 // Saved callee-saved registers and |state|. 74 stp d8, d9, [sp, #16] 75 stp d10, d11, [sp, #32] 76 stp d12, d13, [sp, #48] 77 stp d14, d15, [sp, #64] 78 stp x19, x20, [sp, #80] 79 stp x21, x22, [sp, #96] 80 stp x23, x24, [sp, #112] 81 stp x25, x26, [sp, #128] 82 stp x27, x28, [sp, #144] 83 str $state, [sp, #160] 84 85 // Load registers from |state|, with the exception of x29. x29 is the 86 // frame pointer and also callee-saved, but AAPCS64 allows platforms to 87 // mandate that x29 always point to a frame. iOS64 does so, which means 88 // we cannot fill x29 with entropy without violating ABI rules 89 // ourselves. x29 is tested separately below. 90 ldp d8, d9, [$state], #16 91 ldp d10, d11, [$state], #16 92 ldp d12, d13, [$state], #16 93 ldp d14, d15, [$state], #16 94 ldp x19, x20, [$state], #16 95 ldp x21, x22, [$state], #16 96 ldp x23, x24, [$state], #16 97 ldp x25, x26, [$state], #16 98 ldp x27, x28, [$state], #16 99 100 // Move parameters into temporary registers. 101 mov x9, $func 102 mov x10, $argv 103 mov x11, $argc 104 105 // Load parameters into registers. 106 cbz x11, .Largs_done 107 ldr x0, [x10], #8 108 subs x11, x11, #1 109 b.eq .Largs_done 110 ldr x1, [x10], #8 111 subs x11, x11, #1 112 b.eq .Largs_done 113 ldr x2, [x10], #8 114 subs x11, x11, #1 115 b.eq .Largs_done 116 ldr x3, [x10], #8 117 subs x11, x11, #1 118 b.eq .Largs_done 119 ldr x4, [x10], #8 120 subs x11, x11, #1 121 b.eq .Largs_done 122 ldr x5, [x10], #8 123 subs x11, x11, #1 124 b.eq .Largs_done 125 ldr x6, [x10], #8 126 subs x11, x11, #1 127 b.eq .Largs_done 128 ldr x7, [x10], #8 129 130.Largs_done: 131 blr x9 132 133 // Reload |state| and store registers. 134 ldr $state, [sp, #160] 135 stp d8, d9, [$state], #16 136 stp d10, d11, [$state], #16 137 stp d12, d13, [$state], #16 138 stp d14, d15, [$state], #16 139 stp x19, x20, [$state], #16 140 stp x21, x22, [$state], #16 141 stp x23, x24, [$state], #16 142 stp x25, x26, [$state], #16 143 stp x27, x28, [$state], #16 144 145 // |func| is required to preserve x29, the frame pointer. We cannot load 146 // random values into x29 (see comment above), so compare it against the 147 // expected value and zero the field of |state| if corrupted. 148 mov x9, sp 149 cmp x29, x9 150 b.eq .Lx29_ok 151 str xzr, [$state] 152 153.Lx29_ok: 154 // Restore callee-saved registers. 155 ldp d8, d9, [sp, #16] 156 ldp d10, d11, [sp, #32] 157 ldp d12, d13, [sp, #48] 158 ldp d14, d15, [sp, #64] 159 ldp x19, x20, [sp, #80] 160 ldp x21, x22, [sp, #96] 161 ldp x23, x24, [sp, #112] 162 ldp x25, x26, [sp, #128] 163 ldp x27, x28, [sp, #144] 164 165 ldp x29, x30, [sp], #176 166 AARCH64_VALIDATE_LINK_REGISTER 167 ret 168.size abi_test_trampoline,.-abi_test_trampoline 169____ 170 171# abi_test_clobber_* zeros the corresponding register. These are used to test 172# the ABI-testing framework. 173foreach (0..29) { 174 # x18 is the platform register and off limits. 175 next if ($_ == 18); 176 $code .= <<____; 177.type abi_test_clobber_x$_, %function 178.globl abi_test_clobber_x$_ 179.align 4 180abi_test_clobber_x$_: 181 AARCH64_VALID_CALL_TARGET 182 mov x$_, xzr 183 ret 184.size abi_test_clobber_x$_,.-abi_test_clobber_x$_ 185____ 186} 187foreach (0..31) { 188 $code .= <<____; 189.type abi_test_clobber_d$_, %function 190.globl abi_test_clobber_d$_ 191.align 4 192abi_test_clobber_d$_: 193 AARCH64_VALID_CALL_TARGET 194 fmov d$_, xzr 195 ret 196.size abi_test_clobber_d$_,.-abi_test_clobber_d$_ 197____ 198} 199 200# abi_test_clobber_v*_upper clobbers only the upper half of v*. AAPCS64 only 201# requires the lower half (d*) be preserved. 202foreach (8..15) { 203 $code .= <<____; 204.type abi_test_clobber_v${_}_upper, %function 205.globl abi_test_clobber_v${_}_upper 206.align 4 207abi_test_clobber_v${_}_upper: 208 AARCH64_VALID_CALL_TARGET 209 fmov v${_}.d[1], xzr 210 ret 211.size abi_test_clobber_v${_}_upper,.-abi_test_clobber_v${_}_upper 212____ 213} 214 215print $code; 216close STDOUT or die "error closing STDOUT"; 217