#!/usr/bin/env perl # # For Microsoft CL this is implemented as inline assembler. So that # even though this script can generate even Win32 code, we'll be # using it primarily to generate Win64 modules. Both IA-64 and AMD64 # are supported... # pull APPLINK_MAX value from applink.c... $applink_c=$0; $applink_c=~s|[^/\\]+$||g; $applink_c.="applink.c"; open(INPUT,$applink_c) || die "can't open $applink_c: $!"; @max=grep {/APPLINK_MAX\s+(\d+)/} ; close(INPUT); ($#max==0) or die "can't find APPLINK_MAX in $applink_c"; $max[0]=~/APPLINK_MAX\s+(\d+)/; $N=$1; # number of entries in OPENSSL_UplinkTable not including # OPENSSL_UplinkTable[0], which contains this value... # Idea is to fill the OPENSSL_UplinkTable with pointers to stubs # which invoke 'void OPENSSL_Uplink (ULONG_PTR *table,int index)'; # and then dereference themselves. Latter shall result in endless # loop *unless* OPENSSL_Uplink does not replace 'table[index]' with # something else, e.g. as 'table[index]=unimplemented;'... $arg = shift; #( defined shift || open STDOUT,">$arg" ) || die "can't open $arg: $!"; if ($arg =~ /win32n/) { ia32nasm(); } elsif ($arg =~ /win32/) { ia32masm(); } elsif ($arg =~ /coff/) { ia32gas(); } elsif ($arg =~ /win64i/ or $arg =~ /ia64/) { ia64ias(); } elsif ($arg =~ /win64a/ or $arg =~ /amd64/) { amd64masm(); } else { die "nonsense $arg"; } sub ia32gas() { print <<___; .text ___ for ($i=1;$i<=$N;$i++) { print <<___; .def .Lazy$i; .scl 3; .type 32; .endef .align 4 .Lazy$i: pushl \$$i pushl \$_OPENSSL_UplinkTable call _OPENSSL_Uplink addl \$8,%esp jmp *(_OPENSSL_UplinkTable+4*$i) ___ } print <<___; .data .align 4 .globl _OPENSSL_UplinkTable _OPENSSL_UplinkTable: .long $N ___ for ($i=1;$i<=$N;$i++) { print " .long .Lazy$i\n"; } } sub ia32masm() { print <<___; .386P .model FLAT _DATA SEGMENT PUBLIC _OPENSSL_UplinkTable _OPENSSL_UplinkTable DD $N ; amount of following entries ___ for ($i=1;$i<=$N;$i++) { print " DD FLAT:\$lazy$i\n"; } print <<___; _DATA ENDS _TEXT SEGMENT EXTRN _OPENSSL_Uplink:NEAR ___ for ($i=1;$i<=$N;$i++) { print <<___; ALIGN 4 \$lazy$i PROC NEAR push $i push OFFSET FLAT:_OPENSSL_UplinkTable call _OPENSSL_Uplink add esp,8 jmp DWORD PTR _OPENSSL_UplinkTable+4*$i \$lazy$i ENDP ___ } print <<___; ALIGN 4 _TEXT ENDS END ___ } sub ia32nasm() { print <<___; SEGMENT .data GLOBAL _OPENSSL_UplinkTable _OPENSSL_UplinkTable DD $N ; amount of following entries ___ for ($i=1;$i<=$N;$i++) { print " DD \$lazy$i\n"; } print <<___; SEGMENT .text EXTERN _OPENSSL_Uplink ___ for ($i=1;$i<=$N;$i++) { print <<___; ALIGN 4 \$lazy$i: push $i push _OPENSSL_UplinkTable call _OPENSSL_Uplink add esp,8 jmp [_OPENSSL_UplinkTable+4*$i] ___ } print <<___; ALIGN 4 END ___ } sub ia64ias () { local $V=8; # max number of args uplink functions may accept... print <<___; .data .global OPENSSL_UplinkTable# OPENSSL_UplinkTable: data8 $N // amount of following entries ___ for ($i=1;$i<=$N;$i++) { print " data8 \@fptr(lazy$i#)\n"; } print <<___; .size OPENSSL_UplinkTable,.-OPENSSL_UplinkTable# .text .global OPENSSL_Uplink# .type OPENSSL_Uplink#,\@function ___ for ($i=1;$i<=$N;$i++) { print <<___; .proc lazy$i lazy$i: { .mii; alloc loc0=ar.pfs,$V,3,2,0 mov loc1=b0 addl loc2=\@ltoff(OPENSSL_UplinkTable#),gp };; { .mmi; ld8 out0=[loc2] mov out1=$i };; { .mib; adds loc2=8*$i,out0 br.call.sptk.many b0=OPENSSL_Uplink# };; { .mmi; ld8 r31=[loc2];; ld8 r30=[r31],8 };; { .mii; ld8 gp=[r31] mov b6=r30 mov b0=loc1 };; { .mib; mov ar.pfs=loc0 br.many b6 };; .endp lazy$i# ___ } } sub amd64masm() { print <<___; _DATA SEGMENT PUBLIC OPENSSL_UplinkTable OPENSSL_UplinkTable DQ $N ___ for ($i=1;$i<=$N;$i++) { print " DQ \$lazy$i\n"; } print <<___; _DATA ENDS _TEXT SEGMENT EXTERN OPENSSL_Uplink:PROC ___ for ($i=1;$i<=$N;$i++) { print <<___; ALIGN 4 \$lazy$i PROC push r9 push r8 push rdx push rcx sub rsp,40 lea rcx,OFFSET OPENSSL_UplinkTable mov rdx,$i call OPENSSL_Uplink add rsp,40 pop rcx pop rdx pop r8 pop r9 jmp QWORD PTR OPENSSL_UplinkTable+8*$i \$lazy$i ENDP ___ } print <<___; _TEXT ENDS END ___ }