uplink.pl 4.02 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
#!/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
___
}