|  | #!/usr/bin/env perl | 
|  | # Copyright 2019 The BoringSSL Authors | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | #     https://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  |  | 
|  | # This file defines helper functions for crypto/test/abi_test.h on 32-bit | 
|  | # ARM. See that header for details on how to use this. | 
|  | # | 
|  | # For convenience, this file is linked into libcrypto, where consuming builds | 
|  | # already support architecture-specific sources. The static linker should drop | 
|  | # this code in non-test binaries. This includes a shared library build of | 
|  | # libcrypto, provided --gc-sections (ELF), -dead_strip (iOS), or equivalent is | 
|  | # used. | 
|  | # | 
|  | # References: | 
|  | # | 
|  | # AAPCS: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf | 
|  | # iOS ARMv6: https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html | 
|  | # iOS ARMv7: https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html | 
|  | # Linux: http://sourcery.mentor.com/sgpp/lite/arm/portal/kbattach142/arm_gnu_linux_%20abi.pdf | 
|  |  | 
|  | use strict; | 
|  |  | 
|  | my $flavour = shift; | 
|  | my $output  = shift; | 
|  | if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } | 
|  |  | 
|  | $0 =~ m/(.*[\/\\])[^\/\\]+$/; | 
|  | my $dir = $1; | 
|  | my $xlate; | 
|  | ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or | 
|  | ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or | 
|  | die "can't locate arm-xlate.pl"; | 
|  |  | 
|  | open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\""; | 
|  | *STDOUT = *OUT; | 
|  |  | 
|  | my ($func, $state, $argv, $argc) = ("r0", "r1", "r2", "r3"); | 
|  | my $code = <<____; | 
|  | .syntax	unified | 
|  |  | 
|  | .arch	armv7-a | 
|  | .fpu	vfp | 
|  |  | 
|  | .text | 
|  |  | 
|  | @ abi_test_trampoline loads callee-saved registers from |state|, calls |func| | 
|  | @ with |argv|, then saves the callee-saved registers into |state|. It returns | 
|  | @ the result of |func|. The |unwind| argument is unused. | 
|  | @ uint32_t abi_test_trampoline(void (*func)(...), CallerState *state, | 
|  | @                              const uint32_t *argv, size_t argc, | 
|  | @                              int unwind); | 
|  | .type	abi_test_trampoline, %function | 
|  | .globl	abi_test_trampoline | 
|  | .align	4 | 
|  | abi_test_trampoline: | 
|  | @ Save parameters and all callee-saved registers. For convenience, we | 
|  | @ save r9 on iOS even though it's volatile. | 
|  | vstmdb	sp!, {d8-d15} | 
|  | stmdb	sp!, {r0-r11,lr} | 
|  |  | 
|  | @ Reserve stack space for six (10-4) stack parameters, plus an extra 4 | 
|  | @ bytes to keep it 8-byte-aligned (see AAPCS, section 5.3). | 
|  | sub     sp, sp, #28 | 
|  |  | 
|  | @ Every register in AAPCS is either non-volatile or a parameter (except | 
|  | @ r9 on iOS), so this code, by the actual call, loses all its scratch | 
|  | @ registers. First fill in stack parameters while there are registers | 
|  | @ to spare. | 
|  | cmp	$argc, #4 | 
|  | bls	.Lstack_args_done | 
|  | mov	r4, sp				@ r4 is the output pointer. | 
|  | add	r5, $argv, $argc, lsl #2	@ Set r5 to the end of argv. | 
|  | add	$argv, $argv, #16		@ Skip four arguments. | 
|  | .Lstack_args_loop: | 
|  | ldr	r6, [$argv], #4 | 
|  | cmp	$argv, r5 | 
|  | str	r6, [r4], #4 | 
|  | bne	.Lstack_args_loop | 
|  |  | 
|  | .Lstack_args_done: | 
|  | @ Load registers from |$state|. | 
|  | vldmia	$state!, {d8-d15} | 
|  | #if defined(__APPLE__) | 
|  | @ r9 is not volatile on iOS. | 
|  | ldmia	$state!, {r4-r8,r10-r11} | 
|  | #else | 
|  | ldmia	$state!, {r4-r11} | 
|  | #endif | 
|  |  | 
|  | @ Load register parameters. This uses up our remaining registers, so we | 
|  | @ repurpose lr as scratch space. | 
|  | ldr	$argc, [sp, #40]	@ Reload argc. | 
|  | ldr	lr, [sp, #36]		@ Load argv into lr. | 
|  | cmp	$argc, #3 | 
|  | bhi	.Larg_r3 | 
|  | beq	.Larg_r2 | 
|  | cmp	$argc, #1 | 
|  | bhi	.Larg_r1 | 
|  | beq	.Larg_r0 | 
|  | b	.Largs_done | 
|  |  | 
|  | .Larg_r3: | 
|  | ldr	r3, [lr, #12]	@ argv[3] | 
|  | .Larg_r2: | 
|  | ldr	r2, [lr, #8]	@ argv[2] | 
|  | .Larg_r1: | 
|  | ldr	r1, [lr, #4]	@ argv[1] | 
|  | .Larg_r0: | 
|  | ldr	r0, [lr]	@ argv[0] | 
|  | .Largs_done: | 
|  |  | 
|  | @ With every other register in use, load the function pointer into lr | 
|  | @ and call the function. | 
|  | ldr	lr, [sp, #28] | 
|  | blx	lr | 
|  |  | 
|  | @ r1-r3 are free for use again. The trampoline only supports | 
|  | @ single-return functions. Pass r4-r11 to the caller. | 
|  | ldr	$state, [sp, #32] | 
|  | vstmia	$state!, {d8-d15} | 
|  | #if defined(__APPLE__) | 
|  | @ r9 is not volatile on iOS. | 
|  | stmia	$state!, {r4-r8,r10-r11} | 
|  | #else | 
|  | stmia	$state!, {r4-r11} | 
|  | #endif | 
|  |  | 
|  | @ Unwind the stack and restore registers. | 
|  | add	sp, sp, #44		@ 44 = 28+16 | 
|  | ldmia	sp!, {r4-r11,lr}	@ Skip r0-r3 (see +16 above). | 
|  | vldmia	sp!, {d8-d15} | 
|  |  | 
|  | bx	lr | 
|  | .size	abi_test_trampoline,.-abi_test_trampoline | 
|  | ____ | 
|  |  | 
|  | # abi_test_clobber_* zeros the corresponding register. These are used to test | 
|  | # the ABI-testing framework. | 
|  | foreach (0..12) { | 
|  | # This loop skips r13 (sp), r14 (lr, implicitly clobbered by every call), and | 
|  | # r15 (pc). | 
|  | $code .= <<____; | 
|  | .type	abi_test_clobber_r$_, %function | 
|  | .globl	abi_test_clobber_r$_ | 
|  | .align	4 | 
|  | abi_test_clobber_r$_: | 
|  | mov	r$_, #0 | 
|  | bx	lr | 
|  | .size	abi_test_clobber_r$_,.-abi_test_clobber_r$_ | 
|  | ____ | 
|  | } | 
|  |  | 
|  | foreach (0..15) { | 
|  | my $lo = "s".(2*$_); | 
|  | my $hi = "s".(2*$_+1); | 
|  | $code .= <<____; | 
|  | .type	abi_test_clobber_d$_, %function | 
|  | .globl	abi_test_clobber_d$_ | 
|  | .align	4 | 
|  | abi_test_clobber_d$_: | 
|  | mov	r0, #0 | 
|  | vmov	$lo, r0 | 
|  | vmov	$hi, r0 | 
|  | bx	lr | 
|  | .size	abi_test_clobber_d$_,.-abi_test_clobber_d$_ | 
|  | ____ | 
|  | } | 
|  |  | 
|  | print $code; | 
|  | close STDOUT or die "error closing STDOUT: $!"; |