1 %************************************************************************
3 \section[Driver-obj-splitting]{Splitting into many \tr{.o} files (for libraries)}
5 %************************************************************************
11 open(TMPI, "< $asm_file") || &tidy_up_and_die(1,"$Pgm: failed to open `$asm_file' (to read)\n");
13 &collectExports_hppa() if $TargetPlatform =~ /^hppa/;
14 &collectExports_mips() if $TargetPlatform =~ /^mips/;
16 $octr = 0; # output file counter
17 $* = 1; # multi-line matches are OK
19 %LocalConstant = (); # we have to subvert C compiler's commoning-up of constants...
21 $s_stuff = &ReadTMPIUpToAMarker( '', $octr );
22 # that first stuff is a prologue for all .s outputs
23 $prologue_stuff = &process_asm_block ( $s_stuff );
24 # $_ already has some of the next stuff in it...
26 # &tidy_up_and_die(1,"$Pgm: no split markers in .s file!\n")
27 # if $prologue_stuff eq $s_stuff;
29 # lie about where this stuff came from
30 $prologue_stuff =~ s|"/tmp/ghc\d+\.c"|"$ifile_root\.hc"|g;
32 while ( $_ ne '' ) { # not EOF
35 # grab and de-mangle a section of the .s file...
36 $s_stuff = &ReadTMPIUpToAMarker ( $_, $octr );
37 $this_piece = &process_asm_block ( $s_stuff );
39 # output to a file of its own
40 # open a new output file...
41 $ofname = "${Tmp_prefix}__${octr}.s";
42 open(OUTF, "> $ofname") || die "$Pgm: can't open output file: $ofname\n";
44 print OUTF $prologue_stuff;
45 print OUTF $this_piece;
48 || &tidy_up_and_die(1,"$Pgm:Failed writing ${Tmp_prefix}__${octr}.s\n");
51 $NoOfSplitFiles = $octr;
53 close(TMPI) || &tidy_up_and_die(1,"Failed reading $asm_file\n");
56 sub collectExports_hppa { # Note: HP-PA only
58 %LocalExport = (); # NB: global table
61 if (/^\s+\.EXPORT\s+([^,]+),.*\n/) {
63 local($body) = "\t.IMPORT $label";
69 $label =~ s/\$/\\\$/g;
70 $LocalExport{$label} = $body;
77 sub collectExports_mips { # Note: MIPS only
78 # (not really sure this is necessary [WDP 95/05])
80 $UNDEFINED_FUNS = ''; # NB: global table
83 $UNDEFINED_FUNS .= $_ if /^\t\.globl\s+\S+ \.\S+\n/;
90 sub ReadTMPIUpToAMarker {
91 local($str, $count) = @_; # already read bits
94 for ( $_ = <TMPI>; $_ ne '' && ! /_?__stg_split_marker/; $_ = <TMPI> ) {
97 # if not EOF, then creep forward until next "real" line
98 # (throwing everything away).
99 # that first "real" line will stay in $_.
101 # This loop is intended to pick up the body of the split_marker function
102 # Note that the assembler mangler will already have eliminated this code
103 # if it's been invoked (which it probably has).
105 while ($_ ne '' && (/_?__stg_split_marker/
115 # || /\t\.end/ NOT! Let the split_marker regexp catch it
116 # || /\t\.ent/ NOT! Let the split_marker regexp catch it
117 || /^\s+(save|retl?|restore|nop)/)) {
121 print STDERR "### BLOCK:$count:\n$str" if $Dump_asm_splitting_info;
128 We must (a)~strip the marker off the block, (b)~record any literal C
129 constants that are defined here, and (c)~inject copies of any C constants
130 that are used-but-not-defined here.
133 sub process_asm_block {
136 return(&process_asm_block_m68k($str)) if $TargetPlatform =~ /^m68k-/;
137 return(&process_asm_block_sparc($str)) if $TargetPlatform =~ /^sparc-/;
138 return(&process_asm_block_iX86($str)) if $TargetPlatform =~ /^i[34]86-/;
139 return(&process_asm_block_alpha($str)) if $TargetPlatform =~ /^alpha-/;
140 return(&process_asm_block_hppa($str)) if $TargetPlatform =~ /^hppa/;
141 return(&process_asm_block_mips($str)) if $TargetPlatform =~ /^mips-/;
142 return(&process_asm_block_powerpc($str)) if $TargetPlatform =~ /^powerpc-|^rs6000-/;
145 &tidy_up_and_die(1,"$Pgm: no process_asm_block for $TargetPlatform\n");
148 sub process_asm_block_sparc {
153 $str =~ s/_?__stg_split_marker.*:\n//;
155 $str =~ s/(\.text\n\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/;
156 $str =~ s/(\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/;
159 # make sure the *.hc filename gets saved; not just ghc*.c (temp name)
160 $str =~ s/^\.stabs "(ghc\d+\.c)"/.stabs "$ifile_root.hc"/g; # HACK HACK
162 # remove/record any literal constants defined here
163 while ( $str =~ /(\t\.align .\n\.?(L?LC\d+):\n(\t\.asci[iz].*\n)+)/ ) {
167 &tidy_up_and_die(1,"Local constant label $label already defined!\n")
168 if $LocalConstant{$label};
170 $LocalConstant{$label} = $body;
172 $str =~ s/\t\.align .\n\.?LL?C\d+:\n(\t\.asci[iz].*\n)+//;
175 # inject definitions for any local constants now used herein
176 foreach $k (keys %LocalConstant) {
177 if ( $str =~ /\b$k\b/ ) {
178 $str = $LocalConstant{$k} . $str;
182 print STDERR "### STRIPPED BLOCK (sparc):\n$str" if $Dump_asm_splitting_info;
187 sub process_asm_block_m68k {
192 $str =~ s/(\.text\n\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/;
193 $str =~ s/(\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/;
195 # it seems prudent to stick on one of these:
196 $str = "\.text\n\t.even\n" . $str;
198 # remove/record any literal constants defined here
199 while ( $str =~ /((LC\d+):\n\t\.ascii.*\n)/ ) {
203 &tidy_up_and_die(1,"Local constant label $label already defined!\n")
204 if $LocalConstant{$label};
206 $LocalConstant{$label} = $body;
208 $str =~ s/LC\d+:\n\t\.ascii.*\n//;
211 # inject definitions for any local constants now used herein
212 foreach $k (keys %LocalConstant) {
213 if ( $str =~ /\b$k\b/ ) {
214 $str = $LocalConstant{$k} . $str;
218 print STDERR "### STRIPPED BLOCK (m68k):\n$str" if $Dump_asm_splitting_info;
223 sub process_asm_block_alpha {
228 $str =~ s/_?__stg_split_marker.*:\n//;
230 $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/;
233 # remove/record any literal constants defined here
234 while ( $str =~ /(\.rdata\n\t\.align \d\n)?(\$(C\d+):\n\t\..*\n)/ ) {
238 &tidy_up_and_die(1,"Local constant label $label already defined!\n")
239 if $LocalConstant{$label};
241 $LocalConstant{$label} = ".rdata\n\t.align 3\n" . $body . "\t.text\n";
243 $str =~ s/(\.rdata\n\t\.align \d\n)?\$C\d+:\n\t\..*\n//;
246 # inject definitions for any local constants now used herein
247 foreach $k (keys %LocalConstant) {
248 if ( $str =~ /\$\b$k\b/ ) {
249 $str = $LocalConstant{$k} . $str;
253 # Slide the dummy direct return code into the vtbl .ent/.end block,
254 # to keep the label fixed if it's the last thing in a module, and
255 # to avoid having any anonymous text that the linker will complain about
256 $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/g;
258 print STDERR "### STRIPPED BLOCK (alpha):\n$str" if $Dump_asm_splitting_info;
263 sub process_asm_block_iX86 {
268 $str =~ s/(\.text\n\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/;
269 $str =~ s/(\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/;
271 # it seems prudent to stick on one of these:
272 $str = "\.text\n\t.align 4\n" . $str;
274 # remove/record any literal constants defined here
275 while ( ($str =~ /(\.?(LC\d+):\n\t\.(ascii|string).*\n)/ )) {
279 &tidy_up_and_die(1,"Local constant label $label already defined!\n")
280 if $LocalConstant{$label};
282 $LocalConstant{$label} = $body;
284 $str =~ s/\.?LC\d+:\n\t\.(ascii|string).*\n//;
287 # inject definitions for any local constants now used herein
288 foreach $k (keys %LocalConstant) {
289 if ( $str =~ /\b$k\b/ ) {
290 $str = $LocalConstant{$k} . $str;
294 print STDERR "### STRIPPED BLOCK (iX86):\n$str" if $Dump_asm_splitting_info;
301 sub process_asm_block_hppa {
305 $str =~ s/___stg_split_marker.*\n//;
307 # remove/record any imports defined here
308 while ( $str =~ /^(\s+\.IMPORT\s.*\n)/ ) {
311 $str =~ s/^\s+\.IMPORT.*\n//;
314 # remove/record any literal constants defined here
315 while ( $str =~ /^(\s+\.align.*\n(L\$C\d+)\n(\s.*\n)+); end literal\n/ ) {
318 $label =~ s/\$/\\\$/g;
320 &tidy_up_and_die(1,"Local constant label $label already defined!\n")
321 if $LocalConstant{$label};
323 $LocalConstant{$label} = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n\n" . $body;
325 $str =~ s/^\s+\.SPACE \$TEXT\$\n\s+\.SUBSPA \$LIT\$\s+\.align.*\nL\$C\d+\n(\s.*\n)+; end literal\n//;
328 # inject definitions for any local constants now used herein
329 foreach $k (keys %LocalConstant) {
330 if ( $str =~ /\b$k\b/ ) {
331 $str = $LocalConstant{$k} . $str;
335 # inject required imports for local exports in other chunks
336 foreach $k (keys %LocalExport) {
337 if ( $str =~ /\b$k\b/ && ! /EXPORT\s+$k\b/ ) {
338 $str = $LocalExport{$k} . $str;
342 # inject collected imports
344 $str = $Imports . $str;
346 print STDERR "### STRIPPED BLOCK (hppa):\n$str" if $Dump_asm_splitting_info;
353 sub process_asm_block_mips {
358 $str =~ s/_?__stg_split_marker.*:\n//;
360 $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/;
363 # remove/record any literal constants defined here
364 while ( $str =~ /(\t\.rdata\n\t\.align \d\n)?(\$(LC\d+):\n(\t\.byte\t.*\n)+)/ ) {
368 &tidy_up_and_die(1,"Local constant label $label already defined!\n")
369 if $LocalConstant{$label};
371 $LocalConstant{$label} = "\t.rdata\n\t.align 2\n" . $body . "\t.text\n";
373 $str =~ s/(\t\.rdata\n\t\.align \d\n)?\$LC\d+:\n(\t\.byte\t.*\n)+//;
376 # inject definitions for any local constants now used herein
377 foreach $k (keys %LocalConstant) {
378 if ( $str =~ /\$\b$k\b/ ) {
379 $str = $LocalConstant{$k} . $str;
383 # Slide the dummy direct return code into the vtbl .ent/.end block,
384 # to keep the label fixed if it's the last thing in a module, and
385 # to avoid having any anonymous text that the linker will complain about
386 $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/g;
388 $str .= $UNDEFINED_FUNS; # pin on gratuitiously-large amount of info
390 print STDERR "### STRIPPED BLOCK (mips):\n$str" if $Dump_asm_splitting_info;
397 sub process_asm_block_powerpc {
401 $str =~ s/___stg_split_marker.*\n//;
402 $str =~ s/___stg_split_marker.*\n//; # yes, twice.
404 # remove/record any literal constants defined here
405 while ( $str =~ /^(.csect .data[RW]\n\s+\.align.*\n(LC\.\.\d+):\n(\s\.byte .*\n)+)/ ) {
409 &tidy_up_and_die(1,"Local constant label $label already defined!\n")
410 if $LocalConstant{$label};
412 $LocalConstant{$label} = $body;
414 $str =~ s/^.csect .data[RW]\n\s+\.align.*\nLC\.\.\d+:\n(\s\.byte .*\n)+//;
417 # inject definitions for any local constants now used herein
418 foreach $k (keys %LocalConstant) {
419 if ( $str =~ /\b$k(\b|\[)/ ) {
420 $str = $LocalConstant{$k} . $str;
424 print STDERR "### STRIPPED BLOCK (powerpc/rs6000):\n$str" if $Dump_asm_splitting_info;
426 $str = ".toc\n" . $str;
433 # make "require"r happy...