1 %************************************************************************
3 \section[Driver-asm-fiddling]{Fiddling with assembler files (iX86)}
5 %************************************************************************
10 Utterly stomp out C functions' prologues and epilogues; i.e., the
11 stuff to do with the C stack.
13 Any other required tidying up.
17 sub init_TARGET_STUFF {
19 if ( $TargetPlatform =~ /^i386-.*-linuxaout/ ) {
21 $T_STABBY = 1; # 1 iff .stab things (usually if a.out format)
22 $T_US = '_'; # _ if symbols have an underscore on the front
23 $T_DO_GC = '_PerformGC_wrapper';
24 $T_PRE_APP = '^#'; # regexp that says what comes before APP/NO_APP
25 $T_CONST_LBL = '^LC(\d+):$';
27 $T_PRE_LLBL_PAT = 'L';
29 $T_X86_BADJMP = '^\tjmp [^L\*]';
31 $T_MOVE_DIRVS = '^\s*(\.align\s+\d+(,0x90)?\n|\.globl\s+\S+\n|\.text\n|\.data\n|\.stab[^n].*\n)';
32 $T_COPY_DIRVS = '\.(globl|stab)';
33 $T_hsc_cc_PAT = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
34 $T_DOT_WORD = '\.long';
35 $T_HDR_string = "\.text\n\t\.align 4\n"; # .align 4 is 486-cache friendly
36 $T_HDR_misc = "\.text\n\t\.align 4\n";
37 $T_HDR_data = "\.data\n\t\.align 2\n"; # ToDo: change align??
38 $T_HDR_consist = "\.text\n";
39 $T_HDR_closure = "\.data\n\t\.align 2\n"; # ToDo: change align?
40 $T_HDR_info = "\.text\n\t\.align 4\n"; # NB: requires padding
41 $T_HDR_entry = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
42 $T_HDR_fast = "\.text\n\t\.align 4\n";
43 $T_HDR_vector = "\.text\n\t\.align 4\n"; # NB: requires padding
44 $T_HDR_direct = "\.text\n\t\.align 4\n";
46 } elsif ( $TargetPlatform =~ /^i386-.*-solaris2/ ) {
48 $T_STABBY = 0; # 1 iff .stab things (usually if a.out format)
49 $T_US = ''; # _ if symbols have an underscore on the front
50 $T_DO_GC = 'PerformGC_wrapper';
51 $T_PRE_APP = '/'; # regexp that says what comes before APP/NO_APP
52 $T_CONST_LBL = '^\.LC(\d+):$'; # regexp for what such a lbl looks like
54 $T_PRE_LLBL_PAT = '\.L';
56 $T_X86_BADJMP = '^\tjmp [^\.\*]';
58 $T_MOVE_DIRVS = '^\s*(\.align\s+\d+(,0x90)?\n|\.globl\s+\S+\n|\.text\n|\.data\n|\.section\s+.*\n|\.type\s+.*\n|\.Lfe.*\n\t\.size\s+.*\n|\.size\s+.*\n|\.ident.*\n)';
59 $T_COPY_DIRVS = '\.(globl)';
61 $T_hsc_cc_PAT = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"';
62 $T_DOT_WORD = '\.long';
63 $T_HDR_string = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11)
64 $T_HDR_misc = "\.text\n\t\.align 16\n";
65 $T_HDR_data = "\.data\n\t\.align 4\n"; # ToDo: change align??
66 $T_HDR_consist = "\.text\n";
67 $T_HDR_closure = "\.data\n\t\.align 4\n"; # ToDo: change align?
68 $T_HDR_info = "\.text\n\t\.align 16\n"; # NB: requires padding
69 $T_HDR_entry = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
70 $T_HDR_fast = "\.text\n\t\.align 16\n";
71 $T_HDR_vector = "\.text\n\t\.align 16\n"; # NB: requires padding
72 $T_HDR_direct = "\.text\n\t\.align 16\n";
76 print STDERR "T_STABBY: $T_STABBY\n";
77 print STDERR "T_US: $T_US\n";
78 print STDERR "T_DO_GC: $T_DO_GC\n";
79 print STDERR "T_PRE_APP: $T_PRE_APP\n";
80 print STDERR "T_CONST_LBL: $T_CONST_LBL\n";
81 print STDERR "T_POST_LBL: $T_POST_LBL\n";
82 print STDERR "T_PRE_LLBL_PAT: $T_PRE_LLBL_PAT\n";
83 print STDERR "T_PRE_LLBL: $T_PRE_LLBL\n";
84 print STDERR "T_X86_BADJMP: $T_X86_BADJMP\n";
86 print STDERR "T_MOVE_DIRVS: $T_MOVE_DIRVS\n";
87 print STDERR "T_COPY_DIRVS: $T_COPY_DIRVS\n";
88 print STDERR "T_hsc_cc_PAT: $T_hsc_cc_PAT\n";
89 print STDERR "T_DOT_WORD: $T_DOT_WORD\n";
90 print STDERR "T_HDR_string: $T_HDR_string\n";
91 print STDERR "T_HDR_misc: $T_HDR_misc\n";
92 print STDERR "T_HDR_data: $T_HDR_data\n";
93 print STDERR "T_HDR_consist: $T_HDR_consist\n";
94 print STDERR "T_HDR_closure: $T_HDR_closure\n";
95 print STDERR "T_HDR_info: $T_HDR_info\n";
96 print STDERR "T_HDR_entry: $T_HDR_entry\n";
97 print STDERR "T_HDR_fast: $T_HDR_fast\n";
98 print STDERR "T_HDR_vector: $T_HDR_vector\n";
99 print STDERR "T_HDR_direct: $T_HDR_direct\n";
107 local($in_asmf, $out_asmf) = @_;
109 # multi-line regexp matching:
112 &init_TARGET_STUFF();
113 &init_FUNNY_THINGS();
115 open(INASM, "< $in_asmf")
116 || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
117 open(OUTASM,"> $out_asmf")
118 || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
120 # read whole file, divide into "chunks":
121 # record some info about what we've found...
123 @chk = (); # contents of the chunk
124 $numchks = 0; # number of them
125 @chkcat = (); # what category of thing in each chunk
126 @chksymb = (); # what symbol(base) is defined in this chunk
127 %slowchk = (); # ditto, its regular "slow" entry code
128 %fastchk = (); # ditto, fast entry code
129 %closurechk = (); # ditto, the (static) closure
130 %infochk = (); # given a symbol base, say what chunk its info tbl is in
131 %vectorchk = (); # ditto, return vector table
132 %directchk = (); # ditto, direct return code
138 next if $T_STABBY && /^\.stab.*${T_US}__stg_split_marker/o;
139 next if $T_STABBY && /^\.stab.*ghc.*c_ID/;
140 next if /${T_PRE_APP}(NO_)?APP/o;
142 if ( /^\s+/ ) { # most common case first -- a simple line!
143 # duplicated from the bottom
147 } elsif ( /$T_CONST_LBL/o ) {
149 $chkcat[$i] = 'string';
152 } elsif ( /^${T_US}__stg_split_marker(\d+)${T_POST_LBL}$/o ) {
154 $chkcat[$i] = 'splitmarker';
157 } elsif ( /^${T_US}([A-Za-z0-9_]+)_info${T_POST_LBL}$/o ) {
160 $chkcat[$i] = 'infotbl';
161 $chksymb[$i] = $symb;
163 die "Info table already? $symb; $i\n" if defined($infochk{$symb});
165 $infochk{$symb} = $i;
167 } elsif ( /^${T_US}([A-Za-z0-9_]+)_entry${T_POST_LBL}$/o ) {
169 $chkcat[$i] = 'slow';
174 } elsif ( /^${T_US}([A-Za-z0-9_]+)_fast\d+${T_POST_LBL}$/o ) {
176 $chkcat[$i] = 'fast';
181 } elsif ( /^${T_US}([A-Za-z0-9_]+)_closure${T_POST_LBL}$/o ) {
183 $chkcat[$i] = 'closure';
186 $closurechk{$1} = $i;
188 } elsif ( /^${T_US}ghc.*c_ID${T_POST_LBL}/o ) {
190 $chkcat[$i] = 'consist';
192 } elsif ( /^(___gnu_compiled_c|gcc2_compiled\.)${T_POST_LBL}/o ) {
195 } elsif ( /^${T_US}ErrorIO_call_count${T_POST_LBL}$/o # HACK!!!!
196 || /^${T_US}[A-Za-z0-9_]+\.\d+${T_POST_LBL}$/o
197 || /^${T_US}.*_CAT${T_POST_LBL}$/o # PROF: _entryname_CAT
198 || /^${T_US}CC_.*_struct${T_POST_LBL}$/o # PROF: _CC_ccident_struct
199 || /^${T_US}.*_done${T_POST_LBL}$/o # PROF: _module_done
200 || /^${T_US}_module_registered${T_POST_LBL}$/o # PROF: _module_registered
203 $chkcat[$i] = 'data';
206 } elsif ( /^${T_US}(ret_|djn_)/o ) {
208 $chkcat[$i] = 'misc';
211 } elsif ( /^${T_US}vtbl_([A-Za-z0-9_]+)${T_POST_LBL}$/o ) {
213 $chkcat[$i] = 'vector';
218 } elsif ( /^${T_US}([A-Za-z0-9_]+)DirectReturn${T_POST_LBL}$/o ) {
220 $chkcat[$i] = 'direct';
225 } elsif ( /^${T_US}[A-Za-z0-9_]+_upd${T_POST_LBL}$/o ) {
227 $chkcat[$i] = 'misc';
230 } elsif ( $TargetPlatform =~ /^i386-.*-solaris2/
231 && /^(_uname|uname|stat|fstat):/ ) {
232 # for some utterly bizarre reason, this platform
233 # likes to drop little local C routines with these names
234 # into each and every .o file that #includes the
235 # relevant system .h file. Yuck. We just don't
236 # tolerate them in .hc files (which we are processing
237 # here). If you need to call one of these things from
238 # Haskell, make a call to your own C wrapper, then
239 # put that C wrapper (which calls one of these) in a
240 # plain .c file. WDP 95/12
242 $chkcat[$i] = 'toss';
245 } elsif ( /^${T_US}[A-Za-z0-9_]/o ) {
248 print STDERR "Funny global thing?: $_"
249 unless $KNOWN_FUNNY_THING{$thing}
250 || /^${T_US}_(PRIn|PRStart).*${T_POST_LBL}$/o # pointer reversal GC routines
251 || /^${T_US}CC_.*${T_POST_LBL}$/ # PROF: _CC_ccident
252 || /^${T_US}_reg.*${T_POST_LBL}$/; # PROF: __reg<module>
254 $chkcat[$i] = 'misc';
257 } else { # simple line (duplicated at the top)
262 $numchks = $#chk + 1;
264 # the division into chunks is imperfect;
265 # we throw some things over the fence into the next
268 # also, there are things we would like to know
269 # about the whole module before we start spitting
272 for ($i = 0; $i < $numchks; $i++) {
273 $c = $chk[$i]; # convenience copy
275 # print STDERR "\nCHK $i (BEFORE) (",$chkcat[$i],"):\n", $c;
277 # toss all prologue stuff;
278 # be slightly paranoid to make sure there's
279 # nothing surprising in there
280 if ( $c =~ /--- BEGIN ---/ ) {
281 if (($p, $r) = split(/--- BEGIN ---/, $c)) {
282 $p =~ s/^\tpushl \%edi\n//;
283 $p =~ s/^\tpushl \%esi\n//;
284 $p =~ s/^\tsubl \$\d+,\%esp\n//;
285 die "Prologue junk?: $p\n" if $p =~ /^\t[^\.]/;
287 # glue together what's left
292 # toss all epilogue stuff; again, paranoidly
293 if ( $c =~ /--- END ---/ ) {
294 if (($r, $e) = split(/--- END ---/, $c)) {
296 $e =~ s/^\tpopl \%edi\n//;
297 $e =~ s/^\tpopl \%esi\n//;
298 $e =~ s/^\taddl \$\d+,\%esp\n//;
299 die "Epilogue junk?: $e\n" if $e =~ /^\t[^\.]/;
301 # glue together what's left
306 # toss all calls to __DISCARD__
307 $c =~ s/^\tcall ${T_US}__DISCARD__\n//go;
309 # pin a funny end-thing on (for easier matching):
310 $c .= 'FUNNY#END#THING';
312 # pick some end-things and move them to the next chunk
314 while ( $c =~ /${T_MOVE_DIRVS}FUNNY#END#THING/o ) {
317 if ( $to_move =~ /${T_COPY_DIRVS}/ && $i < ($numchks - 1) ) {
318 $chk[$i + 1] = $to_move . $chk[$i + 1];
319 # otherwise they're tossed
322 $c =~ s/${T_MOVE_DIRVS}FUNNY#END#THING/FUNNY#END#THING/o;
325 $c =~ s/FUNNY#END#THING//;
327 # print STDERR "\nCHK $i (AFTER) (",$chkcat[$i],"):\n", $c;
329 $chk[$i] = $c; # update w/ convenience copy
332 # print out all the literal strings first
333 for ($i = 0; $i < $numchks; $i++) {
334 if ( $chkcat[$i] eq 'string' ) {
335 print OUTASM $T_HDR_string, $chk[$i];
337 $chkcat[$i] = 'DONE ALREADY';
341 for ($i = 0; $i < $numchks; $i++) {
342 # print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n";
344 next if $chkcat[$i] eq 'DONE ALREADY';
346 if ( $chkcat[$i] eq 'misc' ) {
347 print OUTASM $T_HDR_misc;
348 &print_doctored($chk[$i], 0);
350 } elsif ( $chkcat[$i] eq 'toss' ) {
351 print STDERR "*** NB: TOSSING code for $chksymb[$i] !!! ***\n";
353 } elsif ( $chkcat[$i] eq 'data' ) {
354 print OUTASM $T_HDR_data;
355 print OUTASM $chk[$i];
357 } elsif ( $chkcat[$i] eq 'consist' ) {
358 if ( $chk[$i] =~ /$T_hsc_cc_PAT/o ) {
359 local($consist) = "$1.$2.$3";
361 $consist =~ s/\//./g;
363 $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly?
364 print OUTASM $T_HDR_consist, "${consist}${T_POST_LBL}\n";
366 print STDERR "Couldn't grok consistency: ", $chk[$i];
369 } elsif ( $chkcat[$i] eq 'splitmarker' ) {
370 # we can just re-constitute this one...
371 print OUTASM "${T_US}__stg_split_marker",$chksymb[$i],"${T_POST_LBL}\n";
373 } elsif ( $chkcat[$i] eq 'closure'
374 || $chkcat[$i] eq 'infotbl'
375 || $chkcat[$i] eq 'slow'
376 || $chkcat[$i] eq 'fast' ) { # do them in that order
377 $symb = $chksymb[$i];
380 if ( defined($closurechk{$symb}) ) {
381 print OUTASM $T_HDR_closure;
382 print OUTASM $chk[$closurechk{$symb}];
383 $chkcat[$closurechk{$symb}] = 'DONE ALREADY';
387 if ( defined($infochk{$symb}) ) {
389 print OUTASM $T_HDR_info;
390 print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1);
391 # entry code will be put here!
394 if ( $chk[$infochk{$symb}] =~ /${T_DOT_WORD}\s+([A-Za-z0-9_]+_entry)$/o
395 && $1 ne "${T_US}${symb}_entry" ) {
396 print STDERR "!!! entry point???\n",$chk[$infochk{$symb}];
399 $chkcat[$infochk{$symb}] = 'DONE ALREADY';
403 if ( defined($slowchk{$symb}) ) {
405 # teach it to drop through to the fast entry point:
406 $c = $chk[$slowchk{$symb}];
408 if ( defined($fastchk{$symb}) ) {
409 $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%edx\n\tjmp \*\%edx\n//;
410 $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%eax\n\tjmp \*\%eax\n//;
413 print STDERR "still has jump to fast entry point:\n$c"
414 if $c =~ /${T_US}${symb}_fast/; # NB: paranoia
416 print OUTASM $T_HDR_entry;
418 &print_doctored($c, 1); # NB: the 1!!!
420 $chkcat[$slowchk{$symb}] = 'DONE ALREADY';
424 if ( defined($fastchk{$symb}) ) {
425 print OUTASM $T_HDR_fast;
426 &print_doctored($chk[$fastchk{$symb}], 0);
427 $chkcat[$fastchk{$symb}] = 'DONE ALREADY';
430 } elsif ( $chkcat[$i] eq 'vector'
431 || $chkcat[$i] eq 'direct' ) { # do them in that order
432 $symb = $chksymb[$i];
435 if ( defined($vectorchk{$symb}) ) {
436 print OUTASM $T_HDR_vector;
437 print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0);
438 # direct return code will be put here!
439 $chkcat[$vectorchk{$symb}] = 'DONE ALREADY';
443 if ( defined($directchk{$symb}) ) {
444 print OUTASM $T_HDR_direct;
445 &print_doctored($chk[$directchk{$symb}], 0);
446 $chkcat[$directchk{$symb}] = 'DONE ALREADY';
450 &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm: $TargetPlatform)\n$chkcat[$i]\n$chk[$i]\n");
454 close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
455 close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
461 local($_, $need_fallthru_patch) = @_;
463 if ( $TargetPlatform !~ /^i386-/
464 || ! /^\t[a-z]/ ) { # no instructions in here, apparently
468 # OK, must do some x86 **HACKING**
470 local($entry_patch) = '';
471 local($exit_patch) = '';
472 local($call_entry_patch)= '';
473 local($call_exit_patch) = '';
475 #OLD: # first, convert calls to *very magic form*: (ToDo: document
479 # call _?PerformGC_wrapper
483 # call _?PerformGC_wrapper
485 # The reason we do this now is to remove the apparent use of
486 # %esp, which would throw off the "what patch code do we need"
489 # Special macros in ghc/includes/COptWraps.lh, used in
490 # ghc/runtime/CallWrap_C.lc, are required for this to work!
493 s/^\tpushl \$(\d+)\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \$$1,\%eax\n\tcall ${T_DO_GC}\n/go;
494 s/^\tpushl \%eax\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tcall ${T_DO_GC}\n/go;
495 s/^\tpushl \%edx\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \%edx,\%eax\n\tcall ${T_DO_GC}\n/go;
497 #= if ( $StolenX86Regs <= 4 ) { # %ecx is ordinary reg
498 #= s/^\tpushl \%ecx\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \%ecx,\%eax\n\tcall ${T_DO_GC}\n/go;
501 # gotta watch out for weird instructions that
502 # invisibly smash various regs:
503 # rep* %ecx used for counting
504 # scas* %edi used for destination index
505 # cmps* %e[sd]i used for indices
506 # loop* %ecx used for counting
511 # * use of STG reg [ nn(%ebx) ] where no machine reg avail
513 # * GCC used an "STG reg" for its own purposes
515 # * some secret uses of machine reg, requiring STG reg
516 # to be saved/restored
518 # The most dangerous "GCC uses" of an "STG reg" are when
519 # the reg holds the target of a jmp -- it's tricky to
520 # insert the patch-up code before we get to the target!
521 # So here we change the jmps:
523 # --------------------------------------------------------
524 # it can happen that we have jumps of the form...
525 # jmp *<something involving %esp>
527 # jmp <something involving another naughty register...>
529 # a reasonably-common case is:
531 # movl $_blah,<bad-reg>
534 # which is easily fixed as:
536 # sigh! try to hack around it...
539 if ($StolenX86Regs <= 2 ) { # YURGH! spurious uses of esi?
540 s/^\tmovl (.*),\%esi\n\tjmp \*%esi\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
541 s/^\tjmp \*(-?\d*)\((.*\%esi.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
542 s/^\tjmp \*\%esi\n/\tmovl \%esi,\%eax\n\tjmp \*\%eax\n/g;
543 die "$Pgm: (mangler) still have jump involving \%esi!\n$_"
544 if /(jmp|call) .*\%esi/;
546 if ($StolenX86Regs <= 3 ) { # spurious uses of edi?
547 s/^\tmovl (.*),\%edi\n\tjmp \*%edi\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
548 s/^\tjmp \*(-?\d*)\((.*\%edi.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
549 s/^\tjmp \*\%edi\n/\tmovl \%edi,\%eax\n\tjmp \*\%eax\n/g;
550 die "$Pgm: (mangler) still have jump involving \%edi!\n$_"
551 if /(jmp|call) .*\%edi/;
553 #= if ($StolenX86Regs <= 4 ) { # spurious uses of ecx?
554 #= s/^\tmovl (.*),\%ecx\n\tjmp \*%ecx\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
555 #= s/^\tjmp \*(-?\d*)\((.*\%ecx.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
556 #= s/^\tjmp \*\%ecx\n/\tmovl \%ecx,\%eax\n\tjmp \*\%eax\n/g;
557 #= die "$Pgm: (mangler) still have jump involving \%ecx!\n$_"
558 #= if /(jmp|call) .*\%ecx/;
561 # OK, now we can decide what our patch-up code is going to
563 if ( $StolenX86Regs <= 2
564 && ( /32\(\%ebx\)/ || /\%esi/ || /^\tcmps/ ) ) { # R1 (esi)
565 $entry_patch .= "\tmovl \%esi,32(\%ebx)\n";
566 $exit_patch .= "\tmovl 32(\%ebx),\%esi\n";
567 # nothing for call_{entry,exit} because %esi is callee-save
569 if ( $StolenX86Regs <= 3
570 && ( /64\(\%ebx\)/ || /\%edi/ || /^\t(scas|cmps)/ ) ) { # SpA (edi)
571 $entry_patch .= "\tmovl \%edi,64(\%ebx)\n";
572 $exit_patch .= "\tmovl 64(\%ebx),\%edi\n";
573 # nothing for call_{entry,exit} because %edi is callee-save
575 #= if ( $StolenX86Regs <= 4
576 #= && ( /80\(\%ebx\)/ || /\%ecx/ || /^\t(rep|loop)/ ) ) { # Hp (ecx)
577 #= $entry_patch .= "\tmovl \%ecx,80(\%ebx)\n";
578 #= $exit_patch .= "\tmovl 80(\%ebx),\%ecx\n";
580 #= $call_exit_patch .= "\tmovl \%ecx,108(\%ebx)\n";
581 #= $call_entry_patch .= "\tmovl 108(\%ebx),\%ecx\n";
582 #= # I have a really bad feeling about this if we ever
583 #= # have a nested call...
584 #= # NB: should just hide it somewhere in the C stack.
586 # --------------------------------------------------------
587 # next, here we go with non-%esp patching!
589 s/^(\t[a-z])/$entry_patch$1/; # before first instruction
590 s/^(\tcall .*\n(\taddl \$\d+,\%esp\n)?)/$call_exit_patch$1$call_entry_patch/g; # _all_ calls
592 # fix _all_ non-local jumps:
594 s/^\tjmp \*${T_PRE_LLBL_PAT}/\tJMP___SL/go;
595 s/^\tjmp ${T_PRE_LLBL_PAT}/\tJMP___L/go;
597 s/^(\tjmp .*\n)/$exit_patch$1/g; # here's the fix...
599 s/^\tJMP___SL/\tjmp \*${T_PRE_LLBL}/go;
600 s/^\tJMP___L/\tjmp ${T_PRE_LLBL}/go;
602 # fix post-PerformGC wrapper (re-)entries ???
604 if ($StolenX86Regs == 2 ) {
605 die "ARGH! Jump uses \%esi or \%edi with -monly-2-regs:\n$_"
606 if /^\t(jmp|call) .*\%e(si|di)/;
607 #= die "ARGH! Jump uses \%esi, \%edi, or \%ecx with -monly-2-regs:\n$_"
608 #= if /^\t(jmp|call) .*\%e(si|di|cx)/;
609 } elsif ($StolenX86Regs == 3 ) {
610 die "ARGH! Jump uses \%edi with -monly-3-regs:\n$_"
611 if /^\t(jmp|call) .*\%edi/;
612 #= die "ARGH! Jump uses \%edi or \%ecx with -monly-3-regs:\n$_"
613 #= if /^\t(jmp|call) .*\%e(di|cx)/;
614 #= } elsif ($StolenX86Regs == 4 ) {
615 #= die "ARGH! Jump uses \%ecx with -monly-4-regs:\n$_"
616 #= if /^\t(jmp|call) .*\%ecx/;
621 s/^\tmovl \%eax,36\(\%ebx\)\n\tjmp \*36\(\%ebx\)\n/\tmovl \%eax,36\(\%ebx\)\n\tjmp \*\%eax\n/;
623 # --------------------------------------------------------
624 # that's it -- print it
626 die "Funny jumps?\n$_" if /${T_X86_BADJMP}/o; # paranoia
630 if ( $need_fallthru_patch ) { # exit patch for end of slow entry code
631 print OUTASM $exit_patch;
632 # ToDo: make it not print if there is a "jmp" at the end
638 sub init_FUNNY_THINGS {
639 %KNOWN_FUNNY_THING = (
640 "${T_US}CheckHeapCode${T_POST_LBL}", 1,
641 "${T_US}CommonUnderflow${T_POST_LBL}", 1,
642 "${T_US}Continue${T_POST_LBL}", 1,
643 "${T_US}EnterNodeCode${T_POST_LBL}", 1,
644 "${T_US}ErrorIO_call_count${T_POST_LBL}", 1,
645 "${T_US}ErrorIO_innards${T_POST_LBL}", 1,
646 "${T_US}IndUpdRetDir${T_POST_LBL}", 1,
647 "${T_US}IndUpdRetV0${T_POST_LBL}", 1,
648 "${T_US}IndUpdRetV1${T_POST_LBL}", 1,
649 "${T_US}IndUpdRetV2${T_POST_LBL}", 1,
650 "${T_US}IndUpdRetV3${T_POST_LBL}", 1,
651 "${T_US}IndUpdRetV4${T_POST_LBL}", 1,
652 "${T_US}IndUpdRetV5${T_POST_LBL}", 1,
653 "${T_US}IndUpdRetV6${T_POST_LBL}", 1,
654 "${T_US}IndUpdRetV7${T_POST_LBL}", 1,
655 "${T_US}PrimUnderflow${T_POST_LBL}", 1,
656 "${T_US}StackUnderflowEnterNode${T_POST_LBL}", 1,
657 "${T_US}StdErrorCode${T_POST_LBL}", 1,
658 "${T_US}UnderflowVect0${T_POST_LBL}", 1,
659 "${T_US}UnderflowVect1${T_POST_LBL}", 1,
660 "${T_US}UnderflowVect2${T_POST_LBL}", 1,
661 "${T_US}UnderflowVect3${T_POST_LBL}", 1,
662 "${T_US}UnderflowVect4${T_POST_LBL}", 1,
663 "${T_US}UnderflowVect5${T_POST_LBL}", 1,
664 "${T_US}UnderflowVect6${T_POST_LBL}", 1,
665 "${T_US}UnderflowVect7${T_POST_LBL}", 1,
666 "${T_US}UpdErr${T_POST_LBL}", 1,
667 "${T_US}UpdatePAP${T_POST_LBL}", 1,
668 "${T_US}WorldStateToken${T_POST_LBL}", 1,
669 "${T_US}_Enter_Internal${T_POST_LBL}", 1,
670 "${T_US}_PRMarking_MarkNextAStack${T_POST_LBL}", 1,
671 "${T_US}_PRMarking_MarkNextBStack${T_POST_LBL}", 1,
672 "${T_US}_PRMarking_MarkNextCAF${T_POST_LBL}", 1,
673 "${T_US}_PRMarking_MarkNextGA${T_POST_LBL}", 1,
674 "${T_US}_PRMarking_MarkNextRoot${T_POST_LBL}", 1,
675 "${T_US}_PRMarking_MarkNextSpark${T_POST_LBL}", 1,
676 "${T_US}_Scavenge_Forward_Ref${T_POST_LBL}", 1,
677 "${T_US}__std_entry_error__${T_POST_LBL}", 1,
678 "${T_US}_startMarkWorld${T_POST_LBL}", 1,
679 "${T_US}resumeThread${T_POST_LBL}", 1,
680 "${T_US}startCcRegisteringWorld${T_POST_LBL}", 1,
681 "${T_US}startEnterFloat${T_POST_LBL}", 1,
682 "${T_US}startEnterInt${T_POST_LBL}", 1,
683 "${T_US}startPerformIO${T_POST_LBL}", 1,
684 "${T_US}startStgWorld${T_POST_LBL}", 1,
685 "${T_US}stopPerformIO${T_POST_LBL}", 1
690 The following table reversal is used for both info tables and return
691 vectors. In both cases, we remove the first entry from the table,
692 reverse the table, put the label at the end, and paste some code
693 (that which is normally referred to by the first entry in the table)
694 right after the table itself. (The code pasting is done elsewhere.)
698 local($symb, $tbl, $discard1) = @_;
704 local(@lines) = split(/\n/, $tbl);
705 local($i, $extra, $words_to_pad, $j);
707 for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.long\s+/; $i++) {
708 $label .= $lines[$i] . "\n",
709 next if $lines[$i] =~ /^[A-Za-z0-9_]+_info:$/
710 || $lines[$i] =~ /^\.globl/
711 || $lines[$i] =~ /^${T_US}vtbl_\S+:$/;
713 $before .= $lines[$i] . "\n"; # otherwise...
716 for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.long\s+/; $i++) {
717 push(@words, $lines[$i]);
719 # now throw away the first word (entry code):
720 shift(@words) if $discard1;
722 # for 486-cache-friendliness, we want our tables aligned
723 # on 16-byte boundaries (.align 4). Let's pad:
724 $extra = ($#words + 1) % 4;
725 $words_to_pad = ($extra == 0) ? 0 : 4 - $extra;
726 for ($j = 0; $j < $words_to_pad; $j++) { push(@words, "\t\.long 0"); }
728 for (; $i <= $#lines; $i++) {
729 $after .= $lines[$i] . "\n";
732 $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after;
734 # print STDERR "before=$before\n";
735 # print STDERR "label=$label\n";
736 # print STDERR "words=",(reverse @words),"\n";
737 # print STDERR "after=$after\n";
744 sub mini_mangle_asm {
745 local($in_asmf, $out_asmf) = @_;
747 &init_TARGET_STUFF();
749 open(INASM, "< $in_asmf")
750 || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
751 open(OUTASM,"> $out_asmf")
752 || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
758 /^${T_US}(PerformGC|StackOverflow|Yield|PerformReschedule)_wrapper${T_POST_LBL}\n/o;
759 print OUTASM "\tmovl \%esp, ${T_US}__temp_esp\n";
760 print OUTASM "\tmovl \%eax, ${T_US}__temp_eax\n";
764 close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
765 close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
768 # make "require"r happy...