[project @ 1997-03-17 20:34:25 by simonpj]
[ghc-hetmet.git] / ghc / driver / ghc-asm.lprl
1 %************************************************************************
2 %*                                                                      *
3 \section[Driver-asm-fiddling]{Fiddling with assembler files}
4 %*                                                                      *
5 %************************************************************************
6
7 Tasks:
8 \begin{itemize}
9 \item
10 Utterly stomp out C functions' prologues and epilogues; i.e., the
11 stuff to do with the C stack.
12 \item
13 Any other required tidying up.
14 \end{itemize}
15
16 HPPA specific notes:
17 \begin{itemize}
18 \item
19 The HP linker is very picky about symbols being in the appropriate
20 space (code vs. data).  When we mangle the threaded code to put the
21 info tables just prior to the code, they wind up in code space
22 rather than data space.  This means that references to *_info from
23 un-mangled parts of the RTS (e.g. unthreaded GC code) get
24 unresolved symbols.  Solution:  mini-mangler for .c files on HP.  I
25 think this should really be triggered in the driver by a new -rts
26 option, so that user code doesn't get mangled inappropriately.
27 \item
28 With reversed tables, jumps are to the _info label rather than to
29 the _entry label.  The _info label is just an address in code
30 space, rather than an entry point with the descriptive blob we
31 talked about yesterday.  As a result, you can't use the call-style
32 JMP_ macro.  However, some JMP_ macros take _info labels as targets
33 and some take code entry points within the RTS.  The latter won't
34 work with the goto-style JMP_ macro.  Sigh.  Solution: Use the goto
35 style JMP_ macro, and mangle some more assembly, changing all
36 "RP'literal" and "LP'literal" references to "R'literal" and
37 "L'literal," so that you get the real address of the code, rather
38 than the descriptive blob.  Also change all ".word P%literal"
39 entries in info tables and vector tables to just ".word literal,"
40 for the same reason.  Advantage: No more ridiculous call sequences.
41 \end{itemize}
42
43 %************************************************************************
44 %*                                                                      *
45 \subsection{Constants for various architectures}
46 %*                                                                      *
47 %************************************************************************
48
49 \begin{code}
50 sub init_TARGET_STUFF {
51
52     #--------------------------------------------------------#
53     if ( $TargetPlatform =~ /^alpha-.*-.*/ ) {
54
55     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
56     $T_US           = ''; # _ if symbols have an underscore on the front
57     $T_DO_GC        = 'PerformGC_wrapper';
58     $T_PRE_APP      = 'DONT THINK THIS APPLIES'; # regexp that says what comes before APP/NO_APP
59     $T_CONST_LBL    = '^\$C(\d+):$'; # regexp for what such a lbl looks like
60     $T_POST_LBL     = ':';
61
62     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.(globl|ent)\s+\S+|\#.*|\.(file|loc)\s+\S+\s+\S+|\.text|\.r?data)\n)';
63     $T_COPY_DIRVS   = '^\s*(\#|\.(file|globl|ent|loc))';
64
65     $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
66     $T_DOT_WORD     = '\.quad';
67     $T_DOT_GLOBAL   = '^\t\.globl';
68     $T_HDR_literal  = "\.rdata\n\t\.align 3\n";
69     $T_HDR_misc     = "\.text\n\t\.align 3\n";
70     $T_HDR_data     = "\.data\n\t\.align 3\n";
71     $T_HDR_consist  = "\.text\n";
72     $T_HDR_closure  = "\.data\n\t\.align 3\n";
73     $T_HDR_info     = "\.text\n\t\.align 3\n";
74     $T_HDR_entry    = "\.text\n\t\.align 3\n";
75     $T_HDR_fast     = "\.text\n\t\.align 3\n";
76     $T_HDR_vector   = "\.text\n\t\.align 3\n";
77     $T_HDR_direct   = "\.text\n\t\.align 3\n";
78
79     #--------------------------------------------------------#
80     } elsif ( $TargetPlatform =~ /^hppa/ ) {
81
82     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
83     $T_US           = ''; # _ if symbols have an underscore on the front
84     $T_DO_GC        = 'PerformGC_wrapper';
85     $T_PRE_APP      = 'DONT THINK THIS APPLIES'; # regexp that says what comes before APP/NO_APP
86     $T_CONST_LBL    = '^L\$C(\d+)$'; # regexp for what such a lbl looks like
87     $T_POST_LBL     = '';
88
89     $T_MOVE_DIRVS   = '^((\s+\.(IMPORT|EXPORT|PARAM).*|\s+\.align\s+\d+|\s+\.(SPACE|SUBSPA)\s+\S+|\s*)\n)';
90     $T_COPY_DIRVS   = '^\s+\.(IMPORT|EXPORT)';
91
92     $T_hsc_cc_PAT   = '\.STRING.*\)(hsc|cc) (.*)\\\\x09(.*)\\\\x00';
93     $T_DOT_WORD     = '\.word';
94     $T_DOT_GLOBAL   = '^\s+\.EXPORT';
95     $T_HDR_literal  = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n";
96     $T_HDR_misc     = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
97     $T_HDR_data     = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
98     $T_HDR_consist  = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n";
99     $T_HDR_closure  = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
100     $T_HDR_info     = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
101     $T_HDR_entry    = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
102     $T_HDR_fast     = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
103     $T_HDR_vector   = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
104     $T_HDR_direct   = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
105
106     #--------------------------------------------------------#
107     } elsif ( $TargetPlatform =~ /^i386-.*-(linuxaout|freebsd|cygwin32)/ ) {
108
109     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
110     $T_US           = '_'; # _ if symbols have an underscore on the front
111     $T_DO_GC        = '_PerformGC_wrapper';
112     $T_PRE_APP      = '^#'; # regexp that says what comes before APP/NO_APP
113     $T_CONST_LBL    = '^LC(\d+):$';
114     $T_POST_LBL     = ':';
115     $T_X86_PRE_LLBL_PAT = 'L';
116     $T_X86_PRE_LLBL         = 'L';
117     $T_X86_BADJMP   = '^\tjmp [^L\*]';
118
119     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+(,0x90)?|\.globl\s+\S+|\.text|\.data|\.stab[^n].*|\.type\s+.*|\.size\s+.*)\n)';
120     $T_COPY_DIRVS   = '\.(globl|stab)';
121     $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
122     $T_DOT_WORD     = '\.long';
123     $T_DOT_GLOBAL   = '\.globl';
124     $T_HDR_literal  = "\.text\n\t\.align 2\n";
125     $T_HDR_misc     = "\.text\n\t\.align 2,0x90\n";
126     $T_HDR_data     = "\.data\n\t\.align 2\n";
127     $T_HDR_consist  = "\.text\n";
128     $T_HDR_closure  = "\.data\n\t\.align 2\n";
129     $T_HDR_info     = "\.text\n\t\.align 2\n"; # NB: requires padding
130     $T_HDR_entry    = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
131     $T_HDR_fast     = "\.text\n\t\.align 2,0x90\n";
132     $T_HDR_vector   = "\.text\n\t\.align 2\n"; # NB: requires padding
133     $T_HDR_direct   = "\.text\n\t\.align 2,0x90\n";
134
135     #--------------------------------------------------------#
136     } elsif ( $TargetPlatform =~ /^i386-.*-(solaris2|linux)$/ ) {
137
138     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
139     $T_US           = ''; # _ if symbols have an underscore on the front
140     $T_DO_GC        = 'PerformGC_wrapper';
141     $T_PRE_APP      = # regexp that says what comes before APP/NO_APP
142                       ($TargetPlatform =~ /-linux$/) ? '#' : '/' ;
143     $T_CONST_LBL    = '^\.LC(\d+):$'; # regexp for what such a lbl looks like
144     $T_POST_LBL     = ':';
145     $T_X86_PRE_LLBL_PAT = '\.L';
146     $T_X86_PRE_LLBL         = '.L';
147     $T_X86_BADJMP   = '^\tjmp [^\.\*]';
148
149     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+(,0x90)?|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.Lfe.*\n\t\.size\s+.*|\.size\s+.*|\.ident.*)\n)';
150     $T_COPY_DIRVS   = '\.(globl)';
151
152     $T_hsc_cc_PAT   = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"';
153     $T_DOT_WORD     = '\.long';
154     $T_DOT_GLOBAL   = '\.globl';
155     $T_HDR_literal  = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11)
156     $T_HDR_misc     = "\.text\n\t\.align 16\n";
157     $T_HDR_data     = "\.data\n\t\.align 4\n"; # ToDo: change align??
158     $T_HDR_consist  = "\.text\n";
159     $T_HDR_closure  = "\.data\n\t\.align 4\n"; # ToDo: change align?
160     $T_HDR_info     = "\.text\n\t\.align 16\n"; # NB: requires padding
161     $T_HDR_entry    = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
162     $T_HDR_fast     = "\.text\n\t\.align 16\n";
163     $T_HDR_vector   = "\.text\n\t\.align 16\n"; # NB: requires padding
164     $T_HDR_direct   = "\.text\n\t\.align 16\n";
165
166     #--------------------------------------------------------#
167     } elsif ( $TargetPlatform =~ /^m68k-.*-sunos4/ ) {
168
169     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
170     $T_US           = '_'; # _ if symbols have an underscore on the front
171     $T_DO_GC        = '_PerformGC_wrapper';
172     $T_PRE_APP      = '^# MAY NOT APPLY'; # regexp that says what comes before APP/NO_APP
173     $T_CONST_LBL    = '^LC(\d+):$';
174     $T_POST_LBL     = ':';
175
176     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.proc\s+\d+|\.const|\.cstring|\.globl\s+\S+|\.text|\.data|\.even|\.stab[^n].*)\n)';
177     $T_COPY_DIRVS   = '\.(globl|proc|stab)';
178     $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
179
180     $T_DOT_WORD     = '\.long';
181     $T_DOT_GLOBAL   = '\.globl';
182     $T_HDR_literal  = "\.text\n\t\.even\n";
183     $T_HDR_misc     = "\.text\n\t\.even\n";
184     $T_HDR_data     = "\.data\n\t\.even\n";
185     $T_HDR_consist  = "\.text\n";
186     $T_HDR_closure  = "\.data\n\t\.even\n";
187     $T_HDR_info     = "\.text\n\t\.even\n";
188     $T_HDR_entry    = "\.text\n\t\.even\n";
189     $T_HDR_fast     = "\.text\n\t\.even\n";
190     $T_HDR_vector   = "\.text\n\t\.even\n";
191     $T_HDR_direct   = "\.text\n\t\.even\n";
192
193     #--------------------------------------------------------#
194     } elsif ( $TargetPlatform =~ /^mips-.*/ ) {
195
196     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
197     $T_US           = ''; # _ if symbols have an underscore on the front
198     $T_DO_GC        = 'PerformGC_wrapper';
199     $T_PRE_APP      = '^\s*#'; # regexp that says what comes before APP/NO_APP
200     $T_CONST_LBL    = '^\$LC(\d+):$'; # regexp for what such a lbl looks like
201     $T_POST_LBL     = ':';
202
203     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.(globl|ent)\s+\S+|\.text|\.r?data)\n)';
204     $T_COPY_DIRVS   = '\.(globl|ent)';
205
206     $T_hsc_cc_PAT   = 'I WAS TOO LAZY TO DO THIS BIT (WDP 95/05)';
207     $T_DOT_WORD     = '\.word';
208     $T_DOT_GLOBAL   = '^\t\.globl';
209     $T_HDR_literal  = "\t\.rdata\n\t\.align 2\n";
210     $T_HDR_misc     = "\t\.text\n\t\.align 2\n";
211     $T_HDR_data     = "\t\.data\n\t\.align 2\n";
212     $T_HDR_consist  = 'TOO LAZY TO DO THIS TOO';
213     $T_HDR_closure  = "\t\.data\n\t\.align 2\n";
214     $T_HDR_info     = "\t\.text\n\t\.align 2\n";
215     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
216     $T_HDR_fast     = "\t\.text\n\t\.align 2\n";
217     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
218     $T_HDR_direct   = "\t\.text\n\t\.align 2\n";
219
220     #--------------------------------------------------------#
221     } elsif ( $TargetPlatform =~ /^powerpc-.*/ ) {
222
223     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
224     $T_US           = ''; # _ if symbols have an underscore on the front
225     $T_DO_GC        = 'PerformGC_wrapper';
226     $T_PRE_APP      = 'NOT APPLICABLE'; # regexp that says what comes before APP/NO_APP
227     $T_CONST_LBL    = '^LC\.\.(\d+):$'; # regexp for what such a lbl looks like
228     $T_POST_LBL     = ':';
229
230     $T_MOVE_DIRVS   = '^(\s*(\.toc|.csect \S+|\.l?globl \S+|\.align \d+)\n)';
231     $T_COPY_DIRVS   = '\.(l?globl)';
232
233     $T_hsc_cc_PAT   = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"';
234     $T_DOT_WORD     = '\.long';
235     $T_DOT_GLOBAL   = '\.globl';
236     $T_HDR_literal  = "\.section\t\.rodata\n";
237     $T_HDR_misc     = "\.text\n\t\.align 2\n";
238     $T_HDR_data     = "\.data\n\t\.align 2\n";
239     $T_HDR_consist  = "\.text\n";
240     $T_HDR_closure  = "\.data\n\t\.align 2\n";
241     $T_HDR_info     = "\.text\n\t\.align 2\n";
242     $T_HDR_entry    = "\.text\n";
243     $T_HDR_fast     = "\.text\n\t\.align 2\n";
244     $T_HDR_vector   = "\.text\n\t\.align 2\n";
245     $T_HDR_direct   = "\.text\n\t\.align 2\n";
246
247     #--------------------------------------------------------#
248     } elsif ( $TargetPlatform =~ /^sparc-.*-solaris2/ ) {
249
250     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
251     $T_US           = ''; # _ if symbols have an underscore on the front
252     $T_DO_GC        = 'PerformGC_wrapper';
253     $T_PRE_APP      = 'DOES NOT SEEM TO APPLY'; # regexp that says what comes before APP/NO_APP
254     $T_CONST_LBL    = '^\.LLC(\d+):$'; # regexp for what such a lbl looks like
255     $T_POST_LBL     = ':';
256
257     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*|\.section.*|\s+\.type.*|\s+\.size.*)\n)';
258     $T_COPY_DIRVS   = '\.(global|proc|stab)';
259
260     $T_hsc_cc_PAT   = '\.asciz.*\)(hsc|cc) (.*)\\\\t(.*)"';
261     $T_DOT_WORD     = '\.word';
262     $T_DOT_GLOBAL   = '^\t\.global';
263     $T_HDR_literal  = "\.text\n\t\.align 8\n";
264     $T_HDR_misc     = "\.text\n\t\.align 4\n";
265     $T_HDR_data     = "\.data\n\t\.align 8\n";
266     $T_HDR_consist  = "\.text\n";
267     $T_HDR_closure  = "\.data\n\t\.align 4\n";
268     $T_HDR_info     = "\.text\n\t\.align 4\n";
269     $T_HDR_entry    = "\.text\n\t\.align 4\n";
270     $T_HDR_fast     = "\.text\n\t\.align 4\n";
271     $T_HDR_vector   = "\.text\n\t\.align 4\n";
272     $T_HDR_direct   = "\.text\n\t\.align 4\n";
273
274     #--------------------------------------------------------#
275     } elsif ( $TargetPlatform =~ /^sparc-.*-sunos4/ ) {
276
277     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
278     $T_US           = '_'; # _ if symbols have an underscore on the front
279     $T_DO_GC        = '_PerformGC_wrapper';
280     $T_PRE_APP      = '^# DOES NOT SEEM TO APPLY'; # regexp that says what comes before APP/NO_APP
281     $T_CONST_LBL    = '^LC(\d+):$';
282     $T_POST_LBL     = ':';
283
284     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*)\n)';
285     $T_COPY_DIRVS   = '\.(global|proc|stab)';
286     $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
287
288     $T_DOT_WORD     = '\.word';
289     $T_DOT_GLOBAL   = '^\t\.global';
290     $T_HDR_literal  = "\.text\n\t\.align 8\n";
291     $T_HDR_misc     = "\.text\n\t\.align 4\n";
292     $T_HDR_data     = "\.data\n\t\.align 8\n";
293     $T_HDR_consist  = "\.text\n";
294     $T_HDR_closure  = "\.data\n\t\.align 4\n";
295     $T_HDR_info     = "\.text\n\t\.align 4\n";
296     $T_HDR_entry    = "\.text\n\t\.align 4\n";
297     $T_HDR_fast     = "\.text\n\t\.align 4\n";
298     $T_HDR_vector   = "\.text\n\t\.align 4\n";
299     $T_HDR_direct   = "\.text\n\t\.align 4\n";
300
301     #--------------------------------------------------------#
302     } else {
303         print STDERR "$Pgm: don't know how to mangle assembly language for: $TargetPlatform\n";
304         exit 1;
305     }
306
307 if ( 0 ) {
308 print STDERR "T_STABBY: $T_STABBY\n";
309 print STDERR "T_US: $T_US\n";
310 print STDERR "T_DO_GC: $T_DO_GC\n";
311 print STDERR "T_PRE_APP: $T_PRE_APP\n";
312 print STDERR "T_CONST_LBL: $T_CONST_LBL\n";
313 print STDERR "T_POST_LBL: $T_POST_LBL\n";
314 if ( $TargetPlatform =~ /^i386-/ ) {
315     print STDERR "T_X86_PRE_LLBL_PAT: $T_X86_PRE_LLBL_PAT\n";
316     print STDERR "T_X86_PRE_LLBL: $T_X86_PRE_LLBL\n";
317     print STDERR "T_X86_BADJMP: $T_X86_BADJMP\n";
318 }
319 print STDERR "T_MOVE_DIRVS: $T_MOVE_DIRVS\n";
320 print STDERR "T_COPY_DIRVS: $T_COPY_DIRVS\n";
321 print STDERR "T_hsc_cc_PAT: $T_hsc_cc_PAT\n";
322 print STDERR "T_DOT_WORD: $T_DOT_WORD\n";
323 print STDERR "T_HDR_literal: $T_HDR_literal\n";
324 print STDERR "T_HDR_misc: $T_HDR_misc\n";
325 print STDERR "T_HDR_data: $T_HDR_data\n";
326 print STDERR "T_HDR_consist: $T_HDR_consist\n";
327 print STDERR "T_HDR_closure: $T_HDR_closure\n";
328 print STDERR "T_HDR_info: $T_HDR_info\n";
329 print STDERR "T_HDR_entry: $T_HDR_entry\n";
330 print STDERR "T_HDR_fast: $T_HDR_fast\n";
331 print STDERR "T_HDR_vector: $T_HDR_vector\n";
332 print STDERR "T_HDR_direct: $T_HDR_direct\n";
333 }
334
335 }
336 \end{code}
337
338 %************************************************************************
339 %*                                                                      *
340 \subsection{Mangle away}
341 %*                                                                      *
342 %************************************************************************
343
344 \begin{code}
345 sub mangle_asm {
346     local($in_asmf, $out_asmf) = @_;
347
348     # multi-line regexp matching:
349     local($*) = 1;
350     local($i, $c);
351
352
353     &init_TARGET_STUFF();
354     &init_FUNNY_THINGS();
355
356     # perl4 on alphas SEGVs when give ${foo} substitutions in patterns.
357     # To avoid them we declare some locals that allows to avoid using curlies.
358     local($TUS)      = ${T_US};
359     local($TPOSTLBL) = ${T_POST_LBL};
360     local($TMOVEDIRVS) = ${T_MOVE_DIRVS};
361     local($TPREAPP)    = ${T_PRE_APP};
362     local($TCOPYDIRVS) = ${T_COPY_DIRVS};
363     local($TDOTWORD)   = ${T_DOT_WORD};
364
365     open(INASM, "< $in_asmf")
366         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
367     open(OUTASM,"> $out_asmf")
368         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
369
370     # read whole file, divide into "chunks":
371     #   record some info about what we've found...
372
373     @chk = ();          # contents of the chunk
374     $numchks = 0;       # number of them
375     @chkcat = ();       # what category of thing in each chunk
376     @chksymb = ();      # what symbol(base) is defined in this chunk
377     %slowchk = ();      # ditto, its regular "slow" entry code
378     %fastchk = ();      # ditto, fast entry code
379     %closurechk = ();   # ditto, the (static) closure
380     %infochk = ();      # given a symbol base, say what chunk its info tbl is in
381     %vectorchk = ();    # ditto, return vector table
382     %directchk = ();    # ditto, direct return code
383     $EXTERN_DECLS = ''; # .globl <foo> .text (MIPS only)
384
385     $i = 0; $chkcat[0] = 'misc'; $chk[0] = '';
386
387     while (<INASM>) {
388         next if $T_STABBY && /^\.stab.*$TUS[@]?__stg_split_marker/o;
389         next if $T_STABBY && /^\.stab.*ghc.*c_ID/;
390         next if /$TPREAPP(NO_)?APP/o; 
391         next if /^;/ && $TargetPlatform =~ /^hppa/;
392
393         next if /(^$|^\t\.file\t|^ # )/ && $TargetPlatform =~ /^(mips|powerpc)-/;
394
395         last if /^_section_\.text:$/ && $TargetPlatform =~ /^powerpc-/;
396
397         if ( $TargetPlatform =~ /^mips-/ 
398           && /^\t\.(globl \S+ \.text|comm\t)/ ) {
399             $EXTERN_DECLS .= $_ unless /(__DISCARD__|\b(PK_|ASSIGN_)(FLT|DBL)\b)/;
400   
401         } elsif ( /^\s+/ ) { # most common case first -- a simple line!
402             # duplicated from the bottom
403
404             $chk[$i] .= $_;
405
406         } elsif ( /\.\.ng:$/ && $TargetPlatform =~ /^alpha-/ ) {
407             # Alphas: Local labels not to be confused with new chunks
408             $chk[$i] .= $_;
409   
410         # NB: all the rest start with a non-space
411
412         } elsif ( $TargetPlatform =~ /^mips-/
413                && /^\d+:/ ) { # a funny-looking very-local label
414             $chk[$i] .= $_;
415
416         } elsif ( /$T_CONST_LBL/o ) {
417             $chk[++$i]   = $_;
418             $chkcat[$i]  = 'literal';
419             $chksymb[$i] = $1;
420
421         } elsif ( /^$TUS[@]?__stg_split_marker(\d+)$TPOSTLBL[@]?$/o ) {
422             $chk[++$i]   = $_;
423             $chkcat[$i]  = 'splitmarker';
424             $chksymb[$i] = $1;
425
426         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_info$TPOSTLBL[@]?$/o ) {
427             $symb = $1;
428             $chk[++$i]   = $_;
429             $chkcat[$i]  = 'infotbl';
430             $chksymb[$i] = $symb;
431
432             die "Info table already? $symb; $i\n" if defined($infochk{$symb});
433
434             $infochk{$symb} = $i;
435
436         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_entry$TPOSTLBL[@]?$/o ) {
437             $chk[++$i]   = $_;
438             $chkcat[$i]  = 'slow';
439             $chksymb[$i] = $1;
440
441             $slowchk{$1} = $i;
442
443         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_fast\d+$TPOSTLBL[@]?$/o ) {
444             $chk[++$i]   = $_;
445             $chkcat[$i]  = 'fast';
446             $chksymb[$i] = $1;
447
448             $fastchk{$1} = $i;
449
450         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_closure$TPOSTLBL[@]?$/o ) {
451             $chk[++$i]   = $_;
452             $chkcat[$i]  = 'closure';
453             $chksymb[$i] = $1;
454
455             $closurechk{$1} = $i;
456
457         } elsif ( /^$TUS[@]?ghc.*c_ID$TPOSTLBL/o ) {
458             $chk[++$i]  = $_;
459             $chkcat[$i] = 'consist';
460
461         } elsif ( /^($TUS[@]?__gnu_compiled_c|gcc2_compiled\.)$TPOSTLBL/o ) {
462             ; # toss it
463
464         } elsif ( /^$TUS[@]?ErrorIO_call_count$TPOSTLBL[@]?$/o  # HACK!!!!
465                || /^$TUS[A-Za-z0-9_]+\.\d+$TPOSTLBL[@]?$/o
466                || /^$TUS[@]?.*_CAT$TPOSTLBL[@]?$/o              # PROF: _entryname_CAT
467                || /^$TUS[@]?CC_.*_struct$TPOSTLBL[@]?$/o        # PROF: _CC_ccident_struct
468                || /^$TUS[@]?.*_done$TPOSTLBL[@]?$/o             # PROF: _module_done
469                || /^$TUS[@]?_module_registered$TPOSTLBL[@]?$/o  # PROF: _module_registered
470                ) {
471             $chk[++$i]   = $_;
472             $chkcat[$i]  = 'data';
473             $chksymb[$i] = '';
474
475         } elsif ( /^([A-Za-z0-9_]+)\s+\.comm/ && $TargetPlatform =~ /^hppa/ ) {
476             $chk[++$i]   = $_;
477             $chkcat[$i]  = 'bss';
478             $chksymb[$i] = $1;
479
480         } elsif ( /^$TUS[@]?(ret_|djn_)/o ) {
481             $chk[++$i]   = $_;
482             $chkcat[$i]  = 'misc';
483             $chksymb[$i] = '';
484
485         } elsif ( /^$TUS[@]?vtbl_([A-Za-z0-9_]+)$TPOSTLBL[@]?$/o ) {
486             $chk[++$i]   = $_;
487             $chkcat[$i]  = 'vector';
488             $chksymb[$i] = $1;
489
490             $vectorchk{$1} = $i;
491
492         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)DirectReturn$TPOSTLBL[@]?$/o ) {
493             $chk[++$i]   = $_;
494             $chkcat[$i]  = 'direct';
495             $chksymb[$i] = $1;
496
497             $directchk{$1} = $i;
498
499         } elsif ( /^$TUS[@]?[A-Za-z0-9_]+_upd$TPOSTLBL[@]?$/o ) {
500             $chk[++$i]   = $_;
501             $chkcat[$i]  = 'misc';
502             $chksymb[$i] = '';
503
504         } elsif ( $TargetPlatform =~ /^i386-.*-solaris2/
505              &&   /^(_uname|uname|stat|fstat):/ ) {
506             # for some utterly bizarre reason, this platform
507             # likes to drop little local C routines with these names
508             # into each and every .o file that #includes the
509             # relevant system .h file.  Yuck.  We just don't
510             # tolerate them in .hc files (which we are processing
511             # here).  If you need to call one of these things from
512             # Haskell, make a call to your own C wrapper, then
513             # put that C wrapper (which calls one of these) in a
514             # plain .c file.  WDP 95/12
515             $chk[++$i]   = $_;
516             $chkcat[$i]  = 'toss';
517             $chksymb[$i] = $1;
518
519         } elsif ( /^$TUS[@]?[A-Za-z0-9_]/o
520                 && ( $TargetPlatform !~ /^hppa/ # need to avoid local labels in this case
521                    || ! /^L\$\d+$/ )
522                 && ( $TargetPlatform !~ /^powerpc/ # ditto
523                    || ! /^(L\.\.\d+|LT\.\..*):$/ ) ) {
524             local($thing);
525             chop($thing = $_);
526             print STDERR "Funny global thing?: $_"
527                 unless $KNOWN_FUNNY_THING{$thing}
528                     || /^$TUS[@]?_(PRIn|PRStart).*$TPOSTLBL[@]?$/o # pointer reversal GC routines
529                     || /^$TUS[@]?CC_.*$TPOSTLBL$/o              # PROF: _CC_ccident  ([@]? is a silly hack (see above))
530                     || /^$TUS[@]?_reg.*$TPOSTLBL$/o;            # PROF: __reg<module>
531             $chk[++$i]   = $_;
532             $chkcat[$i]  = 'misc';
533             $chksymb[$i] = '';
534
535         } else { # simple line (duplicated at the top)
536
537             $chk[$i] .= $_;
538         }
539     }
540     $numchks = $#chk + 1;
541
542     # the division into chunks is imperfect;
543     # we throw some things over the fence into the next
544     # chunk.
545     #
546     # also, there are things we would like to know
547     # about the whole module before we start spitting
548     # output.
549
550     local($FIRST_MANGLABLE) = ($TargetPlatform =~ /^(alpha-|hppa|mips-)/) ? 1 : 0;
551
552 #   print STDERR "first chunk to mangle: $FIRST_MANGLABLE\n";
553
554     # Alphas: NB: we start meddling at chunk 1, not chunk 0
555     # The first ".rdata" is quite magical; as of GCC 2.7.x, it
556     # spits a ".quad 0" in after the v first ".rdata"; we
557     # detect this special case (tossing the ".quad 0")!
558     local($magic_rdata_seen) = 0;
559   
560     # HPPAs, MIPSen: also start medding at chunk 1
561
562     for ($i = $FIRST_MANGLABLE; $i < $numchks; $i++) {
563         $c = $chk[$i]; # convenience copy
564
565 #       print STDERR "\nCHK $i (BEFORE) (",$chkcat[$i],"):\n", $c;
566
567         # toss all prologue stuff; HPPA is pretty weird
568         # (see elsewhere)
569         $c = &mash_hppa_prologue($c) if $TargetPlatform =~ /^hppa/;
570
571         # be slightly paranoid to make sure there's
572         # nothing surprising in there
573         if ( $c =~ /--- BEGIN ---/ ) {
574             if (($p, $r) = split(/--- BEGIN ---/, $c)) {
575
576                 if ($TargetPlatform =~ /^i386-/) {
577                     $p =~ s/^\tpushl \%edi\n//;
578                     $p =~ s/^\tpushl \%esi\n//;
579                     $p =~ s/^\tsubl \$\d+,\%esp\n//;
580                     $p =~ s/^\tmovl \$\d+,\%eax\n\tcall __alloca\n// if ($TargetPlatform =~ /^.*-cygwin32/);
581                 } elsif ($TargetPlatform =~ /^m68k-/) {
582                     $p =~ s/^\tlink a6,#-?\d.*\n//;
583                     $p =~ s/^\tmovel d2,sp\@-\n//;
584                     $p =~ s/^\tmovel d5,sp\@-\n//; # SMmark.* only?
585                     $p =~ s/^\tmoveml \#0x[0-9a-f]+,sp\@-\n//; # SMmark.* only?
586                 } elsif ($TargetPlatform =~ /^mips-/) {
587                     # the .frame/.mask/.fmask that we use is the same
588                     # as that produced by GCC for miniInterpret; this
589                     # gives GDB some chance of figuring out what happened
590                     $FRAME = "\t.frame\t\$sp,2168,\$31\n\t.mask\t0x90000000,-4\n\t.fmask\t0x00000000,0\n";
591                     $p =~ s/^\t\.(frame).*\n/__FRAME__/g;
592                     $p =~ s/^\t\.(mask|fmask).*\n//g;
593                     $p =~ s/^\t\.cprestore.*\n/\t\.cprestore 416\n/; # 16 + 100 4-byte args
594                     $p =~ s/^\tsubu\t\$sp,\$sp,\d+\n//;
595                     $p =~ s/^\tsw\t\$31,\d+\(\$sp\)\n//;
596                     $p =~ s/^\tsw\t\$fp,\d+\(\$sp\)\n//;
597                     $p =~ s/^\tsw\t\$28,\d+\(\$sp\)\n//;
598                     $p =~ s/__FRAME__/$FRAME/;
599                 } else {
600                     print STDERR "$Pgm: unknown prologue mangling? $TargetPlatform\n";
601                 }
602
603                 die "Prologue junk?: $p\n" if $p =~ /^\t[^\.]/
604                     && $TargetPlatform !~ /^powerpc-/; #ToDo: remove test
605
606                 # glue together what's left
607                 $c = $p . $r;
608                 $c =~ s/\n\t\n/\n/; # junk blank line
609             }
610         }
611
612         if ( $TargetPlatform =~ /^mips-/ ) {
613             # MIPS: first, this basic sequence may occur "--- END ---" or not
614             $c =~ s/^\tlw\t\$31,\d+\(\$sp\)\n\taddu\t\$sp,\$sp,\d+\n\tj\t\$31\n\t\.end/\t\.end/;
615         }
616
617         # toss all epilogue stuff; again, paranoidly
618         if ( $c =~ /--- END ---/ ) {
619             if (($r, $e) = split(/--- END ---/, $c)) {
620                 if ($TargetPlatform =~ /^i386-/) {
621                     $e =~ s/^\tret\n//;
622                     $e =~ s/^\tpopl \%edi\n//;
623                     $e =~ s/^\tpopl \%esi\n//;
624                     $e =~ s/^\taddl \$\d+,\%esp\n//;
625                 } elsif ($TargetPlatform =~ /^m68k-/) {
626                     $e =~ s/^\tunlk a6\n//;
627                     $e =~ s/^\trts\n//;
628                 } elsif ($TargetPlatform =~ /^mips-/) {
629                     $e =~ s/^\tlw\t\$31,\d+\(\$sp\)\n//;
630                     $e =~ s/^\tlw\t\$fp,\d+\(\$sp\)\n//;
631                     $e =~ s/^\taddu\t\$sp,\$sp,\d+\n//;
632                     $e =~ s/^\tj\t\$31\n//;
633                 } else {
634                     print STDERR "$Pgm: unknown epilogue mangling? $TargetPlatform\n";
635                 }
636                 die "Epilogue junk?: $e\n" if $e =~ /^\t[^\.]/
637                     && $TargetPlatform !~ /^powerpc-/; #ToDo: remove test
638
639                 # glue together what's left
640                 $c = $r . $e;
641                 $c =~ s/\n\t\n/\n/; # junk blank line
642             }
643         }
644
645         # On SPARCs, we don't do --- BEGIN/END ---, we just
646         # toss the register-windowing save/restore/ret* instructions
647         # directly:
648         if ( $TargetPlatform =~ /^sparc-/ ) {
649             $c =~ s/^\t(save .*|restore|ret|retl)\n//g;
650             # throw away PROLOGUE comments
651             $c =~ s/^\t!#PROLOGUE# 0\n\t!#PROLOGUE# 1\n//;
652         }
653
654         # On Alphas, the prologue mangling is done a little later (below)
655
656         # toss all calls to __DISCARD__
657         $c =~ s/^\t(call|jbsr|jal)\s+$TUS[@]?__DISCARD__\n//go;
658
659         # MIPS: that may leave some gratuitous asm macros around
660         # (no harm done; but we get rid of them to be tidier)
661         $c =~ s/^\t\.set\tnoreorder\n\t\.set\tnomacro\n\taddu\t(\S+)\n\t\.set\tmacro\n\t\.set\treorder\n/\taddu\t$1\n/
662             if $TargetPlatform =~ /^mips-/;
663
664         # toss stack adjustment after DoSparks
665         $c =~ s/^(\tjbsr _DoSparks\n)\taddqw #8,sp/$1/g
666                 if $TargetPlatform =~ /^m68k-/; # this looks old...
667
668         if ( $TargetPlatform =~ /^alpha-/ &&
669            ! $magic_rdata_seen &&
670            $c =~ /^\s*\.rdata\n\t\.quad 0\n\t\.align \d\n/ ) {
671             $c =~ s/^\s*\.rdata\n\t\.quad 0\n\t\.align (\d)\n/\.rdata\n\t\.align $1\n/;
672             $magic_rdata_seen = 1;
673         }
674
675         # pick some end-things and move them to the next chunk
676
677         # pin a funny end-thing on (for easier matching):
678         $c .= 'FUNNY#END#THING';
679
680         while ( $c =~ /$TMOVEDIRVS[@]?FUNNY#END#THING/o ) {  # [@]? is a silly hack to avoid having to use curlies for T_PRE_APP
681                                                            # (this SEGVs perl4 on alphas, you see)
682
683             $to_move = $1;
684             if ( $i < ($numchks - 1)
685               && ( $to_move =~ /$TCOPYDIRVS/
686                 || ($TargetPlatform =~ /^hppa/ && $to_move =~ /align/ && $chkcat[$i+1] eq 'literal') )) {
687                 $chk[$i + 1] = $to_move . $chk[$i + 1];
688                 # otherwise they're tossed
689             }
690
691             $c =~ s/$TMOVEDIRVS[@]?FUNNY#END#THING/FUNNY#END#THING/o; # [@]? is a hack (see above)
692         }
693
694         if ( $TargetPlatform =~ /^alpha-/ && $c =~ /^\t\.ent\s+(\S+)/ ) {
695             $ent = $1;
696             # toss all prologue stuff, except for loading gp, and the ..ng address
697             if (($p, $r) = split(/^\t\.prologue/, $c)) {
698                 if (($keep, $junk) = split(/\.\.ng:/, $p)) {
699                     $c = $keep . "..ng:\n";
700                 } else {
701                     print STDERR "malformed code block ($ent)?\n"
702                 }
703             }
704             $c .= "\t.frame \$30,0,\$26,0\n\t.prologue" . $r;
705         }
706   
707         $c =~ s/FUNNY#END#THING//;
708
709 #       print STDERR "\nCHK $i (AFTER) (",$chkcat[$i],"):\n", $c;
710
711         $chk[$i] = $c; # update w/ convenience copy
712     }
713
714     if ( $TargetPlatform =~ /^alpha-/ ) {
715         # print out the header stuff first
716         $chk[0] =~ s/^(\t\.file.*)"(ghc\d+\.c)"/$1"$ifile_root.hc"/;
717         print OUTASM $chk[0];
718
719     } elsif ( $TargetPlatform =~ /^hppa/ ) {
720         print OUTASM $chk[0];
721
722     } elsif ( $TargetPlatform =~ /^mips-/ ) {
723         $chk[0] = "\t\.file\t1 \"$ifile_root.hc\"\n" . $chk[0];
724
725         # get rid of horrible "<dollar>Revision: .*$" strings
726         local(@lines0) = split(/\n/, $chk[0]);
727         local($z) = 0;
728         while ( $z <= $#lines0 ) {
729             if ( $lines0[$z] =~ /^\t\.byte\t0x24,0x52,0x65,0x76,0x69,0x73,0x69,0x6f$/ ) {
730                 undef($lines0[$z]);
731                 $z++;
732                 while ( $z <= $#lines0 ) {
733                     undef($lines0[$z]);
734                     last if $lines0[$z] =~ /[,\t]0x0$/;
735                     $z++;
736                 }
737             }
738             $z++;
739         }
740         $chk[0] = join("\n", @lines0);
741         $chk[0] =~ s/\n\n+/\n/;
742         print OUTASM $chk[0];
743     }
744
745     # print out all the literal strings next
746     for ($i = 0; $i < $numchks; $i++) {
747         if ( $chkcat[$i] eq 'literal' ) {
748             print OUTASM $T_HDR_literal, $chk[$i];
749             print OUTASM "; end literal\n" if $TargetPlatform =~ /^hppa/; # for the splitter
750
751             $chkcat[$i] = 'DONE ALREADY';
752         }
753     }
754
755     # on the HPPA, print out all the bss next
756     if ( $TargetPlatform =~ /^hppa/ ) {
757         for ($i = 1; $i < $numchks; $i++) {
758             if ( $chkcat[$i] eq 'bss' ) {
759                 print OUTASM "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$BSS\$\n\t.align 4\n";
760                 print OUTASM $chk[$i];
761
762                 $chkcat[$i] = 'DONE ALREADY';
763             }
764         }
765     }
766
767     for ($i = $FIRST_MANGLABLE; $i < $numchks; $i++) {
768 #       print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n";
769
770         next if $chkcat[$i] eq 'DONE ALREADY';
771
772         if ( $chkcat[$i] eq 'misc' ) {
773             if ($chk[$i] ne '') {
774                 print OUTASM $T_HDR_misc;
775                 &print_doctored($chk[$i], 0);
776             }
777
778         } elsif ( $chkcat[$i] eq 'toss' ) {
779             print STDERR "*** NB: TOSSING code for $chksymb[$i] !!! ***\n";
780
781         } elsif ( $chkcat[$i] eq 'data' ) {
782             if ($chk[$i] ne '') {
783                 print OUTASM $T_HDR_data;
784                 print OUTASM $chk[$i];
785             }
786
787         } elsif ( $chkcat[$i] eq 'consist' ) {
788             if ( $chk[$i] =~ /$T_hsc_cc_PAT/o ) {
789                 local($consist) = "$1.$2.$3";
790                 $consist =~ s/,/./g;
791                 $consist =~ s/\//./g;
792                 $consist =~ s/-/_/g;
793                 $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly?
794                 print OUTASM $T_HDR_consist, "${consist}${T_POST_LBL}\n";
795
796             } elsif ( $TargetPlatform !~ /^(mips|powerpc)-/ ) { # we just don't try in those case (ToDo)
797                 # on mips: consistency string is just a v
798                 # horrible bunch of .bytes,
799                 # which I am too lazy to sort out (WDP 95/05)
800
801                 print STDERR "Couldn't grok consistency: ", $chk[$i];
802             }
803
804         } elsif ( $chkcat[$i] eq 'splitmarker' ) {
805             # we can just re-constitute this one...
806             # NB: we emit _three_ underscores no matter what,
807             # so ghc-split doesn't have to care.
808             print OUTASM "___stg_split_marker",$chksymb[$i],"${T_POST_LBL}\n";
809
810         } elsif ( $chkcat[$i] eq 'closure'
811                || $chkcat[$i] eq 'infotbl'
812                || $chkcat[$i] eq 'slow'
813                || $chkcat[$i] eq 'fast' ) { # do them in that order
814             $symb = $chksymb[$i];
815
816             # CLOSURE
817             if ( defined($closurechk{$symb}) ) {
818                 print OUTASM $T_HDR_closure;
819                 print OUTASM $chk[$closurechk{$symb}];
820                 $chkcat[$closurechk{$symb}] = 'DONE ALREADY';
821             }
822
823             # INFO TABLE
824             if ( defined($infochk{$symb}) ) {
825
826                 print OUTASM $T_HDR_info;
827                 print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1);
828                 # entry code will be put here!
829
830                 # paranoia
831                 if ( $chk[$infochk{$symb}] =~ /$TDOTWORD[@]?\s+([A-Za-z0-9_]+_entry)$/o
832                   && $1 ne "${T_US}${symb}_entry" ) {
833                     print STDERR "!!! entry point???\n",$chk[$infochk{$symb}];
834                 }
835
836                 $chkcat[$infochk{$symb}] = 'DONE ALREADY';
837             }
838
839             # STD ENTRY POINT
840             if ( defined($slowchk{$symb}) ) {
841
842                 # teach it to drop through to the fast entry point:
843                 $c = $chk[$slowchk{$symb}];
844
845                 if ( defined($fastchk{$symb}) ) {
846                     if ( $TargetPlatform =~ /^alpha-/ ) {
847                         $c =~ s/^\tjmp \$31,\(\$27\),0\n\t\.align 4\n\t\.end/\t.align 4\n\t.end/;
848                     } elsif ( $TargetPlatform =~ /^hppa/ ) {
849                         $c =~ s/^\s+ldil.*\n\s+ldo.*\n\s+bv.*\n(.*\n)?\s+\.EXIT/$1\t.EXIT/;
850                     } elsif ( $TargetPlatform =~ /^i386-/ ) {
851                         $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%edx\n\tjmp \*\%edx\n//;
852                         $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%eax\n\tjmp \*\%eax\n//;
853                     } elsif ( $TargetPlatform =~ /^mips-/ ) {
854                         $c =~ s/^\tjmp \$31,\(\$27\),0\n\t\.align 4\n\t\.end/\t.align 4\n\t.end/;
855                     } elsif ( $TargetPlatform =~ /^m68k-/ ) {
856                         $c =~ s/^\tjmp ${T_US}${symb}_fast\d+.*\n\tnop\n//;
857                         $c =~ s/^\tjmp ${T_US}${symb}_fast\d+.*\n//;
858                     } elsif ( $TargetPlatform =~ /^sparc-/ ) {
859                         $c =~ s/^\tcall ${T_US}${symb}_fast\d+,.*\n\tnop\n//;
860                         $c =~ s/^\tcall ${T_US}${symb}_fast\d+,.*\n(\t[a-z].*\n)/$1/;
861                     } else {
862                         print STDERR "$Pgm: mystery slow-fast dropthrough: $TargetPlatform\n";
863                     }
864                 }
865
866                 if ( $TargetPlatform !~ /^(alpha-|hppa|mips-)/ ) {
867                     # On alphas, hppa: no very good way to look for "dangling"
868                     # references to fast-entry point.
869                     # (questionable re hppa and mips...)
870                     print STDERR "still has jump to fast entry point:\n$c"
871                         if $c =~ /$TUS[@]?$symb[@]?_fast/; # NB: paranoia
872                 }
873
874                 print OUTASM $T_HDR_entry;
875
876                 &print_doctored($c, 1); # NB: the 1!!!
877
878                 $chkcat[$slowchk{$symb}] = 'DONE ALREADY';
879             }
880             
881             # FAST ENTRY POINT
882             if ( defined($fastchk{$symb}) ) {
883                 if ( ! defined($slowchk{$symb})
884                    # ToDo: the || clause can go once we're no longer
885                    # concerned about producing exactly the same output as before
886 #OLD:              || $TargetPlatform =~ /^(m68k|sparc|i386)-/
887                    ) {
888                     print OUTASM $T_HDR_fast;
889                 }
890                 &print_doctored($chk[$fastchk{$symb}], 0);
891                 $chkcat[$fastchk{$symb}] = 'DONE ALREADY';
892             }
893
894         } elsif ( $chkcat[$i] eq 'vector'
895                || $chkcat[$i] eq 'direct' ) { # do them in that order
896             $symb = $chksymb[$i];
897
898             # VECTOR TABLE
899             if ( defined($vectorchk{$symb}) ) {
900                 print OUTASM $T_HDR_vector;
901                 print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0);
902                 # direct return code will be put here!
903                 $chkcat[$vectorchk{$symb}] = 'DONE ALREADY';
904             }
905
906             # DIRECT RETURN
907             if ( defined($directchk{$symb}) ) {
908                 print OUTASM $T_HDR_direct;
909                 &print_doctored($chk[$directchk{$symb}], 0);
910                 $chkcat[$directchk{$symb}] = 'DONE ALREADY';
911
912             } elsif ( $TargetPlatform =~ /^alpha-/ ) {
913                 # Alphas: the commented nop is for the splitter, to ensure
914                 # that no module ends with a label as the very last
915                 # thing.  (The linker will adjust the label to point
916                 # to the first code word of the next module linked in,
917                 # even if alignment constraints cause the label to move!)
918
919                 print OUTASM "\t# nop\n";
920             }
921             
922         } else {
923             &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm: $TargetPlatform)\n$chkcat[$i]\n$chk[$i]\n");
924         }
925     }
926
927     print OUTASM $EXTERN_DECLS if $TargetPlatform =~ /^mips-/;
928
929     print OUTASM ".csect .text[PR]\n_section_.text:\n.csect .data[RW]\n\t.long _section_.text\n"
930         if $TargetPlatform =~ /^powerpc-/;
931
932     # finished
933     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
934     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
935 }
936 \end{code}
937
938 \begin{code}
939 sub mash_hppa_prologue { # OK, epilogue, too
940     local($_) = @_;
941
942     # toss all prologue stuff
943     s/^\s+\.ENTRY[^\0]*--- BEGIN ---/\t.ENTRY/;
944
945     # Lie about our .CALLINFO
946     s/^\s+\.CALLINFO.*$/\t.CALLINFO NO_CALLS,NO_UNWIND/;
947
948     # Get rid of P'
949
950     s/LP'/L'/g;
951     s/RP'/R'/g;
952
953     # toss all epilogue stuff
954     s/^\s+--- END ---[^\0]*\.EXIT/\t.EXIT/;
955
956     # Sorry; we moved the _info stuff to the code segment.
957     s/_info,DATA/_info,CODE/g;
958
959     return($_);
960 }
961 \end{code}
962
963 \begin{code}
964 sub print_doctored {
965     local($_, $need_fallthru_patch) = @_;
966
967     if ( $TargetPlatform !~ /^i386-/ 
968       || ! /^\t[a-z]/ ) { # no instructions in here, apparently
969         print OUTASM $_;
970         return;
971     }
972     # OK, must do some x86 **HACKING**
973
974     local($entry_patch) = '';
975     local($exit_patch)  = '';
976     local($call_entry_patch)= '';
977     local($call_exit_patch)     = '';
978
979 #OLD:   # first, convert calls to *very magic form*: (ToDo: document
980     # for real!)  from
981     #
982     #   pushl $768
983     #   call _?PerformGC_wrapper
984     #   addl $4,%esp
985     # to
986     #   movl $768, %eax
987     #   call _?PerformGC_wrapper
988     #
989     # The reason we do this now is to remove the apparent use of
990     # %esp, which would throw off the "what patch code do we need"
991     # decision.
992     #
993     # Special macros in ghc/includes/COptWraps.lh, used in
994     # ghc/runtime/CallWrap_C.lc, are required for this to work!
995     #
996
997     s/^\tpushl \$(\d+)\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \$$1,\%eax\n\tcall ${T_DO_GC}\n/go;
998     s/^\tpushl \%eax\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tcall ${T_DO_GC}\n/go;
999     s/^\tpushl \%edx\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \%edx,\%eax\n\tcall ${T_DO_GC}\n/go;
1000
1001 #=  if ( $StolenX86Regs <= 4 ) { # %ecx is ordinary reg
1002 #=      s/^\tpushl \%ecx\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \%ecx,\%eax\n\tcall ${T_DO_GC}\n/go;
1003 #=  }
1004
1005     # gotta watch out for weird instructions that
1006     # invisibly smash various regs:
1007     #   rep*    %ecx used for counting
1008     #   scas*   %edi used for destination index
1009     #   cmps*   %e[sd]i used for indices
1010     #   loop*   %ecx used for counting
1011     #
1012     # SIGH.
1013
1014     # We cater for:
1015     #  * use of STG reg [ nn(%ebx) ] where no machine reg avail
1016     #
1017     #  * GCC used an "STG reg" for its own purposes
1018     #
1019     #  * some secret uses of machine reg, requiring STG reg
1020     #    to be saved/restored
1021
1022     # The most dangerous "GCC uses" of an "STG reg" are when
1023     # the reg holds the target of a jmp -- it's tricky to
1024     # insert the patch-up code before we get to the target!
1025     # So here we change the jmps:
1026
1027     # --------------------------------------------------------
1028     # it can happen that we have jumps of the form...
1029     #   jmp *<something involving %esp>
1030     # or
1031     #   jmp <something involving another naughty register...>
1032     #
1033     # a reasonably-common case is:
1034     #
1035     #   movl $_blah,<bad-reg>
1036     #   jmp  *<bad-reg>
1037     #
1038     # which is easily fixed as:
1039     #
1040     # sigh! try to hack around it...
1041     #
1042
1043     if ($StolenX86Regs <= 2 ) { # YURGH! spurious uses of esi?
1044         s/^\tmovl (.*),\%esi\n\tjmp \*%esi\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1045         s/^\tjmp \*(-?\d*)\((.*\%esi.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
1046         s/^\tjmp \*\%esi\n/\tmovl \%esi,\%eax\n\tjmp \*\%eax\n/g;
1047         die "$Pgm: (mangler) still have jump involving \%esi!\n$_"
1048             if /(jmp|call) .*\%esi/;
1049     }
1050     if ($StolenX86Regs <= 3 ) { # spurious uses of edi?
1051         s/^\tmovl (.*),\%edi\n\tjmp \*%edi\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1052         s/^\tjmp \*(-?\d*)\((.*\%edi.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
1053         s/^\tjmp \*\%edi\n/\tmovl \%edi,\%eax\n\tjmp \*\%eax\n/g;
1054         die "$Pgm: (mangler) still have jump involving \%edi!\n$_"
1055             if /(jmp|call) .*\%edi/;
1056     }
1057 #=  if ($StolenX86Regs <= 4 ) { # spurious uses of ecx?
1058 #=      s/^\tmovl (.*),\%ecx\n\tjmp \*%ecx\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1059 #=      s/^\tjmp \*(-?\d*)\((.*\%ecx.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
1060 #=      s/^\tjmp \*\%ecx\n/\tmovl \%ecx,\%eax\n\tjmp \*\%eax\n/g;
1061 #=      die "$Pgm: (mangler) still have jump involving \%ecx!\n$_"
1062 #=          if /(jmp|call) .*\%ecx/;
1063 #=  }
1064
1065     # OK, now we can decide what our patch-up code is going to
1066     # be:
1067     if ( $StolenX86Regs <= 2
1068          && ( /32\(\%ebx\)/ || /\%esi/ || /^\tcmps/ ) ) { # R1 (esi)
1069         $entry_patch .= "\tmovl \%esi,32(\%ebx)\n";
1070         $exit_patch  .= "\tmovl 32(\%ebx),\%esi\n";
1071         # nothing for call_{entry,exit} because %esi is callee-save
1072     }
1073     if ( $StolenX86Regs <= 3
1074          && ( /64\(\%ebx\)/ || /\%edi/ || /^\t(scas|cmps)/ ) ) { # SpA (edi)
1075         $entry_patch .= "\tmovl \%edi,64(\%ebx)\n";
1076         $exit_patch  .= "\tmovl 64(\%ebx),\%edi\n";
1077         # nothing for call_{entry,exit} because %edi is callee-save
1078     }
1079 #=  if ( $StolenX86Regs <= 4
1080 #=       && ( /80\(\%ebx\)/ || /\%ecx/ || /^\t(rep|loop)/ ) ) { # Hp (ecx)
1081 #=      $entry_patch .= "\tmovl \%ecx,80(\%ebx)\n";
1082 #=      $exit_patch  .= "\tmovl 80(\%ebx),\%ecx\n";
1083 #=
1084 #=      $call_exit_patch  .= "\tmovl \%ecx,108(\%ebx)\n";
1085 #=      $call_entry_patch .= "\tmovl 108(\%ebx),\%ecx\n";
1086 #=      # I have a really bad feeling about this if we ever
1087 #=      # have a nested call...
1088 #=      # NB: should just hide it somewhere in the C stack.
1089 #=  }
1090     # --------------------------------------------------------
1091     # next, here we go with non-%esp patching!
1092     #
1093     s/^(\t[a-z])/$entry_patch$1/; # before first instruction
1094     s/^(\tcall .*\n(\taddl \$\d+,\%esp\n)?)/$call_exit_patch$1$call_entry_patch/g; # _all_ calls
1095
1096     # fix _all_ non-local jumps:
1097
1098     s/^\tjmp \*${T_X86_PRE_LLBL_PAT}/\tJMP___SL/go;
1099     s/^\tjmp ${T_X86_PRE_LLBL_PAT}/\tJMP___L/go;
1100
1101     s/^(\tjmp .*\n)/$exit_patch$1/g; # here's the fix...
1102
1103     s/^\tJMP___SL/\tjmp \*${T_X86_PRE_LLBL}/go;
1104     s/^\tJMP___L/\tjmp ${T_X86_PRE_LLBL}/go;
1105
1106     # fix post-PerformGC wrapper (re-)entries ???
1107
1108     if ($StolenX86Regs == 2 ) {
1109         die "ARGH! Jump uses \%esi or \%edi with -monly-2-regs:\n$_" 
1110             if /^\t(jmp|call) .*\%e(si|di)/;
1111 #=      die "ARGH! Jump uses \%esi, \%edi, or \%ecx with -monly-2-regs:\n$_" 
1112 #=          if /^\t(jmp|call) .*\%e(si|di|cx)/;
1113     } elsif ($StolenX86Regs == 3 ) {
1114         die "ARGH! Jump uses \%edi with -monly-3-regs:\n$_" 
1115             if /^\t(jmp|call) .*\%edi/;
1116 #=      die "ARGH! Jump uses \%edi or \%ecx with -monly-3-regs:\n$_" 
1117 #=          if /^\t(jmp|call) .*\%e(di|cx)/;
1118 #=  } elsif ($StolenX86Regs == 4 ) {
1119 #=      die "ARGH! Jump uses \%ecx with -monly-4-regs:\n$_" 
1120 #=          if /^\t(jmp|call) .*\%ecx/;
1121     }
1122
1123     # final peephole fixes
1124
1125     s/^\tmovl \%eax,36\(\%ebx\)\n\tjmp \*36\(\%ebx\)\n/\tmovl \%eax,36\(\%ebx\)\n\tjmp \*\%eax\n/;
1126 # the short form may tickle perl bug:
1127 #    s/^\tmovl \$${T_US}(.*),(\%e[abcd]x)\n\tjmp \*$2/\tjmp $T_US$1/g;
1128     s/^\tmovl \$${T_US}(.*),\%eax\n\tjmp \*\%eax/\tjmp $T_US$1/g;
1129     s/^\tmovl \$${T_US}(.*),\%ebx\n\tjmp \*\%ebx/\tjmp $T_US$1/g;
1130     s/^\tmovl \$${T_US}(.*),\%ecx\n\tjmp \*\%ecx/\tjmp $T_US$1/g;
1131     s/^\tmovl \$${T_US}(.*),\%edx\n\tjmp \*\%edx/\tjmp $T_US$1/g;
1132
1133     # Hacks to eliminate some reloads of Hp.  Worth about 5% code size.
1134     # We could do much better than this, but at least it catches about
1135     # half of the unnecessary reloads.
1136     # Note that these will stop working if either:
1137     #  (i) the offset of Hp from BaseReg changes from 80, or
1138     #  (ii) the register assignment of BaseReg changes from %ebx
1139
1140     s/^\tmovl 80\(\%ebx\),\%e.x\n\tmovl \$(.*),(-?[0-9]*)\(\%e.x\)\n\tmovl 80\(\%ebx\),\%e(.)x/\tmovl 80\(\%ebx\),\%e$3x\n\tmovl \$$1,$2\(\%e$3x\)/g;
1141
1142     s/^\tmovl 80\(\%ebx\),\%e(.)x\n\tmovl (.*),\%e(.)x\n\tmovl \%e$3x,(-?[0-9]*\(\%e$1x\))\n\tmovl 80\(\%ebx\),\%e$1x/\tmovl 80\(\%ebx\),\%e$1x\n\tmovl $2,\%e$3x\n\tmovl \%e$3x,$4/g;
1143
1144     s/^\tmovl 80\(\%ebx\),\%edx((\n\t(movl|addl) .*,((-?[0-9]*\(.*)|(\%e[abc]x)))+)\n\tmovl 80\(\%ebx\),\%edx/\tmovl 80\(\%ebx\),\%edx$1/g;
1145     s/^\tmovl 80\(\%ebx\),\%eax((\n\t(movl|addl) .*,((-?[0-9]*\(.*)|(\%e[bcd]x)))+)\n\tmovl 80\(\%ebx\),\%eax/\tmovl 80\(\%ebx\),\%eax$1/g;
1146
1147     # --------------------------------------------------------
1148     # that's it -- print it
1149     #
1150     #die "Funny jumps?\n$_" if /${T_X86_BADJMP}/o; # paranoia
1151
1152     print OUTASM $_;
1153
1154     if ( $need_fallthru_patch ) { # exit patch for end of slow entry code
1155         print OUTASM $exit_patch;
1156         # ToDo: make it not print if there is a "jmp" at the end
1157     }
1158 }
1159 \end{code}
1160
1161 \begin{code}
1162 sub init_FUNNY_THINGS {
1163     %KNOWN_FUNNY_THING = (
1164         "${T_US}CheckHeapCode${T_POST_LBL}", 1,
1165         "${T_US}CommonUnderflow${T_POST_LBL}", 1,
1166         "${T_US}Continue${T_POST_LBL}", 1,
1167         "${T_US}EnterNodeCode${T_POST_LBL}", 1,
1168         "${T_US}ErrorIO_call_count${T_POST_LBL}", 1,
1169         "${T_US}ErrorIO_innards${T_POST_LBL}", 1,
1170         "${T_US}IndUpdRetDir${T_POST_LBL}", 1,
1171         "${T_US}IndUpdRetV0${T_POST_LBL}", 1,
1172         "${T_US}IndUpdRetV1${T_POST_LBL}", 1,
1173         "${T_US}IndUpdRetV2${T_POST_LBL}", 1,
1174         "${T_US}IndUpdRetV3${T_POST_LBL}", 1,
1175         "${T_US}IndUpdRetV4${T_POST_LBL}", 1,
1176         "${T_US}IndUpdRetV5${T_POST_LBL}", 1,
1177         "${T_US}IndUpdRetV6${T_POST_LBL}", 1,
1178         "${T_US}IndUpdRetV7${T_POST_LBL}", 1,
1179         "${T_US}PrimUnderflow${T_POST_LBL}", 1,
1180         "${T_US}StackUnderflowEnterNode${T_POST_LBL}", 1,
1181         "${T_US}StdErrorCode${T_POST_LBL}", 1,
1182         "${T_US}UnderflowVect0${T_POST_LBL}", 1,
1183         "${T_US}UnderflowVect1${T_POST_LBL}", 1,
1184         "${T_US}UnderflowVect2${T_POST_LBL}", 1,
1185         "${T_US}UnderflowVect3${T_POST_LBL}", 1,
1186         "${T_US}UnderflowVect4${T_POST_LBL}", 1,
1187         "${T_US}UnderflowVect5${T_POST_LBL}", 1,
1188         "${T_US}UnderflowVect6${T_POST_LBL}", 1,
1189         "${T_US}UnderflowVect7${T_POST_LBL}", 1,
1190         "${T_US}UpdErr${T_POST_LBL}", 1,
1191         "${T_US}UpdatePAP${T_POST_LBL}", 1,
1192         "${T_US}WorldStateToken${T_POST_LBL}", 1,
1193         "${T_US}_Enter_Internal${T_POST_LBL}", 1,
1194         "${T_US}_PRMarking_MarkNextAStack${T_POST_LBL}", 1,
1195         "${T_US}_PRMarking_MarkNextBStack${T_POST_LBL}", 1,
1196         "${T_US}_PRMarking_MarkNextCAF${T_POST_LBL}", 1,
1197         "${T_US}_PRMarking_MarkNextGA${T_POST_LBL}", 1,
1198         "${T_US}_PRMarking_MarkNextRoot${T_POST_LBL}", 1,
1199         "${T_US}_PRMarking_MarkNextSpark${T_POST_LBL}", 1,
1200         "${T_US}_PRMarking_MarkNextEvent${T_POST_LBL}", 1,
1201         "${T_US}_PRMarking_MarkNextClosureInFetchBuffer${T_POST_LBL}", 1,
1202         "${T_US}_Scavenge_Forward_Ref${T_POST_LBL}", 1,
1203         "${T_US}__std_entry_error__${T_POST_LBL}", 1,
1204         "${T_US}_startMarkWorld${T_POST_LBL}", 1,
1205         "${T_US}resumeThread${T_POST_LBL}", 1,
1206         "${T_US}startCcRegisteringWorld${T_POST_LBL}", 1,
1207         "${T_US}startEnterFloat${T_POST_LBL}", 1,
1208         "${T_US}startEnterInt${T_POST_LBL}", 1,
1209         "${T_US}startPerformIO${T_POST_LBL}", 1,
1210         "${T_US}startStgWorld${T_POST_LBL}", 1,
1211         "${T_US}stopPerformIO${T_POST_LBL}", 1
1212     );
1213 }
1214 \end{code}
1215
1216 The following table reversal is used for both info tables and return
1217 vectors.  In both cases, we remove the first entry from the table,
1218 reverse the table, put the label at the end, and paste some code
1219 (that which is normally referred to by the first entry in the table)
1220 right after the table itself.  (The code pasting is done elsewhere.)
1221
1222 \begin{code}
1223 sub rev_tbl {
1224     local($symb, $tbl, $discard1) = @_;
1225
1226     local($before) = '';
1227     local($label) = '';
1228     local(@imports) = (); # hppa only
1229     local(@words) = ();
1230     local($after) = '';
1231     local(@lines) = split(/\n/, $tbl);
1232     local($i, $extra, $words_to_pad, $j);
1233    
1234     # see comment in mangleAsm as to why this silliness is needed.
1235     local($TDOTWORD) = ${T_DOT_WORD};
1236     local($TDOTGLOBAL) = ${T_DOT_GLOBAL};
1237     local($TUS) = ${T_US};
1238     local($TPOSTLBL) = ${T_POST_LBL};
1239
1240     for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t$TDOTWORD\s+/o; $i++) {
1241         $label .= $lines[$i] . "\n",
1242             next if $lines[$i] =~ /^[A-Za-z0-9_]+_info$TPOSTLBL[@]?$/o
1243                  || $lines[$i] =~ /$TDOTGLOBAL/o
1244                  || $lines[$i] =~ /^$TUS[@]?vtbl_\S+$TPOSTLBL[@]?$/o;
1245
1246         $before .= $lines[$i] . "\n"; # otherwise...
1247     }
1248
1249     if ( $TargetPlatform !~ /^hppa/ ) {
1250         for ( ; $i <= $#lines && $lines[$i] =~ /^\t$TDOTWORD\s+/o; $i++) {
1251             push(@words, $lines[$i]);
1252         }
1253     } else { # hppa weirdness
1254         for ( ; $i <= $#lines && $lines[$i] =~ /^\s+\.(word|IMPORT)/; $i++) {
1255             if ($lines[$i] =~ /^\s+\.IMPORT/) {
1256                 push(@imports, $lines[$i]);
1257             } else {
1258                 # We don't use HP's ``function pointers''
1259                 # We just use labels in code space, like normal people
1260                 $lines[$i] =~ s/P%//;
1261                 push(@words, $lines[$i]);
1262             }
1263         }
1264     }
1265
1266     # now throw away the first word (entry code):
1267     shift(@words) if $discard1;
1268
1269 # Padding removed to reduce code size and improve performance on Pentiums.
1270 # Simon M. 13/4/96
1271     # for 486-cache-friendliness, we want our tables aligned
1272     # on 16-byte boundaries (.align 4).  Let's pad:
1273 #    $extra = ($#words + 1) % 4;
1274 #    $words_to_pad = ($extra == 0) ? 0 : 4 - $extra;
1275 #    for ($j = 0; $j < $words_to_pad; $j++) { push(@words, "\t${T_DOT_WORD} 0"); }
1276
1277     for (; $i <= $#lines; $i++) {
1278         $after .= $lines[$i] . "\n";
1279     }
1280
1281     # Alphas:If we have anonymous text (not part of a procedure), the
1282     # linker may complain about missing exception information.  Bleh.
1283     if ( $TargetPlatform =~ /^alpha-/ && $label =~ /^([A-Za-z0-9_]+):$/) {
1284         $before = "\t.ent $1\n" . $before;
1285         $after .= "\t.end $1\n";
1286     }
1287
1288     $tbl = $before
1289          . (($TargetPlatform !~ /^hppa/) ? '' : join("\n", @imports) . "\n")
1290          . join("\n", (reverse @words)) . "\n"
1291          . $label . $after;
1292
1293 #   print STDERR "before=$before\n";
1294 #   print STDERR "label=$label\n";
1295 #   print STDERR "words=",(reverse @words),"\n";
1296 #   print STDERR "after=$after\n";
1297
1298     $tbl;
1299 }
1300 \end{code}
1301
1302 \begin{code}
1303 sub mini_mangle_asm_i386 {
1304     local($in_asmf, $out_asmf) = @_;
1305
1306     &init_TARGET_STUFF();
1307
1308     # see mangleAsm comment
1309     local($TUS) = ${T_US};
1310     local($TPOSTLBL)=${T_POST_LBL};
1311
1312     open(INASM, "< $in_asmf")
1313         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
1314     open(OUTASM,"> $out_asmf")
1315         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
1316
1317     while (<INASM>) {
1318         print OUTASM;
1319
1320         next unless
1321             /^$TUS[@]?(PerformGC|StackOverflow|Yield|PerformReschedule)_wrapper$TPOSTLBL\n/o;
1322         print OUTASM "\tmovl \%esp, ${T_US}__temp_esp\n";
1323         print OUTASM "\tmovl \%eax, ${T_US}__temp_eax\n";
1324     }
1325
1326     # finished:
1327     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
1328     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
1329 }
1330 \end{code}
1331
1332 The HP is a major nuisance.  The threaded code mangler moved info
1333 tables from data space to code space, but unthreaded code in the RTS
1334 still has references to info tables in data space.  Since the HP
1335 linker is very precise about where symbols live, we need to patch the
1336 references in the unthreaded RTS as well.
1337
1338 \begin{code}
1339 sub mini_mangle_asm_hppa {
1340     local($in_asmf, $out_asmf) = @_;
1341
1342     open(INASM, "< $in_asmf")
1343         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
1344     open(OUTASM,"> $out_asmf")
1345         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
1346
1347     while (<INASM>) {
1348         s/_info,DATA/_info,CODE/;   # Move _info references to code space
1349         s/P%_PR/_PR/;
1350         print OUTASM;
1351     }
1352
1353     # finished:
1354     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
1355     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
1356 }
1357
1358 # make "require"r happy...
1359 1;
1360 \end{code}