| #!/usr/bin/env perl | 
 | # Copyright 2018 The BoringSSL Authors | 
 | # | 
 | # Permission to use, copy, modify, and/or distribute this software for any | 
 | # purpose with or without fee is hereby granted, provided that the above | 
 | # copyright notice and this permission notice appear in all copies. | 
 | # | 
 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 
 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | 
 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | 
 | # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | 
 | # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
 |  | 
 | # This file defines helper functions for crypto/test/abi_test.h on x86. 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 (Mac), or equivalent is | 
 | # used. | 
 | # | 
 | # References: | 
 | # | 
 | # SysV ABI: https://uclibc.org/docs/psABI-i386.pdf | 
 | # Win32 ABI: https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions?view=vs-2017 | 
 |  | 
 | use strict; | 
 |  | 
 | $0 =~ m/(.*[\/\\])[^\/\\]+$/; | 
 | my $dir = $1; | 
 | push(@INC, "${dir}", "${dir}../../perlasm"); | 
 | require "x86asm.pl"; | 
 |  | 
 | my $output = pop; | 
 | open STDOUT, ">$output"; | 
 |  | 
 | &asm_init($ARGV[0]); | 
 |  | 
 | # 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|. |unwind| is ignored. | 
 | # uint32_t abi_test_trampoline(void (*func)(...), CallerState *state, | 
 | #                              const uint32_t *argv, size_t argc, | 
 | #                              int unwind); | 
 | &function_begin("abi_test_trampoline") | 
 | 	# Load registers from |state|. Note |function_begin| (as opposed to | 
 | 	# |function_begin_B|) automatically saves all callee-saved registers, so we | 
 | 	# may freely clobber them. | 
 | 	&mov("ecx", &wparam(1)); | 
 | 	&mov("esi", &DWP(4*0, "ecx")); | 
 | 	&mov("edi", &DWP(4*1, "ecx")); | 
 | 	&mov("ebx", &DWP(4*2, "ecx")); | 
 | 	&mov("ebp", &DWP(4*3, "ecx")); | 
 |  | 
 | 	# Use a fixed stack allocation so |wparam| continues to work. abi_test.h | 
 | 	# supports at most 10 arguments. The SysV ABI requires a 16-byte-aligned | 
 | 	# stack on process entry, so round up to 3 (mod 4). | 
 | 	&stack_push(11); | 
 |  | 
 | 	# Copy parameters to stack. | 
 | 	&mov("eax", &wparam(2)); | 
 | 	&xor("ecx", "ecx"); | 
 | &set_label("loop"); | 
 | 	&cmp("ecx", &wparam(3)); | 
 | 	&jae(&label("loop_done")); | 
 | 	&mov("edx", &DWP(0, "eax", "ecx", 4)); | 
 | 	&mov(&DWP(0, "esp", "ecx", 4), "edx"); | 
 | 	&add("ecx", 1); | 
 | 	&jmp(&label("loop")); | 
 |  | 
 | &set_label("loop_done"); | 
 | 	&call_ptr(&wparam(0)); | 
 |  | 
 | 	&stack_pop(11); | 
 |  | 
 | 	# Save registers back into |state|. | 
 | 	&mov("ecx", &wparam(1)); | 
 | 	&mov(&DWP(4*0, "ecx"), "esi"); | 
 | 	&mov(&DWP(4*1, "ecx"), "edi"); | 
 | 	&mov(&DWP(4*2, "ecx"), "ebx"); | 
 | 	&mov(&DWP(4*3, "ecx"), "ebp"); | 
 | &function_end("abi_test_trampoline") | 
 |  | 
 | # abi_test_get_and_clear_direction_flag clears the direction flag. If the flag | 
 | # was previously set, it returns one. Otherwise, it returns zero. | 
 | # int abi_test_get_and_clear_direction_flag(void); | 
 | &function_begin_B("abi_test_get_and_clear_direction_flag"); | 
 | 	&pushf(); | 
 | 	&pop("eax"); | 
 | 	&and("eax", 0x400); | 
 | 	&shr("eax", 10); | 
 | 	&cld(); | 
 | 	&ret(); | 
 | &function_end_B("abi_test_get_and_clear_direction_flag"); | 
 |  | 
 | # abi_test_set_direction_flag sets the direction flag. | 
 | # void abi_test_set_direction_flag(void); | 
 | &function_begin_B("abi_test_set_direction_flag"); | 
 | 	&std(); | 
 | 	&ret(); | 
 | &function_end_B("abi_test_set_direction_flag"); | 
 |  | 
 | # abi_test_clobber_* zeros the corresponding register. These are used to test | 
 | # the ABI-testing framework. | 
 | foreach ("eax", "ebx", "ecx", "edx", "edi", "esi", "ebp") { | 
 | &function_begin_B("abi_test_clobber_$_"); | 
 | 	&xor($_, $_); | 
 | 	&ret(); | 
 | &function_end_B("abi_test_clobber_$_"); | 
 | } | 
 | foreach (0..7) { | 
 | &function_begin_B("abi_test_clobber_xmm$_"); | 
 | 	&pxor("xmm$_", "xmm$_"); | 
 | 	&ret(); | 
 | &function_end_B("abi_test_clobber_xmm$_"); | 
 | } | 
 |  | 
 | &asm_finish(); | 
 |  | 
 | close STDOUT or die "error closing STDOUT: $!"; |