| #!/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+)/} <INPUT>; |
| 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 |
| ___ |
| } |
| |