acdf6928ca52c1c65b93861364aa90faafcb4e70
[openssl.git] / crypto / bn / asm / sparcv9-mont.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. Rights for redistribution and usage in source and binary
6 # forms are granted according to the OpenSSL license.
7 # ====================================================================
8
9 # December 2005
10 #
11 # Pure SPARCv9/8+ and IALU-only bn_mul_mont implementation. The reasons
12 # for undertaken effort are multiple. First of all, UltraSPARC is not
13 # the whole SPARCv9 universe and other VIS-free implementations deserve
14 # optimized code as much. Secondly, newly introduced UltraSPARC T1,
15 # a.k.a. Niagara, has shared FPU and concurrent FPU-intensive pathes,
16 # such as sparcv9a-mont, will simply sink it. Yes, T1 is equipped with
17 # several integrated RSA/DSA accelerator circuits accessible through
18 # kernel driver [only(*)], but having decent user-land software
19 # implementation is important too. Finally, reasons like desire to
20 # experiment with dedicated squaring procedure. Yes, this module
21 # implements one, because it was easiest to draft it in SPARCv9
22 # instructions...
23
24 # (*)   Engine accessing the driver in question is on my TODO list.
25 #       For reference, acceleator is estimated to give 6 to 10 times
26 #       improvement on single-threaded RSA sign. It should be noted
27 #       that 6-10x improvement coefficient does not actually mean
28 #       something extraordinary in terms of absolute [single-threaded]
29 #       performance, as SPARCv9 instruction set is by all means least
30 #       suitable for high performance crypto among other 64 bit
31 #       platforms. 6-10x factor simply places T1 in same performance
32 #       domain as say AMD64 and IA-64. Improvement of RSA verify don't
33 #       appear impressive at all, but it's the sign operation which is
34 #       far more critical/interesting.
35
36 # You might notice that inner loops are modulo-scheduled:-) This has
37 # essentially negligible impact on UltraSPARC performance, it's
38 # Fujitsu SPARC64 V users who should notice and hopefully appreciate
39 # the advantage... Currently this module surpasses sparcv9a-mont.pl
40 # by ~20% on UltraSPARC-III and later cores, but recall that sparcv9a
41 # module still have hidden potential [see TODO list there], which is
42 # estimated to be larger than 20%...
43
44 # int bn_mul_mont(
45 $rp="%i0";      # BN_ULONG *rp,
46 $ap="%i1";      # const BN_ULONG *ap,
47 $bp="%i2";      # const BN_ULONG *bp,
48 $np="%i3";      # const BN_ULONG *np,
49 $n0="%i4";      # const BN_ULONG *n0,
50 $num="%i5";     # int num);
51
52 $bits=32;
53 for (@ARGV)     { $bits=64 if (/\-m64/ || /\-xarch\=v9/); }
54 if ($bits==64)  { $bias=2047; $frame=192; }
55 else            { $bias=0;    $frame=128; }
56
57 $car0="%o0";
58 $car1="%o1";
59 $car2="%o2";    # 1 bit
60 $acc0="%o3";
61 $acc1="%o4";
62 $mask="%g1";    # 32 bits, what a waste...
63 $tmp0="%g4";
64 $tmp1="%g5";
65
66 $i="%l0";
67 $j="%l1";
68 $mul0="%l2";
69 $mul1="%l3";
70 $tp="%l4";
71 $apj="%l5";
72 $npj="%l6";
73 $tpj="%l7";
74
75 $fname="bn_mul_mont_int";
76
77 $code=<<___;
78 .section        ".text",#alloc,#execinstr
79
80 .global $fname
81 .align  32
82 $fname:
83         cmp     %o5,4                   ! 128 bits minimum
84         bge,pt  %icc,.Lenter
85         sethi   %hi(0xffffffff),$mask
86         retl
87         clr     %o0
88 .align  32
89 .Lenter:
90         save    %sp,-$frame,%sp
91         sll     $num,2,$num             ! num*=4
92         or      $mask,%lo(0xffffffff),$mask
93         ld      [$n0],$n0
94         cmp     $ap,$bp
95         and     $num,$mask,$num
96         ld      [$bp],$mul0             ! bp[0]
97         nop
98
99         add     %sp,$bias,%o7           ! real top of stack
100         ld      [$ap],$car0             ! ap[0] ! redundant in squaring context
101         sub     %o7,$num,%o7
102         ld      [$ap+4],$apj            ! ap[1]
103         and     %o7,-1024,%o7
104         ld      [$np],$car1             ! np[0]
105         sub     %o7,$bias,%sp           ! alloca
106         ld      [$np+4],$npj            ! np[1]
107         be,pt   `$bits==32?"%icc":"%xcc"`,.Lbn_sqr_mont
108         mov     12,$j
109
110         mulx    $car0,$mul0,$car0       ! ap[0]*bp[0]
111         mulx    $apj,$mul0,$tmp0        !prologue! ap[1]*bp[0]
112         and     $car0,$mask,$acc0
113         add     %sp,$bias+$frame,$tp
114         ld      [$ap+8],$apj            !prologue!
115
116         mulx    $n0,$acc0,$mul1         ! "t[0]"*n0
117         and     $mul1,$mask,$mul1
118
119         mulx    $car1,$mul1,$car1       ! np[0]*"t[0]"*n0
120         mulx    $npj,$mul1,$acc1        !prologue! np[1]*"t[0]"*n0
121         srlx    $car0,32,$car0
122         add     $acc0,$car1,$car1
123         ld      [$np+8],$npj            !prologue!
124         srlx    $car1,32,$car1
125         mov     $tmp0,$acc0             !prologue!
126
127 .L1st:
128         mulx    $apj,$mul0,$tmp0
129         mulx    $npj,$mul1,$tmp1
130         add     $acc0,$car0,$car0
131         ld      [$ap+$j],$apj           ! ap[j]
132         and     $car0,$mask,$acc0
133         add     $acc1,$car1,$car1
134         ld      [$np+$j],$npj           ! np[j]
135         srlx    $car0,32,$car0
136         add     $acc0,$car1,$car1
137         add     $j,4,$j                 ! j++
138         mov     $tmp0,$acc0
139         st      $car1,[$tp]
140         cmp     $j,$num
141         mov     $tmp1,$acc1
142         srlx    $car1,32,$car1
143         bl      %icc,.L1st
144         add     $tp,4,$tp               ! tp++
145 !.L1st
146
147         mulx    $apj,$mul0,$tmp0        !epilogue!
148         mulx    $npj,$mul1,$tmp1
149         add     $acc0,$car0,$car0
150         and     $car0,$mask,$acc0
151         add     $acc1,$car1,$car1
152         srlx    $car0,32,$car0
153         add     $acc0,$car1,$car1
154         st      $car1,[$tp]
155         srlx    $car1,32,$car1
156
157         add     $tmp0,$car0,$car0
158         and     $car0,$mask,$acc0
159         add     $tmp1,$car1,$car1
160         srlx    $car0,32,$car0
161         add     $acc0,$car1,$car1
162         st      $car1,[$tp+4]
163         srlx    $car1,32,$car1
164
165         add     $car0,$car1,$car1
166         st      $car1,[$tp+8]
167         srlx    $car1,32,$car2
168 \f
169         mov     4,$i                    ! i++
170         ld      [$bp+4],$mul0           ! bp[1]
171 .Louter:
172         add     %sp,$bias+$frame,$tp
173         ld      [$ap],$car0             ! ap[0]
174         ld      [$ap+4],$apj            ! ap[1]
175         ld      [$np],$car1             ! np[0]
176         ld      [$np+4],$npj            ! np[1]
177         ld      [$tp],$tmp1             ! tp[0]
178         ld      [$tp+4],$tpj            ! tp[1]
179         mov     12,$j
180
181         mulx    $car0,$mul0,$car0
182         mulx    $apj,$mul0,$tmp0        !prologue!
183         add     $tmp1,$car0,$car0
184         ld      [$ap+8],$apj            !prologue!
185         and     $car0,$mask,$acc0
186
187         mulx    $n0,$acc0,$mul1
188         and     $mul1,$mask,$mul1
189
190         mulx    $car1,$mul1,$car1
191         mulx    $npj,$mul1,$acc1        !prologue!
192         srlx    $car0,32,$car0
193         add     $acc0,$car1,$car1
194         ld      [$np+8],$npj            !prologue!
195         srlx    $car1,32,$car1
196         mov     $tmp0,$acc0             !prologue!
197
198 .Linner:
199         mulx    $apj,$mul0,$tmp0
200         mulx    $npj,$mul1,$tmp1
201         add     $tpj,$car0,$car0
202         ld      [$ap+$j],$apj           ! ap[j]
203         add     $acc0,$car0,$car0
204         add     $acc1,$car1,$car1
205         ld      [$np+$j],$npj           ! np[j]
206         and     $car0,$mask,$acc0
207         ld      [$tp+8],$tpj            ! tp[j]
208         srlx    $car0,32,$car0
209         add     $acc0,$car1,$car1
210         add     $j,4,$j                 ! j++
211         mov     $tmp0,$acc0
212         st      $car1,[$tp]             ! tp[j-1]
213         srlx    $car1,32,$car1
214         mov     $tmp1,$acc1
215         cmp     $j,$num
216         bl      %icc,.Linner
217         add     $tp,4,$tp               ! tp++
218 !.Linner
219
220         mulx    $apj,$mul0,$tmp0        !epilogue!
221         mulx    $npj,$mul1,$tmp1
222         add     $tpj,$car0,$car0
223         add     $acc0,$car0,$car0
224         ld      [$tp+8],$tpj            ! tp[j]
225         and     $car0,$mask,$acc0
226         add     $acc1,$car1,$car1
227         srlx    $car0,32,$car0
228         add     $acc0,$car1,$car1
229         st      $car1,[$tp]             ! tp[j-1]
230         srlx    $car1,32,$car1
231
232         add     $tpj,$car0,$car0
233         add     $tmp0,$car0,$car0
234         and     $car0,$mask,$acc0
235         add     $tmp1,$car1,$car1
236         add     $acc0,$car1,$car1
237         st      $car1,[$tp+4]           ! tp[j-1]
238         srlx    $car0,32,$car0
239         add     $i,4,$i                 ! i++
240         srlx    $car1,32,$car1
241
242         add     $car0,$car1,$car1
243         cmp     $i,$num
244         add     $car2,$car1,$car1
245         st      $car1,[$tp+8]
246
247         srlx    $car1,32,$car2
248         bl,a    %icc,.Louter
249         ld      [$bp+$i],$mul0          ! bp[i]
250 !.Louter
251
252         add     $tp,12,$tp
253 \f
254 .Ltail:
255         add     $np,$num,$np
256         add     $rp,$num,$rp
257
258         cmp     $car2,0                 ! clears %icc.c
259         bne,pn  %icc,.Lsub
260         sub     %g0,$num,%o7            ! k=-num
261
262         cmp     $car1,$npj              ! compare top-most $tp and $np words
263         bcs,pt  %icc,.Lcopy             ! %icc.c is clean if not taken
264         nop
265
266 .align  16,0x1000000
267 .Lsub:
268         ld      [$tp+%o7],%o0
269         ld      [$np+%o7],%o1
270         subccc  %o0,%o1,%o1
271         st      %o1,[$rp+%o7]
272         add     %o7,4,%o7
273         brnz    %o7,.Lsub
274         nop
275         subccc  $car2,0,$car2
276         bcc     %icc,.Lzap
277         sub     %g0,$num,%o7
278
279 .align  16,0x1000000
280 .Lcopy:
281         ld      [$tp+%o7],%o0
282         st      %o0,[$rp+%o7]
283         add     %o7,4,%o7
284         brnz    %o7,.Lcopy
285         nop
286         ba      .Lzap
287         sub     %g0,$num,%o7
288
289 .align  32
290 .Lzap:
291         st      %g0,[$tp+%o7]
292         add     %o7,4,%o7
293         brnz    %o7,.Lzap
294         nop
295         mov     1,%i0
296         ret
297         restore
298 ___
299 \f
300 ########
301 ######## .Lbn_sqr_mont gives up to 20% *overall* improvement over
302 ######## code without following dedicated squaring procedure.
303 ########
304 $sbit="%i2";            # re-use $bp!
305
306 $code.=<<___;
307 .align  32
308 .Lbn_sqr_mont:
309         mulx    $mul0,$mul0,$car0               ! ap[0]*ap[0]
310         mulx    $apj,$mul0,$tmp0                !prologue!
311         and     $car0,$mask,$acc0
312         add     %sp,$bias+$frame,$tp
313         ld      [$ap+8],$apj                    !prologue!
314
315         mulx    $n0,$acc0,$mul1                 ! "t[0]"*n0
316         srlx    $car0,32,$car0
317         and     $mul1,$mask,$mul1
318
319         mulx    $car1,$mul1,$car1               ! np[0]*"t[0]"*n0
320         mulx    $npj,$mul1,$acc1                !prologue!
321         and     $car0,1,$sbit
322         ld      [$np+8],$npj                    !prologue!
323         srlx    $car0,1,$car0
324         add     $acc0,$car1,$car1
325         srlx    $car1,32,$car1
326         mov     $tmp0,$acc0                     !prologue!
327
328 .Lsqr_1st:
329         mulx    $apj,$mul0,$tmp0
330         mulx    $npj,$mul1,$tmp1
331         add     $acc0,$car0,$car0               ! ap[j]*a0+c0
332         add     $acc1,$car1,$car1
333         ld      [$ap+$j],$apj                   ! ap[j]
334         and     $car0,$mask,$acc0
335         ld      [$np+$j],$npj                   ! np[j]
336         srlx    $car0,32,$car0
337         add     $acc0,$acc0,$acc0
338         or      $sbit,$acc0,$acc0
339         mov     $tmp1,$acc1
340         srlx    $acc0,32,$sbit
341         add     $j,4,$j                         ! j++
342         and     $acc0,$mask,$acc0
343         cmp     $j,$num
344         add     $acc0,$car1,$car1
345         st      $car1,[$tp]
346         mov     $tmp0,$acc0
347         srlx    $car1,32,$car1
348         bl      %icc,.Lsqr_1st
349         add     $tp,4,$tp                       ! tp++
350 !.Lsqr_1st
351
352         mulx    $apj,$mul0,$tmp0                ! epilogue
353         mulx    $npj,$mul1,$tmp1
354         add     $acc0,$car0,$car0               ! ap[j]*a0+c0
355         add     $acc1,$car1,$car1
356         and     $car0,$mask,$acc0
357         srlx    $car0,32,$car0
358         add     $acc0,$acc0,$acc0
359         or      $sbit,$acc0,$acc0
360         srlx    $acc0,32,$sbit
361         and     $acc0,$mask,$acc0
362         add     $acc0,$car1,$car1
363         st      $car1,[$tp]
364         srlx    $car1,32,$car1
365
366         add     $tmp0,$car0,$car0               ! ap[j]*a0+c0
367         add     $tmp1,$car1,$car1
368         and     $car0,$mask,$acc0
369         srlx    $car0,32,$car0
370         add     $acc0,$acc0,$acc0
371         or      $sbit,$acc0,$acc0
372         srlx    $acc0,32,$sbit
373         and     $acc0,$mask,$acc0
374         add     $acc0,$car1,$car1
375         st      $car1,[$tp+4]
376         srlx    $car1,32,$car1
377
378         add     $car0,$car0,$car0
379         or      $sbit,$car0,$car0
380         add     $car0,$car1,$car1
381         st      $car1,[$tp+8]
382         srlx    $car1,32,$car2
383 \f
384         ld      [%sp+$bias+$frame],$tmp0        ! tp[0]
385         ld      [%sp+$bias+$frame+4],$tmp1      ! tp[1]
386         ld      [%sp+$bias+$frame+8],$tpj       ! tp[2]
387         ld      [$ap+4],$mul0                   ! ap[1]
388         ld      [$ap+8],$apj                    ! ap[2]
389         ld      [$np],$car1                     ! np[0]
390         ld      [$np+4],$npj                    ! np[1]
391         mulx    $n0,$tmp0,$mul1
392
393         mulx    $mul0,$mul0,$car0
394         and     $mul1,$mask,$mul1
395
396         mulx    $car1,$mul1,$car1
397         mulx    $npj,$mul1,$acc1
398         add     $tmp0,$car1,$car1
399         and     $car0,$mask,$acc0
400         ld      [$np+8],$npj                    ! np[2]
401         srlx    $car1,32,$car1
402         add     $tmp1,$car1,$car1
403         srlx    $car0,32,$car0
404         add     $acc0,$car1,$car1
405         and     $car0,1,$sbit
406         add     $acc1,$car1,$car1
407         srlx    $car0,1,$car0
408         mov     12,$j
409         st      $car1,[%sp+$bias+$frame]        ! tp[0]=
410         srlx    $car1,32,$car1
411         add     %sp,$bias+$frame+4,$tp
412
413 .Lsqr_2nd:
414         mulx    $apj,$mul0,$acc0
415         mulx    $npj,$mul1,$acc1
416         add     $acc0,$car0,$car0
417         add     $tpj,$car1,$car1
418         ld      [$ap+$j],$apj                   ! ap[j]
419         and     $car0,$mask,$acc0
420         ld      [$np+$j],$npj                   ! np[j]
421         srlx    $car0,32,$car0
422         add     $acc1,$car1,$car1
423         ld      [$tp+8],$tpj                    ! tp[j]
424         add     $acc0,$acc0,$acc0
425         add     $j,4,$j                         ! j++
426         or      $sbit,$acc0,$acc0
427         srlx    $acc0,32,$sbit
428         and     $acc0,$mask,$acc0
429         cmp     $j,$num
430         add     $acc0,$car1,$car1
431         st      $car1,[$tp]                     ! tp[j-1]
432         srlx    $car1,32,$car1
433         bl      %icc,.Lsqr_2nd
434         add     $tp,4,$tp                       ! tp++
435 !.Lsqr_2nd
436
437         mulx    $apj,$mul0,$acc0
438         mulx    $npj,$mul1,$acc1
439         add     $acc0,$car0,$car0
440         add     $tpj,$car1,$car1
441         and     $car0,$mask,$acc0
442         srlx    $car0,32,$car0
443         add     $acc1,$car1,$car1
444         add     $acc0,$acc0,$acc0
445         or      $sbit,$acc0,$acc0
446         srlx    $acc0,32,$sbit
447         and     $acc0,$mask,$acc0
448         add     $acc0,$car1,$car1
449         st      $car1,[$tp]                     ! tp[j-1]
450         srlx    $car1,32,$car1
451
452         add     $car0,$car0,$car0
453         or      $sbit,$car0,$car0
454         add     $car0,$car1,$car1
455         add     $car2,$car1,$car1
456         st      $car1,[$tp+4]
457         srlx    $car1,32,$car2
458 \f
459         ld      [%sp+$bias+$frame],$tmp1        ! tp[0]
460         ld      [%sp+$bias+$frame+4],$tpj       ! tp[1]
461         ld      [$ap+8],$mul0                   ! ap[2]
462         ld      [$np],$car1                     ! np[0]
463         ld      [$np+4],$npj                    ! np[1]
464         mulx    $n0,$tmp1,$mul1
465         and     $mul1,$mask,$mul1
466         mov     8,$i
467
468         mulx    $mul0,$mul0,$car0
469         mulx    $car1,$mul1,$car1
470         and     $car0,$mask,$acc0
471         add     $tmp1,$car1,$car1
472         srlx    $car0,32,$car0
473         add     %sp,$bias+$frame,$tp
474         srlx    $car1,32,$car1
475         and     $car0,1,$sbit
476         srlx    $car0,1,$car0
477         mov     4,$j
478
479 .Lsqr_outer:
480 .Lsqr_inner1:
481         mulx    $npj,$mul1,$acc1
482         add     $tpj,$car1,$car1
483         add     $j,4,$j
484         ld      [$tp+8],$tpj
485         cmp     $j,$i
486         add     $acc1,$car1,$car1
487         ld      [$np+$j],$npj
488         st      $car1,[$tp]
489         srlx    $car1,32,$car1
490         bl      %icc,.Lsqr_inner1
491         add     $tp,4,$tp
492 !.Lsqr_inner1
493
494         add     $j,4,$j
495         ld      [$ap+$j],$apj                   ! ap[j]
496         mulx    $npj,$mul1,$acc1
497         add     $tpj,$car1,$car1
498         ld      [$np+$j],$npj                   ! np[j]
499         add     $acc0,$car1,$car1
500         ld      [$tp+8],$tpj                    ! tp[j]
501         add     $acc1,$car1,$car1
502         st      $car1,[$tp]
503         srlx    $car1,32,$car1
504
505         add     $j,4,$j
506         cmp     $j,$num
507         be,pn   %icc,.Lsqr_no_inner2
508         add     $tp,4,$tp
509
510 .Lsqr_inner2:
511         mulx    $apj,$mul0,$acc0
512         mulx    $npj,$mul1,$acc1
513         add     $tpj,$car1,$car1
514         add     $acc0,$car0,$car0
515         ld      [$ap+$j],$apj                   ! ap[j]
516         and     $car0,$mask,$acc0
517         ld      [$np+$j],$npj                   ! np[j]
518         srlx    $car0,32,$car0
519         add     $acc0,$acc0,$acc0
520         ld      [$tp+8],$tpj                    ! tp[j]
521         or      $sbit,$acc0,$acc0
522         add     $j,4,$j                         ! j++
523         srlx    $acc0,32,$sbit
524         and     $acc0,$mask,$acc0
525         cmp     $j,$num
526         add     $acc0,$car1,$car1
527         add     $acc1,$car1,$car1
528         st      $car1,[$tp]                     ! tp[j-1]
529         srlx    $car1,32,$car1
530         bl      %icc,.Lsqr_inner2
531         add     $tp,4,$tp                       ! tp++
532
533 .Lsqr_no_inner2:
534         mulx    $apj,$mul0,$acc0
535         mulx    $npj,$mul1,$acc1
536         add     $tpj,$car1,$car1
537         add     $acc0,$car0,$car0
538         and     $car0,$mask,$acc0
539         srlx    $car0,32,$car0
540         add     $acc0,$acc0,$acc0
541         or      $sbit,$acc0,$acc0
542         srlx    $acc0,32,$sbit
543         and     $acc0,$mask,$acc0
544         add     $acc0,$car1,$car1
545         add     $acc1,$car1,$car1
546         st      $car1,[$tp]                     ! tp[j-1]
547         srlx    $car1,32,$car1
548
549         add     $car0,$car0,$car0
550         or      $sbit,$car0,$car0
551         add     $car0,$car1,$car1
552         add     $car2,$car1,$car1
553         st      $car1,[$tp+4]
554         srlx    $car1,32,$car2
555 \f
556         add     $i,4,$i                         ! i++
557         ld      [%sp+$bias+$frame],$tmp1        ! tp[0]
558         ld      [%sp+$bias+$frame+4],$tpj       ! tp[1]
559         ld      [$ap+$i],$mul0                  ! ap[j]
560         ld      [$np],$car1                     ! np[0]
561         ld      [$np+4],$npj                    ! np[1]
562         mulx    $n0,$tmp1,$mul1
563         and     $mul1,$mask,$mul1
564         add     $i,4,$tmp0
565
566         mulx    $mul0,$mul0,$car0
567         mulx    $car1,$mul1,$car1
568         and     $car0,$mask,$acc0
569         add     $tmp1,$car1,$car1
570         srlx    $car0,32,$car0
571         add     %sp,$bias+$frame,$tp
572         srlx    $car1,32,$car1
573         and     $car0,1,$sbit
574         srlx    $car0,1,$car0
575
576         cmp     $tmp0,$num                      ! i<num-1
577         bl      %icc,.Lsqr_outer
578         mov     4,$j
579 \f
580 .Lsqr_last:
581         mulx    $npj,$mul1,$acc1
582         add     $tpj,$car1,$car1
583         add     $j,4,$j
584         ld      [$tp+8],$tpj
585         cmp     $j,$i
586         add     $acc1,$car1,$car1
587         ld      [$np+$j],$npj
588         st      $car1,[$tp]
589         srlx    $car1,32,$car1
590         bl      %icc,.Lsqr_last
591         add     $tp,4,$tp
592 !.Lsqr_last
593
594         mulx    $npj,$mul1,$acc1
595         add     $tpj,$car1,$car1
596         add     $acc0,$car1,$car1
597         add     $acc1,$car1,$car1
598         st      $car1,[$tp]
599         srlx    $car1,32,$car1
600
601         add     $car0,$car0,$car0               ! recover $car0
602         or      $sbit,$car0,$car0
603         add     $car0,$car1,$car1
604         add     $car2,$car1,$car1
605         st      $car1,[$tp+4]
606         srlx    $car1,32,$car2
607
608         ba      .Ltail
609         add     $tp,8,$tp
610 .type   $fname,#function
611 .size   $fname,(.-$fname)
612 ___
613 $code =~ s/\`([^\`]*)\`/eval($1)/gem;
614 print $code;
615 close STDOUT;