Robert Sloan | 4c22c5f | 2019-03-01 15:53:37 -0800 | [diff] [blame] | 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 | |
| 30 | use strict; |
| 31 | |
| 32 | my $flavour = shift; |
| 33 | my $output = shift; |
| 34 | if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } |
| 35 | |
| 36 | $0 =~ m/(.*[\/\\])[^\/\\]+$/; |
| 37 | my $dir = $1; |
| 38 | my $xlate; |
| 39 | ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or |
| 40 | ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or |
| 41 | die "can't locate arm-xlate.pl"; |
| 42 | |
| 43 | open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\""; |
| 44 | *STDOUT = *OUT; |
| 45 | |
| 46 | my ($func, $state, $argv, $argc) = ("x0", "x1", "x2", "x3"); |
| 47 | my $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 |
| 59 | abi_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. |
| 169 | foreach (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 |
| 176 | abi_test_clobber_x$_: |
| 177 | mov x$_, xzr |
| 178 | ret |
| 179 | .size abi_test_clobber_x$_,.-abi_test_clobber_x$_ |
| 180 | ____ |
| 181 | } |
| 182 | foreach (0..31) { |
| 183 | $code .= <<____; |
| 184 | .type abi_test_clobber_d$_, %function |
| 185 | .globl abi_test_clobber_d$_ |
| 186 | .align 4 |
| 187 | abi_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. |
| 196 | foreach (8..15) { |
| 197 | $code .= <<____; |
| 198 | .type abi_test_clobber_v${_}_upper, %function |
| 199 | .globl abi_test_clobber_v${_}_upper |
| 200 | .align 4 |
| 201 | abi_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 | |
| 208 | print $code; |
Pete Bentley | 0c61efe | 2019-08-13 09:32:23 +0100 | [diff] [blame^] | 209 | close STDOUT or die "error closing STDOUT"; |