Fix the splitter with perl 5.10; patch from Audrey Tang
[ghc-hetmet.git] / driver / split / ghc-split.lprl
1 %************************************************************************
2 %*                                                                      *
3 \section[Driver-obj-splitting]{Splitting into many \tr{.o} files (for libraries)}
4 %*                                                                      *
5 %************************************************************************
6
7 \begin{code}
8 $TargetPlatform = $TARGETPLATFORM;
9
10 ($Pgm = $0) =~ s|.*/||;
11 $ifile      = $ARGV[0];
12 $Tmp_prefix = $ARGV[1];
13 $Output     = $ARGV[2];
14
15 &split_asm_file($ifile);
16
17 open(OUTPUT, "> $Output") ||  &tidy_up_and_die(1,"$Pgm: failed to open `$Output' (to write)\n");
18 print OUTPUT "$NoOfSplitFiles\n";
19 close(OUTPUT);
20
21 exit(0);
22 \end{code}
23
24
25 \begin{code}
26 sub split_asm_file {
27     local($asm_file) = @_;
28     my @pieces = ();
29
30     open(TMPI, "< $asm_file") || &tidy_up_and_die(1,"$Pgm: failed to open `$asm_file' (to read)\n");
31
32     &collectExports_hppa() if $TargetPlatform =~ /^hppa/;
33     &collectExports_mips() if $TargetPlatform =~ /^mips/;
34     &collectDyldStuff_darwin() if $TargetPlatform =~ /-apple-darwin/;
35
36     $octr = 0;  # output file counter
37
38     %LocalConstant = (); # we have to subvert C compiler's commoning-up of constants...
39
40     $s_stuff = &ReadTMPIUpToAMarker( '', $octr );
41     # that first stuff is a prologue for all .s outputs
42     $prologue_stuff = &process_asm_block ( $s_stuff );
43     # $_ already has some of the next stuff in it...
44
45 #   &tidy_up_and_die(1,"$Pgm: no split markers in .s file!\n")
46 #       if $prologue_stuff eq $s_stuff;
47
48     # lie about where this stuff came from
49     # Note the \Q: this ignores regex meta-chars in $Tmp_prefix.
50     $prologue_stuff =~ s/\Q"$Tmp_prefix.c"/"$ifile_root.hc"/gm;
51
52     while ( $_ ne '' ) { # not EOF
53         $octr++;
54
55         # grab and de-mangle a section of the .s file...
56         $s_stuff = &ReadTMPIUpToAMarker ( $_, $octr );
57         $pieces[$octr] = &process_asm_block ( $s_stuff );
58     }
59
60     # Make sure that we still have some output when the input file is empty
61     if ($octr == 0) {
62         $octr = 1;
63         $pieces[$octr] = '';
64     }
65
66     $NoOfSplitFiles = $octr;
67
68     if ($pieces[$NoOfSplitFiles] =~ /(\n[ \t]*\.section[ \t]+\.note\.GNU-stack,[^\n]*\n)/m) {
69         $note_gnu_stack = $1;
70         for $octr (1..($NoOfSplitFiles - 1)) {
71             $pieces[$octr] .= $note_gnu_stack;
72         }
73     }
74
75     for $octr (1..$NoOfSplitFiles) {
76         # output to a file of its own
77         # open a new output file...
78         $ofname = "${Tmp_prefix}__${octr}.s";
79         open(OUTF, "> $ofname") || die "$Pgm: can't open output file: $ofname\n";
80
81         print OUTF $prologue_stuff;
82         print OUTF $pieces[$octr];
83
84         close(OUTF)
85           || &tidy_up_and_die(1,"$Pgm:Failed writing ${Tmp_prefix}__${octr}.s\n");
86     }
87
88     close(TMPI) || &tidy_up_and_die(1,"Failed reading $asm_file\n");
89 }
90
91 sub collectExports_hppa { # Note: HP-PA only
92
93     %LocalExport = (); # NB: global table
94
95     while(<TMPI>) {
96         if (/^\s+\.EXPORT\s+([^,]+),.*\n/m) {
97             local($label) = $1;
98             local($body)  = "\t.IMPORT $label";
99             if (/,DATA/m) { 
100                 $body .= ",DATA\n"; 
101             } else { 
102                 $body .= ",CODE\n"; 
103             }
104             $label =~ s/\$/\\\$/gm;
105             $LocalExport{$label} = $body;
106         }
107     }
108
109     seek(TMPI, 0, 0);
110 }
111
112 sub collectExports_mips { # Note: MIPS only
113     # (not really sure this is necessary [WDP 95/05])
114
115     $UNDEFINED_FUNS = ''; # NB: global table
116
117     while(<TMPI>) {
118         $UNDEFINED_FUNS .= $_ if /^\t\.globl\s+\S+ \.\S+\n/m;
119         # just save 'em all
120     }
121
122     seek(TMPI, 0, 0);
123 }
124
125 sub collectDyldStuff_darwin {
126     local($chunk_label,$label,$cur_section,$section,$chunk,$alignment,$cur_alignment);
127     
128     %DyldChunks = (); # NB: global table
129     %DyldChunksDefined = (); # NB: global table
130         
131     $cur_section = '';
132     $section = '';
133     $label = '';
134     $chunk = '';
135     $alignment = '';
136     $cur_alignment = '';
137     
138     while ( 1 ) {
139         $_ = <TMPI>;
140         if ( $_ eq '' || (/^L(_.+)\$.+:/m && !(/^L(.*)\$stub_binder:/m))) {
141             if ( $label ne '' ) {
142                 $DyldChunksDefined{$label} .= $section . $alignment . $chunk_label . $ chunk;
143                 if( $section =~ s/\.data/\.non_lazy_symbol_pointer/m ) {
144                     $chunk = "\t.indirect_symbol $label\n\t.long 0\n";
145                 }
146                 $DyldChunks{$label} .= $section . $alignment . $chunk_label . $chunk;
147                 print STDERR "### dyld chunk: $label\n$section$alignment$chunk\n###\n" if $Dump_asm_splitting_info;
148             }
149             last if ($_ eq '');
150                 
151             $chunk = '';
152             $chunk_label = $_;
153             $label = $1;
154             $section = $cur_section;
155             $alignment = $cur_alignment;
156             print STDERR "label: $label\n" if $Dump_asm_splitting_info;
157         } elsif ( /^\s*\.(symbol_stub|picsymbol_stub|lazy_symbol_pointer|non_lazy_symbol_pointer|data|section __IMPORT,.*|section __DATA, __la_sym_ptr(2|3),lazy_symbol_pointers)/m ) {
158             $cur_section = $_;
159             printf STDERR "section: $cur_section\n" if $Dump_asm_splitting_info;
160             $cur_alignment = ''
161         } elsif ( /^\s*\.section\s+__TEXT,__symbol_stub1,symbol_stubs,pure_instructions,\d+/m ) {
162             $cur_section = $_;
163             printf STDERR "section: $cur_section\n" if $Dump_asm_splitting_info;
164                 # always make sure we align things
165             $cur_alignment = '\t.align 2'
166         } elsif ( /^\s*\.align.*/m ) { 
167             $cur_alignment = $_;
168             printf STDERR "alignment: $cur_alignment\n" if $Dump_asm_splitting_info;
169         } else {
170             $chunk .= $_;
171         }
172     }
173     
174     seek(TMPI, 0, 0);
175 }
176
177 sub ReadTMPIUpToAMarker {
178     local($str, $count) = @_; # already read bits
179
180     
181     for ( $_ = <TMPI>; $_ ne '' && ! /_?__stg_split_marker/m; $_ = <TMPI> ) {
182         $str .= $_;
183     }
184     # if not EOF, then creep forward until next "real" line
185     # (throwing everything away).
186     # that first "real" line will stay in $_.
187
188     # This loop is intended to pick up the body of the split_marker function
189     # Note that the assembler mangler will already have eliminated this code
190     # if it's been invoked (which it probably has).
191
192     while ($_ ne '' && (/_?__stg_split_marker/m
193                      || /^L[^C].*:$/m
194                      || /^\.stab/m
195                      || /\t\.proc/m
196                      || /\t\.stabd/m
197                      || /\t\.even/m
198                      || /\tunlk a6/m
199                      || /^\t!#PROLOGUE/m
200                      || /\t\.prologue/m
201                      || /\t\.frame/m
202                      # || /\t\.end/ NOT!  Let the split_marker regexp catch it
203                      # || /\t\.ent/ NOT!  Let the split_marker regexp catch it
204                      || /^\s+(save|retl?|restore|nop)/m)) {
205         $_ = <TMPI>;
206     }
207
208     print STDERR "### BLOCK:$count:\n$str" if $Dump_asm_splitting_info;
209
210     # return str
211     $str =~ tr/\r//d if $TargetPlatform =~ /-mingw32$/m; # in case Perl doesn't convert line endings
212     $str;
213 }
214 \end{code}
215
216 We must (a)~strip the marker off the block, (b)~record any literal C
217 constants that are defined here, and (c)~inject copies of any C constants
218 that are used-but-not-defined here.
219
220 \begin{code}
221 sub process_asm_block {
222     local($str) = @_;
223
224     return(&process_asm_block_darwin($str))
225                             if $TargetPlatform =~ /-apple-darwin/m;
226     return(&process_asm_block_m68k($str))  if $TargetPlatform =~ /^m68k-/m;
227     return(&process_asm_block_sparc($str)) if $TargetPlatform =~ /^sparc-/m;
228     return(&process_asm_block_iX86($str))  if $TargetPlatform =~ /^i[34]86-/m;
229     return(&process_asm_block_x86_64($str))  if $TargetPlatform =~ /^x86_64-/m;
230     return(&process_asm_block_alpha($str)) if $TargetPlatform =~ /^alpha-/m;
231     return(&process_asm_block_hppa($str))  if $TargetPlatform =~ /^hppa/m;
232     return(&process_asm_block_mips($str))   if $TargetPlatform =~ /^mips-/m;
233     return(&process_asm_block_powerpc_linux($str))
234                             if $TargetPlatform =~ /^powerpc-[^-]+-linux/m;
235
236     # otherwise...
237     &tidy_up_and_die(1,"$Pgm: no process_asm_block for $TargetPlatform\n");
238 }
239
240 sub process_asm_block_sparc {
241     local($str) = @_;
242
243     # strip the marker
244     if ( $OptimiseC ) {
245         $str =~ s/_?__stg_split_marker.*:\n//m;
246     } else {
247         $str =~ s/(\.text\n\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/m;
248         $str =~ s/(\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/m;
249     }
250
251     # make sure the *.hc filename gets saved; not just ghc*.c (temp name)
252     $str =~ s/^\.stabs "(ghc\d+\.c)"/.stabs "$ifile_root.hc"/gm; # HACK HACK
253
254     # remove/record any literal constants defined here
255     while ( $str =~ /(\t\.align .\n\.?(L?LC\d+):\n(\t\.asci[iz].*\n)+)/m ) {
256         local($label) = $2;
257         local($body)  = $1;
258
259         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
260             if $LocalConstant{$label};
261
262         $LocalConstant{$label} = $body;
263         
264         $str =~ s/\t\.align .\n\.?LL?C\d+:\n(\t\.asci[iz].*\n)+//m;
265     }
266
267     # inject definitions for any local constants now used herein
268     foreach $k (keys %LocalConstant) {
269         if ( $str =~ /\b$k\b/m ) {
270             $str = $LocalConstant{$k} . $str;
271         }
272     }
273
274    print STDERR "### STRIPPED BLOCK (sparc):\n$str" if $Dump_asm_splitting_info;
275
276    $str;
277 }
278
279 sub process_asm_block_m68k {
280     local($str) = @_;
281
282     # strip the marker
283
284     $str =~ s/(\.text\n\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/m;
285     $str =~ s/(\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/m;
286
287     # it seems prudent to stick on one of these:
288     $str = "\.text\n\t.even\n" . $str;
289
290     # remove/record any literal constants defined here
291     while ( $str =~ /((LC\d+):\n\t\.ascii.*\n)/m ) {
292         local($label) = $2;
293         local($body)  = $1;
294
295         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
296             if $LocalConstant{$label};
297
298         $LocalConstant{$label} = $body;
299         
300         $str =~ s/LC\d+:\n\t\.ascii.*\n//m;
301     }
302
303     # inject definitions for any local constants now used herein
304     foreach $k (keys %LocalConstant) {
305         if ( $str =~ /\b$k\b/m ) {
306             $str = $LocalConstant{$k} . $str;
307         }
308     }
309
310    print STDERR "### STRIPPED BLOCK (m68k):\n$str" if $Dump_asm_splitting_info;
311
312    $str;
313 }
314
315 sub process_asm_block_alpha {
316     local($str) = @_;
317
318     # strip the marker
319     if ( $OptimiseC ) {
320         $str =~ s/_?__stg_split_marker.*:\n//m;
321     } else {
322         $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/m;
323     }
324
325     # remove/record any literal constants defined here
326     while ( $str =~ /(\.rdata\n\t\.align \d\n)?(\$(C\d+):\n\t\..*\n)/m ) {
327         local($label) = $3;
328         local($body)  = $2;
329
330         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
331             if $LocalConstant{$label};
332
333         $LocalConstant{$label} = ".rdata\n\t.align 3\n" . $body . "\t.text\n";
334         
335         $str =~ s/(\.rdata\n\t\.align \d\n)?\$C\d+:\n\t\..*\n//m;
336     }
337
338     # inject definitions for any local constants now used herein
339     foreach $k (keys %LocalConstant) {
340         if ( $str =~ /\$\b$k\b/m ) {
341             $str = $LocalConstant{$k} . $str;
342         }
343     }
344
345     # Slide the dummy direct return code into the vtbl .ent/.end block,
346     # to keep the label fixed if it's the last thing in a module, and
347     # to avoid having any anonymous text that the linker will complain about
348     $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/gm;
349
350     print STDERR "### STRIPPED BLOCK (alpha):\n$str" if $Dump_asm_splitting_info;
351
352     $str;
353 }
354
355 sub process_asm_block_iX86 {
356     local($str) = @_;
357
358     # strip the marker
359
360     $str =~ s/(\.text\n\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/m;
361     $str =~ s/(\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/m;
362
363     # it seems prudent to stick on one of these:
364     $str = "\.text\n\t.align 4\n" . $str;
365
366     # remove/record any literal constants defined here
367     # [perl made uglier to work around the perl 5.7/5.8 bug documented at
368     # http://bugs6.perl.org/rt2/Ticket/Display.html?id=1760 and illustrated
369     # by the seg fault of perl -e '("x\n" x 5000) =~ /(.*\n)+/'
370     # -- ccshan 2002-09-05]
371     while ( ($str =~ /((?:^|\.)(LC\d+):\n(\t\.(ascii|string).*\n|\s*\.byte.*\n){1,100})/m )) {
372         local($label) = $2;
373         local($body)  = $1;
374         local($prefix, $suffix) = ($`, $');
375
376         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
377             if $LocalConstant{$label};
378
379         while ( $suffix =~ /^((\t\.(ascii|string).*\n|\s*\.byte.*\n){1,100})/ ) {
380             $body .= $1;
381             $suffix = $';
382         }
383         $LocalConstant{$label} = $body;
384         $str = $prefix . $suffix;
385     }
386
387     # inject definitions for any local constants now used herein
388     foreach $k (keys %LocalConstant) {
389         if ( $str =~ /\b$k\b/m ) {
390             $str = $LocalConstant{$k} . $str;
391         }
392     }
393
394    print STDERR "### STRIPPED BLOCK (iX86):\n$str" if $Dump_asm_splitting_info;
395
396    $str;
397 }
398 \end{code}
399
400 \begin{code}
401 sub process_asm_block_x86_64 {
402     local($str) = @_;
403
404     # remove/record any literal constants defined here
405     # [perl made uglier to work around the perl 5.7/5.8 bug documented at
406     # http://bugs6.perl.org/rt2/Ticket/Display.html?id=1760 and illustrated
407     # by the seg fault of perl -e '("x\n" x 5000) =~ /(.*\n)+/'
408     # -- ccshan 2002-09-05]
409     while ( ($str =~ /((?:^|\.)(LC\d+):\n(\t\.(ascii|string).*\n|\s*\.byte.*\n){1,100})/m )) {
410         local($label) = $2;
411         local($body)  = $1;
412         local($prefix, $suffix) = ($`, $');
413
414         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
415             if $LocalConstant{$label};
416
417         while ( $suffix =~ /^((\t\.(ascii|string).*\n|\s*\.byte.*\n){1,100})/ ) {
418             $body .= $1;
419             $suffix = $';
420         }
421         $LocalConstant{$label} = $body;
422         $str = $prefix . $suffix;
423     }
424
425     # inject definitions for any local constants now used herein
426     foreach $k (keys %LocalConstant) {
427         if ( $str =~ /\b$k\b/m ) {
428             $str = $LocalConstant{$k} . $str;
429         }
430     }
431
432    print STDERR "### STRIPPED BLOCK (x86_64):\n$str" if $Dump_asm_splitting_info;
433
434    $str;
435 }
436 \end{code}
437
438 \begin{code}
439 sub process_asm_block_hppa {
440     local($str) = @_;
441
442     # strip the marker
443     $str =~ s/___stg_split_marker.*\n//m;
444
445     # remove/record any imports defined here
446     while ( $str =~ /^(\s+\.IMPORT\s.*\n)/m ) {
447         $Imports .= $1;
448
449         $str =~ s/^\s+\.IMPORT.*\n//m;
450     }
451
452     # remove/record any literal constants defined here
453     while ( $str =~ /^(\s+\.align.*\n(L\$C\d+)\n(\s.*\n)+); end literal\n/m ) {
454         local($label) = $2;
455         local($body)  = $1;
456         local($prefix) = $`;
457         local($suffix) = $';
458         $label =~ s/\$/\\\$/gm;
459
460         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
461             if $LocalConstant{$label};
462
463         $LocalConstant{$label} = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n\n" . $body;
464         
465         $str = $prefix . $suffix;
466     }
467
468     # inject definitions for any local constants now used herein
469     foreach $k (keys %LocalConstant) {
470         if ( $str =~ /\b$k\b/m ) {
471             $str = $LocalConstant{$k} . $str;
472         }
473     }
474
475     # inject required imports for local exports in other chunks
476     foreach $k (keys %LocalExport) {
477         if ( $str =~ /\b$k\b/m && ! /EXPORT\s+$k\b/m ) {
478             $str = $LocalExport{$k} . $str;
479         }
480     }
481
482     # inject collected imports
483
484     $str = $Imports . $str;
485
486     print STDERR "### STRIPPED BLOCK (hppa):\n$str" if $Dump_asm_splitting_info;
487
488     $str;
489 }
490 \end{code}
491
492 \begin{code}
493 sub process_asm_block_mips {
494     local($str) = @_;
495
496     # strip the marker
497     if ( $OptimiseC ) {
498         $str =~ s/_?__stg_split_marker.*:\n//m;
499     } else {
500         $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/m;
501     }
502
503     # remove/record any literal constants defined here
504     while ( $str =~ /(\t\.rdata\n\t\.align \d\n)?^(\$(LC\d+):\n(\t\.byte\t.*\n)+)/m ) {
505         local($label) = $3;
506         local($body)  = $2;
507
508         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
509             if $LocalConstant{$label};
510
511         $LocalConstant{$label} = "\t.rdata\n\t.align 2\n" . $body . "\t.text\n";
512         
513         $str =~ s/(\t\.rdata\n\t\.align \d\n)?\$LC\d+:\n(\t\.byte\t.*\n)+//m;
514     }
515
516     # inject definitions for any local constants now used herein
517     foreach $k (keys %LocalConstant) {
518         if ( $str =~ /\$\b$k\b/m ) {
519             $str = $LocalConstant{$k} . $str;
520         }
521     }
522
523     # Slide the dummy direct return code into the vtbl .ent/.end block,
524     # to keep the label fixed if it's the last thing in a module, and
525     # to avoid having any anonymous text that the linker will complain about
526     $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/gm;
527
528     $str .= $UNDEFINED_FUNS; # pin on gratuitiously-large amount of info
529
530     print STDERR "### STRIPPED BLOCK (mips):\n$str" if $Dump_asm_splitting_info;
531
532     $str;
533 }
534 \end{code}
535
536 \begin{code}
537 # The logic for both Darwin/PowerPC and Darwin/x86 ends up being the same.
538
539 sub process_asm_block_darwin {
540     local($str) = @_;
541     local($dyld_stuff) = '';
542
543     # strip the marker
544     $str =~ s/___stg_split_marker.*\n//m;
545
546     $str =~ s/L_.*\$.*:\n(.|\n)*//m;
547
548     # remove/record any literal constants defined here
549     while ( $str =~ s/^(\s+.const.*\n\s+\.align.*\n(LC\d+):\n(\s\.(byte|short|long|fill|space|ascii).*\n)+)//m ) {
550         local($label) = $2;
551         local($body)  = $1;
552
553         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
554             if $LocalConstant{$label};
555
556         $LocalConstant{$label} = $body;
557     }
558
559     # inject definitions for any local constants now used herein
560     foreach $k (keys %LocalConstant) {
561         if ( $str =~ /\b$k(\b|\[)/m ) {
562             $str = $LocalConstant{$k} . $str;
563         }
564     }
565     
566     foreach $k (keys %DyldChunks) {
567         if ( $str =~ /\bL$k\$/m ) {
568             if ( $str =~ /^$k:$/m ) {
569                 $dyld_stuff .= $DyldChunksDefined{$k};
570             } else {
571                 $dyld_stuff .= $DyldChunks{$k};
572             }
573         }
574     }
575
576     $str .= "\n" . $dyld_stuff;
577
578     print STDERR "### STRIPPED BLOCK (darwin):\n$str" if $Dump_asm_splitting_info;
579
580     $str;
581 }
582 \end{code}
583
584 \begin{code}
585 sub process_asm_block_powerpc_linux {
586     local($str) = @_;
587
588     # strip the marker
589     $str =~ s/__stg_split_marker.*\n//m;
590
591     # remove/record any literal constants defined here
592     while ( $str =~ s/^(\s+.section\s+\.rodata\n\s+\.align.*\n(\.LC\d+):\n(\s\.(byte|short|long|quad|2byte|4byte|8byte|fill|space|ascii|string).*\n)+)//m ) {
593         local($label) = $2;
594         local($body)  = $1;
595
596         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
597             if $LocalConstant{$label};
598
599         $LocalConstant{$label} = $body;
600     }
601
602     # inject definitions for any local constants now used herein
603     foreach $k (keys %LocalConstant) {
604         if ( $str =~ /[\s,]$k\b/m ) {
605             $str = $LocalConstant{$k} . $str;
606         }
607     }
608     
609     print STDERR "### STRIPPED BLOCK (powerpc linux):\n$str" if $Dump_asm_splitting_info;
610
611     $str;
612 }
613 \end{code}
614
615 \begin{code}
616 sub tidy_up_and_die {
617     local($return_val, $msg) = @_;
618     print STDERR $msg;
619     exit (($return_val == 0) ? 0 : 1);
620 }
621 \end{code}