1#!/usr/bin/env perl
2#
3# For Microsoft CL this is implemented as inline assembler. So that
4# even though this script can generate even Win32 code, we'll be
5# using it primarily to generate Win64 modules. Both IA-64 and AMD64
6# are supported...
7
8# pull APPLINK_MAX value from applink.c...
9$applink_c=$0;
10$applink_c=~s|[^/\\]+$||g;
11$applink_c.="applink.c";
12open(INPUT,$applink_c) || die "can't open $applink_c: $!";
13@max=grep {/APPLINK_MAX\s+(\d+)/} <INPUT>;
14close(INPUT);
15($#max==0) or die "can't find APPLINK_MAX in $applink_c";
16
17$max[0]=~/APPLINK_MAX\s+(\d+)/;
18$N=$1;	# number of entries in OPENSSL_UplinkTable not including
19	# OPENSSL_UplinkTable[0], which contains this value...
20
21# Idea is to fill the OPENSSL_UplinkTable with pointers to stubs
22# which invoke 'void OPENSSL_Uplink (ULONG_PTR *table,int index)';
23# and then dereference themselves. Latter shall result in endless
24# loop *unless* OPENSSL_Uplink does not replace 'table[index]' with
25# something else, e.g. as 'table[index]=unimplemented;'...
26
27$arg = shift;
28#( defined shift || open STDOUT,">$arg" ) || die "can't open $arg: $!";
29
30if ($arg =~ /win32n/)	{ ia32nasm();  }
31elsif ($arg =~ /win32/)	{ ia32masm();  }
32elsif ($arg =~ /coff/)	{ ia32gas();   }
33elsif ($arg =~ /win64i/ or $arg =~ /ia64/)	{ ia64ias();   }
34elsif ($arg =~ /win64a/ or $arg =~ /amd64/)	{ amd64masm(); }
35else	{ die "nonsense $arg"; }
36
37sub ia32gas() {
38print <<___;
39.text
40___
41for ($i=1;$i<=$N;$i++) {
42print <<___;
43.def	.Lazy$i;	.scl	3;	.type	32;	.endef
44.align	4
45.Lazy$i:
46	pushl	\$$i
47	pushl	\$_OPENSSL_UplinkTable
48	call	_OPENSSL_Uplink
49	addl	\$8,%esp
50	jmp	*(_OPENSSL_UplinkTable+4*$i)
51___
52}
53print <<___;
54.data
55.align	4
56.globl  _OPENSSL_UplinkTable
57_OPENSSL_UplinkTable:
58	.long	$N
59___
60for ($i=1;$i<=$N;$i++) {   print "	.long	.Lazy$i\n";   }
61}
62
63sub ia32masm() {
64print <<___;
65.386P
66.model	FLAT
67
68_DATA	SEGMENT
69PUBLIC	_OPENSSL_UplinkTable
70_OPENSSL_UplinkTable	DD	$N	; amount of following entries
71___
72for ($i=1;$i<=$N;$i++) {   print "	DD	FLAT:\$lazy$i\n";   }
73print <<___;
74_DATA	ENDS
75
76_TEXT	SEGMENT
77EXTRN	_OPENSSL_Uplink:NEAR
78___
79for ($i=1;$i<=$N;$i++) {
80print <<___;
81ALIGN	4
82\$lazy$i	PROC NEAR
83	push	$i
84	push	OFFSET FLAT:_OPENSSL_UplinkTable
85	call	_OPENSSL_Uplink
86	add	esp,8
87	jmp	DWORD PTR _OPENSSL_UplinkTable+4*$i
88\$lazy$i	ENDP
89___
90}
91print <<___;
92ALIGN	4
93_TEXT	ENDS
94END
95___
96}
97
98sub ia32nasm() {
99print <<___;
100SEGMENT	.data
101GLOBAL	_OPENSSL_UplinkTable
102_OPENSSL_UplinkTable	DD	$N	; amount of following entries
103___
104for ($i=1;$i<=$N;$i++) {   print "	DD	\$lazy$i\n";   }
105print <<___;
106
107SEGMENT	.text
108EXTERN	_OPENSSL_Uplink
109___
110for ($i=1;$i<=$N;$i++) {
111print <<___;
112ALIGN	4
113\$lazy$i:
114	push	$i
115	push	_OPENSSL_UplinkTable
116	call	_OPENSSL_Uplink
117	add	esp,8
118	jmp	[_OPENSSL_UplinkTable+4*$i]
119___
120}
121print <<___;
122ALIGN	4
123END
124___
125}
126
127sub ia64ias () {
128local $V=8;	# max number of args uplink functions may accept...
129print <<___;
130.data
131.global	OPENSSL_UplinkTable#
132OPENSSL_UplinkTable:	data8	$N	// amount of following entries
133___
134for ($i=1;$i<=$N;$i++) {   print "	data8	\@fptr(lazy$i#)\n";   }
135print <<___;
136.size	OPENSSL_UplinkTable,.-OPENSSL_UplinkTable#
137
138.text
139.global	OPENSSL_Uplink#
140.type	OPENSSL_Uplink#,\@function
141___
142for ($i=1;$i<=$N;$i++) {
143print <<___;
144.proc	lazy$i
145lazy$i:
146{ .mii;	alloc	loc0=ar.pfs,$V,3,2,0
147	mov	loc1=b0
148	addl	loc2=\@ltoff(OPENSSL_UplinkTable#),gp	};;
149{ .mmi;	ld8	out0=[loc2]
150	mov	out1=$i					};;
151{ .mib;	adds	loc2=8*$i,out0
152	br.call.sptk.many	b0=OPENSSL_Uplink#	};;
153{ .mmi;	ld8	r31=[loc2];;
154	ld8	r30=[r31],8				};;
155{ .mii;	ld8	gp=[r31]
156	mov	b6=r30
157	mov	b0=loc1					};;
158{ .mib; mov	ar.pfs=loc0
159	br.many	b6					};;
160.endp	lazy$i#
161___
162}
163}
164
165sub amd64masm() {
166print <<___;
167_DATA	SEGMENT
168PUBLIC	OPENSSL_UplinkTable
169OPENSSL_UplinkTable	DQ	$N
170___
171for ($i=1;$i<=$N;$i++) {   print "	DQ	\$lazy$i\n";   }
172print <<___;
173_DATA	ENDS
174
175_TEXT	SEGMENT
176EXTERN	OPENSSL_Uplink:PROC
177___
178for ($i=1;$i<=$N;$i++) {
179print <<___;
180ALIGN	4
181\$lazy$i	PROC
182	push	r9
183	push	r8
184	push	rdx
185	push	rcx
186	sub	rsp,40
187	lea	rcx,OFFSET OPENSSL_UplinkTable
188	mov	rdx,$i
189	call	OPENSSL_Uplink
190	add	rsp,40
191	pop	rcx
192	pop	rdx
193	pop	r8
194	pop	r9
195	jmp	QWORD PTR OPENSSL_UplinkTable+8*$i
196\$lazy$i	ENDP
197___
198}
199print <<___;
200_TEXT	ENDS
201END
202___
203}
204
205