#!/usr/bin/env perl # Copyright (c) 2018, Google Inc. # # 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;