chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,170 @@
#!/usr/bin/env perl
# Copyright (c) 2019, Google Inc.
#
# SPDX-License-Identifier: ISC
# 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;
$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: $!";

View File

@@ -0,0 +1,205 @@
#!/usr/bin/env perl
# Copyright (c) 2019, Google Inc.
#
# SPDX-License-Identifier: ISC
# This file defines helper functions for crypto/test/abi_test.h on aarch64. 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:
#
# AAPCS64: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
# iOS ARM64: https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html
use strict;
my $flavour = shift;
my $output = shift;
$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) = ("x0", "x1", "x2", "x3");
my $code = <<____;
#include <openssl/arm_arch.h>
.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.
// uint64_t abi_test_trampoline(void (*func)(...), CallerState *state,
// const uint64_t *argv, size_t argc,
// uint64_t unwind);
.type abi_test_trampoline, %function
.globl abi_test_trampoline
.align 4
abi_test_trampoline:
.Labi_test_trampoline_begin:
AARCH64_SIGN_LINK_REGISTER
// Stack layout (low to high addresses)
// x29,x30 (16 bytes)
// d8-d15 (64 bytes)
// x19-x28 (80 bytes)
// $state (8 bytes)
// padding (8 bytes)
stp x29, x30, [sp, #-176]!
mov x29, sp
// Saved callee-saved registers and |state|.
stp d8, d9, [sp, #16]
stp d10, d11, [sp, #32]
stp d12, d13, [sp, #48]
stp d14, d15, [sp, #64]
stp x19, x20, [sp, #80]
stp x21, x22, [sp, #96]
stp x23, x24, [sp, #112]
stp x25, x26, [sp, #128]
stp x27, x28, [sp, #144]
str $state, [sp, #160]
// Load registers from |state|, with the exception of x29. x29 is the
// frame pointer and also callee-saved, but AAPCS64 allows platforms to
// mandate that x29 always point to a frame. iOS64 does so, which means
// we cannot fill x29 with entropy without violating ABI rules
// ourselves. x29 is tested separately below.
ldp d8, d9, [$state], #16
ldp d10, d11, [$state], #16
ldp d12, d13, [$state], #16
ldp d14, d15, [$state], #16
ldp x19, x20, [$state], #16
ldp x21, x22, [$state], #16
ldp x23, x24, [$state], #16
ldp x25, x26, [$state], #16
ldp x27, x28, [$state], #16
// Move parameters into temporary registers.
mov x9, $func
mov x10, $argv
mov x11, $argc
// Load parameters into registers.
cbz x11, .Largs_done
ldr x0, [x10], #8
subs x11, x11, #1
b.eq .Largs_done
ldr x1, [x10], #8
subs x11, x11, #1
b.eq .Largs_done
ldr x2, [x10], #8
subs x11, x11, #1
b.eq .Largs_done
ldr x3, [x10], #8
subs x11, x11, #1
b.eq .Largs_done
ldr x4, [x10], #8
subs x11, x11, #1
b.eq .Largs_done
ldr x5, [x10], #8
subs x11, x11, #1
b.eq .Largs_done
ldr x6, [x10], #8
subs x11, x11, #1
b.eq .Largs_done
ldr x7, [x10], #8
.Largs_done:
blr x9
// Reload |state| and store registers.
ldr $state, [sp, #160]
stp d8, d9, [$state], #16
stp d10, d11, [$state], #16
stp d12, d13, [$state], #16
stp d14, d15, [$state], #16
stp x19, x20, [$state], #16
stp x21, x22, [$state], #16
stp x23, x24, [$state], #16
stp x25, x26, [$state], #16
stp x27, x28, [$state], #16
// |func| is required to preserve x29, the frame pointer. We cannot load
// random values into x29 (see comment above), so compare it against the
// expected value and zero the field of |state| if corrupted.
mov x9, sp
cmp x29, x9
b.eq .Lx29_ok
str xzr, [$state]
.Lx29_ok:
// Restore callee-saved registers.
ldp d8, d9, [sp, #16]
ldp d10, d11, [sp, #32]
ldp d12, d13, [sp, #48]
ldp d14, d15, [sp, #64]
ldp x19, x20, [sp, #80]
ldp x21, x22, [sp, #96]
ldp x23, x24, [sp, #112]
ldp x25, x26, [sp, #128]
ldp x27, x28, [sp, #144]
ldp x29, x30, [sp], #176
AARCH64_VALIDATE_LINK_REGISTER
ret
.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..29) {
# x18 is the platform register and off limits.
next if ($_ == 18);
$code .= <<____;
.type abi_test_clobber_x$_, %function
.globl abi_test_clobber_x$_
.align 4
abi_test_clobber_x$_:
AARCH64_VALID_CALL_TARGET
mov x$_, xzr
ret
.size abi_test_clobber_x$_,.-abi_test_clobber_x$_
____
}
foreach (0..31) {
$code .= <<____;
.type abi_test_clobber_d$_, %function
.globl abi_test_clobber_d$_
.align 4
abi_test_clobber_d$_:
AARCH64_VALID_CALL_TARGET
fmov d$_, xzr
ret
.size abi_test_clobber_d$_,.-abi_test_clobber_d$_
____
}
# abi_test_clobber_v*_upper clobbers only the upper half of v*. AAPCS64 only
# requires the lower half (d*) be preserved.
foreach (8..15) {
$code .= <<____;
.type abi_test_clobber_v${_}_upper, %function
.globl abi_test_clobber_v${_}_upper
.align 4
abi_test_clobber_v${_}_upper:
AARCH64_VALID_CALL_TARGET
fmov v${_}.d[1], xzr
ret
.size abi_test_clobber_v${_}_upper,.-abi_test_clobber_v${_}_upper
____
}
print $code;
close STDOUT or die "error closing STDOUT: $!";

View File

@@ -0,0 +1,251 @@
#!/usr/bin/env perl
# Copyright (c) 2019, Google Inc.
#
# SPDX-License-Identifier: ISC
# This file defines helper functions for crypto/test/abi_test.h on ppc64le. 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 or equivalent is used.
#
# References:
#
# ELFv2: http://openpowerfoundation.org/wp-content/uploads/resources/leabi/leabi-20170510.pdf
use strict;
my $flavour = shift;
my $output = shift;
$0 =~ m/(.*[\/\\])[^\/\\]+$/;
my $dir = $1;
my $xlate;
( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
die "can't locate ppc-xlate.pl";
open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT = *OUT;
unless ($flavour =~ /linux.*64le/) {
die "This file only supports the ELFv2 ABI, used by ppc64le";
}
my $code = "";
sub load_or_store_regs {
# $op is "l" or "st".
my ($op, $base_reg, $base_offset) = @_;
# Vector registers.
foreach (20..31) {
my $offset = $base_offset + ($_ - 20) * 16;
# Vector registers only support indexed register addressing.
$code .= "\tli\tr11, $offset\n";
$code .= "\t${op}vx\tv$_, r11, $base_reg\n";
}
# Save general registers.
foreach (14..31) {
my $offset = $base_offset + 192 + ($_ - 14) * 8;
$code .= "\t${op}d\tr$_, $offset($base_reg)\n";
}
# Save floating point registers.
foreach (14..31) {
my $offset = $base_offset + 336 + ($_ - 14) * 8;
$code .= "\t${op}fd\tf$_, $offset($base_reg)\n";
}
}
sub load_regs {
my ($base_reg, $base_offset) = @_;
load_or_store_regs("l", $base_reg, $base_offset);
}
sub store_regs {
my ($base_reg, $base_offset) = @_;
load_or_store_regs("st", $base_reg, $base_offset);
}
my ($func, $state, $argv, $argc) = ("r3", "r4", "r5", "r6");
$code .= <<____;
.machine "any"
.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.
# uint64_t abi_test_trampoline(void (*func)(...), CallerState *state,
# const uint64_t *argv, size_t argc,
# uint64_t unwind);
.globl abi_test_trampoline
.align 5
abi_test_trampoline:
# LR is saved into the caller's stack frame.
mflr r0
std r0, 16(r1)
# Allocate 66*8 = 528 bytes of stack frame. From the top of the stack
# to the bottom, the stack frame is:
#
# 0(r1) - Back chain pointer
# 8(r1) - CR save area
# 16(r1) - LR save area (for |func|)
# 24(r1) - TOC pointer save area
# 32(r1) - Saved copy of |state|
# 40(r1) - Padding
# 48(r1) - Vector register save area (v20-v31, 12 registers)
# 240(r1) - General register save area (r14-r31, 18 registers)
# 384(r1) - Floating point register save area (f14-f31, 18 registers)
#
# Note the layouts of the register save areas and CallerState match.
#
# In the ELFv2 ABI, the parameter save area is optional if the function
# is non-variadic and all parameters fit in registers. We only support
# such functions, so we omit it to test that |func| does not rely on it.
stdu r1, -528(r1)
mfcr r0
std r0, 8(r1) # Save CR
std r2, 24(r1) # Save TOC
std $state, 32(r1) # Save |state|
____
# Save registers to the stack.
store_regs("r1", 48);
# Load registers from the caller.
load_regs($state, 0);
$code .= <<____;
# Load CR from |state|.
ld r0, 480($state)
mtcr r0
# Move parameters into temporary registers so they are not clobbered.
addi r11, $argv, -8 # Adjust for ldu below
mr r12, $func
# Load parameters into registers.
cmpdi $argc, 0
beq .Largs_done
mtctr $argc
ldu r3, 8(r11)
bdz .Largs_done
ldu r4, 8(r11)
bdz .Largs_done
ldu r5, 8(r11)
bdz .Largs_done
ldu r6, 8(r11)
bdz .Largs_done
ldu r7, 8(r11)
bdz .Largs_done
ldu r8, 8(r11)
bdz .Largs_done
ldu r9, 8(r11)
bdz .Largs_done
ldu r10, 8(r11)
.Largs_done:
li r2, 0 # Clear TOC to test |func|'s global entry point
mtctr r12
bctrl
ld r2, 24(r1) # Restore TOC
ld $state, 32(r1) # Reload |state|
____
# Output resulting registers to the caller.
store_regs($state, 0);
# Restore registers from the stack.
load_regs("r1", 48);
$code .= <<____;
mfcr r0
std r0, 480($state) # Output CR to caller
ld r0, 8(r1)
mtcrf 0b00111000, r0 # Restore CR2-CR4
addi r1, r1, 528
ld r0, 16(r1) # Restore LR
mtlr r0
blr
.size abi_test_trampoline,.-abi_test_trampoline
____
# abi_test_clobber_* clobbers the corresponding register. These are used to test
# the ABI-testing framework.
foreach (0..31) {
# r1 is the stack pointer. r13 is the thread pointer.
next if ($_ == 1 || $_ == 13);
$code .= <<____;
.globl abi_test_clobber_r$_
.align 5
abi_test_clobber_r$_:
li r$_, 0
blr
.size abi_test_clobber_r$_,.-abi_test_clobber_r$_
____
}
foreach (0..31) {
$code .= <<____;
.globl abi_test_clobber_f$_
.align 4
abi_test_clobber_f$_:
li r0, 0
# Use the red zone.
std r0, -8(r1)
lfd f$_, -8(r1)
blr
.size abi_test_clobber_f$_,.-abi_test_clobber_f$_
____
}
foreach (0..31) {
$code .= <<____;
.globl abi_test_clobber_v$_
.align 4
abi_test_clobber_v$_:
vxor v$_, v$_, v$_
blr
.size abi_test_clobber_v$_,.-abi_test_clobber_v$_
____
}
foreach (0..7) {
# PPC orders CR fields in big-endian, so the mask is reversed from what one
# would expect.
my $mask = 1 << (7 - $_);
$code .= <<____;
.globl abi_test_clobber_cr$_
.align 4
abi_test_clobber_cr$_:
# Flip the bits on cr$_ rather than setting to zero. With a four-bit
# register, zeroing it will do nothing 1 in 16 times.
mfcr r0
not r0, r0
mtcrf $mask, r0
blr
.size abi_test_clobber_cr$_,.-abi_test_clobber_cr$_
____
}
$code .= <<____;
.globl abi_test_clobber_ctr
.align 4
abi_test_clobber_ctr:
li r0, 0
mtctr r0
blr
.size abi_test_clobber_ctr,.-abi_test_clobber_ctr
.globl abi_test_clobber_lr
.align 4
abi_test_clobber_lr:
mflr r0
mtctr r0
li r0, 0
mtlr r0
bctr
.size abi_test_clobber_lr,.-abi_test_clobber_lr
____
print $code;
close STDOUT or die "error closing STDOUT: $!";

View File

@@ -0,0 +1,113 @@
#!/usr/bin/env perl
# Copyright (c) 2018, Google Inc.
#
# SPDX-License-Identifier: ISC
# 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 = $ARGV[1];
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: $!";

View File

@@ -0,0 +1,427 @@
#!/usr/bin/env perl
# Copyright (c) 2018, Google Inc.
#
# SPDX-License-Identifier: ISC
# This file defines helper functions for crypto/test/abi_test.h on x86_64. 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://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
# Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/x64-software-conventions?view=vs-2017
use strict;
my $flavour = shift;
my $output = shift;
my $win64 = 0;
$win64 = 1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
$0 =~ m/(.*[\/\\])[^\/\\]+$/;
my $dir = $1;
my $xlate;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
open OUT, "| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT = *OUT;
# @inp is the registers used for function inputs, in order.
my @inp = $win64 ? ("%rcx", "%rdx", "%r8", "%r9") :
("%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9");
# @caller_state is the list of registers that the callee must preserve for the
# caller. This must match the definition of CallerState in abi_test.h.
my @caller_state = ("%rbx", "%rbp", "%r12", "%r13", "%r14", "%r15");
if ($win64) {
@caller_state = ("%rbx", "%rbp", "%rdi", "%rsi", "%r12", "%r13", "%r14",
"%r15", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10",
"%xmm11", "%xmm12", "%xmm13", "%xmm14", "%xmm15");
}
# $caller_state_size is the size of CallerState, in bytes.
my $caller_state_size = 0;
foreach (@caller_state) {
if (/^%r/) {
$caller_state_size += 8;
} elsif (/^%xmm/) {
$caller_state_size += 16;
} else {
die "unknown register $_";
}
}
# load_caller_state returns code which loads a CallerState structure at
# $off($reg) into the respective registers. No other registers are touched, but
# $reg may not be a register in CallerState. $cb is an optional callback to
# add extra lines after each movq or movdqa. $cb is passed the offset, relative
# to $reg, and name of each register.
sub load_caller_state {
my ($off, $reg, $cb) = @_;
my $ret = "";
foreach (@caller_state) {
my $old_off = $off;
if (/^%r/) {
$ret .= "\tmovq\t$off($reg), $_\n";
$off += 8;
} elsif (/^%xmm/) {
$ret .= "\tmovdqa\t$off($reg), $_\n";
$off += 16;
} else {
die "unknown register $_";
}
$ret .= $cb->($old_off, $_) if (defined($cb));
}
return $ret;
}
# store_caller_state behaves like load_caller_state, except that it writes the
# current values of the registers into $off($reg).
sub store_caller_state {
my ($off, $reg, $cb) = @_;
my $ret = "";
foreach (@caller_state) {
my $old_off = $off;
if (/^%r/) {
$ret .= "\tmovq\t$_, $off($reg)\n";
$off += 8;
} elsif (/^%xmm/) {
$ret .= "\tmovdqa\t$_, $off($reg)\n";
$off += 16;
} else {
die "unknown register $_";
}
$ret .= $cb->($old_off, $_) if (defined($cb));
}
return $ret;
}
# $max_params is the maximum number of parameters abi_test_trampoline supports.
my $max_params = 10;
# Windows reserves stack space for the register-based parameters, while SysV
# only reserves space for the overflow ones.
my $stack_params_skip = $win64 ? scalar(@inp) : 0;
my $num_stack_params = $win64 ? $max_params : $max_params - scalar(@inp);
my ($func, $state, $argv, $argc, $unwind) = @inp;
my $code = <<____;
.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|. If |unwind| is non-zero, this function triggers unwind
# instrumentation.
# uint64_t abi_test_trampoline(void (*func)(...), CallerState *state,
# const uint64_t *argv, size_t argc,
# int unwind);
.type abi_test_trampoline, \@abi-omnipotent
.globl abi_test_trampoline
.align 16
abi_test_trampoline:
.cfi_startproc
.seh_startproc
_CET_ENDBR
# Stack layout:
# 8 bytes - align
# $caller_state_size bytes - saved caller registers
# 8 bytes - scratch space
# 8 bytes - saved copy of \$unwind (SysV-only)
# 8 bytes - saved copy of \$state
# 8 bytes - saved copy of \$func
# 8 bytes - if needed for stack alignment
# 8*$num_stack_params bytes - parameters for \$func
____
my $stack_alloc_size = 8 + $caller_state_size + 8*3 + 8*$num_stack_params;
if (!$win64) {
$stack_alloc_size += 8;
}
# SysV and Windows both require the stack to be 16-byte-aligned. The call
# instruction offsets it by 8, so stack allocations must be 8 mod 16.
if ($stack_alloc_size % 16 != 8) {
$num_stack_params++;
$stack_alloc_size += 8;
}
my $stack_params_offset = 8 * $stack_params_skip;
my $func_offset = 8 * $num_stack_params;
my $state_offset = $func_offset + 8;
# On Win64, unwind is already passed in memory. On SysV, it is passed in as
# register and we must reserve stack space for it.
my ($unwind_offset, $scratch_offset);
if ($win64) {
$unwind_offset = $stack_alloc_size + 5*8;
$scratch_offset = $state_offset + 8;
} else {
$unwind_offset = $state_offset + 8;
$scratch_offset = $unwind_offset + 8;
}
my $caller_state_offset = $scratch_offset + 8;
$code .= <<____;
subq \$$stack_alloc_size, %rsp
.cfi_adjust_cfa_offset $stack_alloc_size
.seh_allocstack $stack_alloc_size
____
$code .= <<____ if (!$win64);
movq $unwind, $unwind_offset(%rsp)
____
# Store our caller's state. This is needed because we modify it ourselves, and
# also to isolate the test infrastruction from the function under test failing
# to save some register.
$code .= store_caller_state($caller_state_offset, "%rsp", sub {
my ($off, $reg) = @_;
$reg = substr($reg, 1);
# SEH records offsets relative to %rsp (when there is no frame pointer), while
# CFI records them relative to the CFA, the value of the parent's stack
# pointer just before the call.
my $cfi_off = $off - $stack_alloc_size - 8;
my $seh_dir = ".seh_savereg";
$seh_dir = ".seh_savexmm128" if ($reg =~ /^xmm/);
return <<____;
.cfi_offset $reg, $cfi_off
$seh_dir \%$reg, $off
____
});
$code .= load_caller_state(0, $state);
$code .= <<____;
# Stash \$func and \$state, so they are available after the call returns.
movq $func, $func_offset(%rsp)
movq $state, $state_offset(%rsp)
# Load parameters. Note this will clobber \$argv and \$argc, so we can
# only use non-parameter volatile registers. There are three, and they
# are the same between SysV and Win64: %rax, %r10, and %r11.
movq $argv, %r10
movq $argc, %r11
____
foreach (@inp) {
$code .= <<____;
dec %r11
js .Largs_done
movq (%r10), $_
addq \$8, %r10
____
}
$code .= <<____;
leaq $stack_params_offset(%rsp), %rax
.Largs_loop:
dec %r11
js .Largs_done
# This block should be:
# movq (%r10), %rtmp
# movq %rtmp, (%rax)
# There are no spare registers available, so we spill into the scratch
# space.
movq %r11, $scratch_offset(%rsp)
movq (%r10), %r11
movq %r11, (%rax)
movq $scratch_offset(%rsp), %r11
addq \$8, %r10
addq \$8, %rax
jmp .Largs_loop
.Largs_done:
movq $func_offset(%rsp), %rax
movq $unwind_offset(%rsp), %r10
testq %r10, %r10
jz .Lno_unwind
# Set the trap flag.
pushfq
orq \$0x100, 0(%rsp)
popfq
# Run an instruction to trigger a breakpoint immediately before the
# call.
nop
.globl abi_test_unwind_start
abi_test_unwind_start:
call *%rax
.globl abi_test_unwind_return
abi_test_unwind_return:
# Clear the trap flag. Note this assumes the trap flag was clear on
# entry. We do not support instrumenting an unwind-instrumented
# |abi_test_trampoline|.
pushfq
andq \$-0x101, 0(%rsp) # -0x101 is ~0x100
popfq
.globl abi_test_unwind_stop
abi_test_unwind_stop:
jmp .Lcall_done
.Lno_unwind:
call *%rax
.Lcall_done:
# Store what \$func did our state, so our caller can check.
movq $state_offset(%rsp), $state
____
$code .= store_caller_state(0, $state);
# Restore our caller's state.
$code .= load_caller_state($caller_state_offset, "%rsp", sub {
my ($off, $reg) = @_;
$reg = substr($reg, 1);
return ".cfi_restore\t$reg\n";
});
$code .= <<____;
addq \$$stack_alloc_size, %rsp
.cfi_adjust_cfa_offset -$stack_alloc_size
# %rax already contains \$func's return value, unmodified.
ret
.cfi_endproc
.seh_endproc
.size abi_test_trampoline,.-abi_test_trampoline
____
# abi_test_clobber_* zeros the corresponding register. These are used to test
# the ABI-testing framework.
foreach ("ax", "bx", "cx", "dx", "di", "si", "bp", 8..15) {
$code .= <<____;
.type abi_test_clobber_r$_, \@abi-omnipotent
.globl abi_test_clobber_r$_
.align 16
abi_test_clobber_r$_:
_CET_ENDBR
xorq %r$_, %r$_
ret
.size abi_test_clobber_r$_,.-abi_test_clobber_r$_
____
}
foreach (0..15) {
$code .= <<____;
.type abi_test_clobber_xmm$_, \@abi-omnipotent
.globl abi_test_clobber_xmm$_
.align 16
abi_test_clobber_xmm$_:
_CET_ENDBR
pxor %xmm$_, %xmm$_
ret
.size abi_test_clobber_xmm$_,.-abi_test_clobber_xmm$_
____
}
$code .= <<____;
# abi_test_bad_unwind_wrong_register preserves the ABI, but annotates the wrong
# register in unwind metadata.
# void abi_test_bad_unwind_wrong_register(void);
.type abi_test_bad_unwind_wrong_register, \@abi-omnipotent
.globl abi_test_bad_unwind_wrong_register
.align 16
abi_test_bad_unwind_wrong_register:
.cfi_startproc
.seh_startproc
_CET_ENDBR
pushq %r12
.cfi_push %r13 # This should be %r13
.seh_pushreg %r13 # This should be %r13
# Windows evaluates epilogs directly in the unwinder, rather than using
# unwind codes. Add a nop so there is one non-epilog point (immediately
# before the nop) where the unwinder can observe the mistake.
nop
popq %r12
.cfi_pop %r12
ret
.seh_endproc
.cfi_endproc
.size abi_test_bad_unwind_wrong_register,.-abi_test_bad_unwind_wrong_register
# abi_test_bad_unwind_temporary preserves the ABI, but temporarily corrupts the
# storage space for a saved register, breaking unwind.
# void abi_test_bad_unwind_temporary(void);
.type abi_test_bad_unwind_temporary, \@abi-omnipotent
.globl abi_test_bad_unwind_temporary
.align 16
abi_test_bad_unwind_temporary:
.cfi_startproc
.seh_startproc
_CET_ENDBR
pushq %r12
.cfi_push %r12
.seh_pushreg %r12
movq %r12, %rax
inc %rax
movq %rax, (%rsp)
# Unwinding from here is incorrect. Although %r12 itself has not been
# changed, the unwind codes say to look in (%rsp) instead.
movq %r12, (%rsp)
# Unwinding is now fixed.
popq %r12
.cfi_pop %r12
ret
.cfi_endproc
.seh_endproc
.size abi_test_bad_unwind_temporary,.-abi_test_bad_unwind_temporary
# 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);
.type abi_test_set_direction_flag, \@abi-omnipotent
.globl abi_test_get_and_clear_direction_flag
abi_test_get_and_clear_direction_flag:
_CET_ENDBR
pushfq
popq %rax
andq \$0x400, %rax
shrq \$10, %rax
cld
ret
.size abi_test_get_and_clear_direction_flag,.-abi_test_get_and_clear_direction_flag
# abi_test_set_direction_flag sets the direction flag.
# void abi_test_set_direction_flag(void);
.type abi_test_set_direction_flag, \@abi-omnipotent
.globl abi_test_set_direction_flag
abi_test_set_direction_flag:
_CET_ENDBR
std
ret
.size abi_test_set_direction_flag,.-abi_test_set_direction_flag
____
if ($win64) {
$code .= <<____;
# abi_test_bad_unwind_epilog preserves the ABI, and correctly annotates the
# prolog, but the epilog does not match Win64's rules, breaking unwind during
# the epilog.
# void abi_test_bad_unwind_epilog(void);
.type abi_test_bad_unwind_epilog, \@abi-omnipotent
.globl abi_test_bad_unwind_epilog
.align 16
abi_test_bad_unwind_epilog:
.seh_startproc
pushq %r12
.seh_pushreg %r12
nop
# The epilog should begin here, but the nop makes it invalid.
popq %r12
nop
ret
.seh_endproc
.size abi_test_bad_unwind_epilog,.-abi_test_bad_unwind_epilog
____
}
print $code;
close STDOUT or die "error closing STDOUT: $!";