• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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