[project @ 2005-04-30 15:45:58 by wolfgang]
[ghc-hetmet.git] / ghc / driver / mangler / 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 General note [chak]: Many regexps are very fragile because they rely on white
17 space being in the right place.  This caused trouble with gcc 2.95 (at least
18 on Linux), where the use of white space in .s files generated by gcc suddenly 
19 changed.  To guarantee compatibility across different versions of gcc, make
20 sure (at least on i386-.*-linux) that regexps tolerate varying amounts of white
21 space between an assembler statement and its arguments as well as after a the
22 comma separating multiple arguments.  
23
24 \emph{For the time being, I have corrected the regexps for i386-.*-linux.  I
25 didn't touch all the regexps for other i386 platforms, as I don't have
26 a box to test these changes.}
27
28 HPPA specific notes:
29 \begin{itemize}
30 \item
31 The HP linker is very picky about symbols being in the appropriate
32 space (code vs. data).  When we mangle the threaded code to put the
33 info tables just prior to the code, they wind up in code space
34 rather than data space.  This means that references to *_info from
35 un-mangled parts of the RTS (e.g. unthreaded GC code) get
36 unresolved symbols.  Solution:  mini-mangler for .c files on HP.  I
37 think this should really be triggered in the driver by a new -rts
38 option, so that user code doesn't get mangled inappropriately.
39 \item
40 With reversed tables, jumps are to the _info label rather than to
41 the _entry label.  The _info label is just an address in code
42 space, rather than an entry point with the descriptive blob we
43 talked about yesterday.  As a result, you can't use the call-style
44 JMP_ macro.  However, some JMP_ macros take _info labels as targets
45 and some take code entry points within the RTS.  The latter won't
46 work with the goto-style JMP_ macro.  Sigh.  Solution: Use the goto
47 style JMP_ macro, and mangle some more assembly, changing all
48 "RP'literal" and "LP'literal" references to "R'literal" and
49 "L'literal," so that you get the real address of the code, rather
50 than the descriptive blob.  Also change all ".word P%literal"
51 entries in info tables and vector tables to just ".word literal,"
52 for the same reason.  Advantage: No more ridiculous call sequences.
53 \end{itemize}
54
55 %************************************************************************
56 %*                                                                      *
57 \subsection{Top-level code}
58 %*                                                                      *
59 %************************************************************************
60
61 \begin{code}
62 $TargetPlatform = $TARGETPLATFORM;
63
64 ($Pgm = $0) =~ s|.*/||;
65 $ifile = $ARGV[0];
66 $ofile = $ARGV[1];
67
68 if ( $TargetPlatform =~ /^i386-/ ) {
69     if ($ARGV[2] eq '') {
70         $StolenX86Regs = 4;
71     } else {
72         $StolenX86Regs = $ARGV[2];
73     }
74 }
75
76 &mangle_asm($ifile,$ofile);
77
78 exit(0);
79 \end{code}
80
81 %************************************************************************
82 %*                                                                      *
83 \subsection{Constants for various architectures}
84 %*                                                                      *
85 %************************************************************************
86
87 \begin{code}
88 sub init_TARGET_STUFF {
89
90     #--------------------------------------------------------#
91     if ( $TargetPlatform =~ /^alpha-.*-.*/ ) {
92
93     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
94     $T_US           = ''; # _ if symbols have an underscore on the front
95     $T_PRE_APP      = 'DONT THINK THIS APPLIES'; # regexp that says what comes before APP/NO_APP
96     $T_CONST_LBL    = '^\$L?C(\d+):$'; # regexp for what such a lbl looks like
97     $T_POST_LBL     = ':';
98
99     $T_MOVE_DIRVS   = '^(\s*(\$.*\.\.ng:|\.align\s+\d+|\.(globl|ent)\s+\S+|\#.*|\.(file|loc)\s+\S+\s+\S+|\.text|\.r?data)\n)';
100     $T_COPY_DIRVS   = '^\s*(\$.*\.\.ng:|\#|\.(file|globl|ent|loc))';
101
102     $T_DOT_WORD     = '\.(long|quad|byte|word)';
103     $T_DOT_GLOBAL   = '^\t\.globl';
104     $T_HDR_literal  = "\.rdata\n\t\.align 3\n";
105     $T_HDR_misc     = "\.text\n\t\.align 3\n";
106     $T_HDR_data     = "\.data\n\t\.align 3\n";
107     $T_HDR_rodata   = "\.rdata\n\t\.align 3\n";
108     $T_HDR_closure  = "\.data\n\t\.align 3\n";
109     $T_HDR_info     = "\.text\n\t\.align 3\n";
110     $T_HDR_entry    = "\.text\n\t\.align 3\n";
111     $T_HDR_vector   = "\.text\n\t\.align 3\n";
112
113     #--------------------------------------------------------#
114     } elsif ( $TargetPlatform =~ /^hppa/ ) {
115
116     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
117     $T_US           = ''; # _ if symbols have an underscore on the front
118     $T_PRE_APP      = 'DONT THINK THIS APPLIES'; # regexp that says what comes before APP/NO_APP
119     $T_CONST_LBL    = '^L\$C(\d+)$'; # regexp for what such a lbl looks like
120     $T_POST_LBL     = '';
121
122     $T_MOVE_DIRVS   = '^((\s+\.(IMPORT|EXPORT|PARAM).*|\s+\.align\s+\d+|\s+\.(SPACE|SUBSPA)\s+\S+|\s*)\n)';
123     $T_COPY_DIRVS   = '^\s+\.(IMPORT|EXPORT)';
124
125     $T_DOT_WORD     = '\.(blockz|word|half|byte)';
126     $T_DOT_GLOBAL   = '^\s+\.EXPORT';
127     $T_HDR_literal  = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n";
128     $T_HDR_misc     = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
129     $T_HDR_data     = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
130     $T_HDR_rodata   = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
131     $T_HDR_closure  = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
132     $T_HDR_info     = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
133     $T_HDR_entry    = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
134     $T_HDR_vector   = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
135
136     #--------------------------------------------------------#
137     } elsif ( $TargetPlatform =~ /^i386-.*-(linuxaout|freebsd2|nextstep3|cygwin32|mingw32)$/ ) {
138                                 # NeXT added but not tested. CaS
139
140     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
141     $T_US           = '_'; # _ if symbols have an underscore on the front
142     $T_PRE_APP      = '^#'; # regexp that says what comes before APP/NO_APP
143     $T_CONST_LBL    = '^LC(\d+):$';
144     $T_POST_LBL     = ':';
145     $T_X86_PRE_LLBL_PAT = 'L';
146     $T_X86_PRE_LLBL         = 'L';
147     $T_X86_BADJMP   = '^\tjmp [^L\*]';
148
149     $T_MOVE_DIRVS   = '^(\s*(\.(p2)?align\s.*|\.globl\s+\S+|\.text|\.data|\.stab[^n].*|\.type\s+.*|\.size\s+.*|\.lcomm.*)\n)';
150     $T_COPY_DIRVS   = '\.(globl|stab|lcomm)';
151     $T_DOT_WORD     = '\.(long|word|value|byte|space)';
152     $T_DOT_GLOBAL   = '\.globl';
153     $T_HDR_literal  = "\.text\n\t\.align 2\n";
154     $T_HDR_misc     = "\.text\n\t\.align 2,0x90\n";
155     $T_HDR_data     = "\.data\n\t\.align 2\n";
156     $T_HDR_rodata   = "\.text\n\t\.align 2\n";
157     $T_HDR_closure  = "\.data\n\t\.align 2\n";
158     $T_HDR_info     = "\.text\n\t\.align 2\n"; # NB: requires padding
159     $T_HDR_entry    = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
160     $T_HDR_vector   = "\.text\n\t\.align 2\n"; # NB: requires padding
161
162     #--------------------------------------------------------#
163     } elsif ( $TargetPlatform =~ /^i386-.*-(solaris2|linux|freebsd|netbsd|openbsd)$/ ) {
164
165     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
166     $T_US           = ''; # _ if symbols have an underscore on the front
167     $T_PRE_APP      = # regexp that says what comes before APP/NO_APP
168                       ($TargetPlatform =~ /-(linux|freebsd|netbsd|openbsd)$/) ? '#' : '/' ;
169     $T_CONST_LBL    = '^\.LC(\d+):$'; # regexp for what such a lbl looks like
170     $T_POST_LBL     = ':';
171     $T_X86_PRE_LLBL_PAT = '\.L';
172     $T_X86_PRE_LLBL         = '.L';
173     $T_X86_BADJMP   = '^\tjmp\s+[^\.\*]';
174
175     $T_MOVE_DIRVS   = '^(\s*(\.(p2)?align\s.*|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.size\s+\S+\s*,\s*\d+|\.ident.*|\.local.*)\n)';
176     $T_COPY_DIRVS   = '^\s*\.(globl|type|size|local)';
177
178     $T_DOT_WORD     = '\.(long|value|word|byte|zero)';
179     $T_DOT_GLOBAL   = '\.globl';
180     $T_HDR_literal  = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11)
181     $T_HDR_misc     = "\.text\n\t\.align 4\n";
182     $T_HDR_data     = "\.data\n\t\.align 4\n";
183     $T_HDR_rodata   = "\.section\t\.rodata\n\t\.align 4\n";
184     $T_HDR_closure  = "\.data\n\t\.align 4\n";
185     $T_HDR_info     = "\.text\n\t\.align 4\n";
186     $T_HDR_entry    = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
187     $T_HDR_vector   = "\.text\n\t\.align 4\n"; # NB: requires padding
188
189     #--------------------------------------------------------#
190     } elsif ( $TargetPlatform =~ /^ia64-.*-linux$/ ) {
191
192     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
193     $T_US           = ''; # _ if symbols have an underscore on the front
194     $T_PRE_APP      = '#';
195     $T_CONST_LBL    = '^\.LC(\d+):$'; # regexp for what such a lbl looks like
196     $T_POST_LBL     = ':';
197
198     $T_MOVE_DIRVS   = '^(\s*\.(global|proc|pred\.safe_across_calls|text|data|section|subsection|align|size|type|ident)\s+.*\n)';
199     $T_COPY_DIRVS   = '\.(global|proc)';
200
201     $T_DOT_WORD     = '\.(long|value|byte|zero)';
202     $T_DOT_GLOBAL   = '\.global';
203     $T_HDR_literal  = "\.section\t\.rodata\n";
204     $T_HDR_misc     = "\.text\n\t\.align 8\n";
205     $T_HDR_data     = "\.data\n\t\.align 8\n";
206     $T_HDR_rodata   = "\.section\t\.rodata\n\t\.align 8\n";
207     $T_HDR_closure  = "\.data\n\t\.align 8\n";
208     $T_HDR_info     = "\.text\n\t\.align 8\n";
209     $T_HDR_entry    = "\.text\n\t\.align 16\n";
210     $T_HDR_vector   = "\.text\n\t\.align 8\n";
211
212     #--------------------------------------------------------#
213     } elsif ( $TargetPlatform =~ /^x86_64-.*-(linux|openbsd)$/ ) {
214
215     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
216     $T_US           = ''; # _ if symbols have an underscore on the front
217     $T_PRE_APP      = '#';
218     $T_CONST_LBL    = '^\.LC(\d+):$'; # regexp for what such a lbl looks like
219     $T_POST_LBL     = ':';
220
221     $T_MOVE_DIRVS   = '^(\s*\.(globl|text|data|section|align|size|type|ident|local)\s+.*\n)';
222     $T_COPY_DIRVS   = '\.(globl|local)';
223
224     $T_DOT_WORD     = '\.(quad|long|value|byte|zero)';
225     $T_DOT_GLOBAL   = '\.global';
226
227     $T_HDR_literal16 = "\.section\t\.rodata.cst16\n\t.align 16\n";
228     $T_HDR_literal  = "\.section\t\.rodata\n";
229
230     $T_HDR_misc     = "\.text\n\t\.align 8\n";
231     $T_HDR_data     = "\.data\n\t\.align 8\n";
232     $T_HDR_rodata   = "\.section\t\.rodata\n\t\.align 8\n";
233
234         # the assembler on x86_64/Linux refuses to generate code for
235         #   .quad  x - y
236         # where x is in the text section and y in the rodata section.
237         # It works if y is in the text section, though.  This is probably
238         # going to cause difficulties for PIC, I imagine.
239     $T_HDR_relrodata= "\.text\n\t\.align 8\n";
240
241     $T_HDR_closure  = "\.data\n\t\.align 8\n";
242     $T_HDR_info     = "\.text\n\t\.align 8\n";
243     $T_HDR_entry    = "\.text\n\t\.align 8\n";
244     $T_HDR_vector   = "\.text\n\t\.align 8\n";
245
246     #--------------------------------------------------------#
247     } elsif ( $TargetPlatform =~ /^m68k-.*-sunos4/ ) {
248
249     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
250     $T_US           = '_'; # _ if symbols have an underscore on the front
251     $T_PRE_APP      = '^# MAY NOT APPLY'; # regexp that says what comes before APP/NO_APP
252     $T_CONST_LBL    = '^LC(\d+):$';
253     $T_POST_LBL     = ':';
254
255     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.proc\s+\d+|\.const|\.cstring|\.globl\s+\S+|\.text|\.data|\.even|\.stab[^n].*)\n)';
256     $T_COPY_DIRVS   = '\.(globl|proc|stab)';
257
258     $T_DOT_WORD     = '\.long';
259     $T_DOT_GLOBAL   = '\.globl';
260     $T_HDR_literal  = "\.text\n\t\.even\n";
261     $T_HDR_misc     = "\.text\n\t\.even\n";
262     $T_HDR_data     = "\.data\n\t\.even\n";
263     $T_HDR_rodata   = "\.text\n\t\.even\n";
264     $T_HDR_closure  = "\.data\n\t\.even\n";
265     $T_HDR_info     = "\.text\n\t\.even\n";
266     $T_HDR_entry    = "\.text\n\t\.even\n";
267     $T_HDR_vector   = "\.text\n\t\.even\n";
268
269     #--------------------------------------------------------#
270     } elsif ( $TargetPlatform =~ /^mips-.*/ ) {
271
272     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
273     $T_US           = ''; # _ if symbols have an underscore on the front
274     $T_PRE_APP      = '^\s*#'; # regexp that says what comes before APP/NO_APP
275     $T_CONST_LBL    = '^\$LC(\d+):$'; # regexp for what such a lbl looks like
276     $T_POST_LBL     = ':';
277
278     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.(globl|ent)\s+\S+|\.text|\.r?data)\n)';
279     $T_COPY_DIRVS   = '\.(globl|ent)';
280
281     $T_DOT_WORD     = '\.word';
282     $T_DOT_GLOBAL   = '^\t\.globl';
283     $T_HDR_literal  = "\t\.rdata\n\t\.align 2\n";
284     $T_HDR_misc     = "\t\.text\n\t\.align 2\n";
285     $T_HDR_data     = "\t\.data\n\t\.align 2\n";
286     $T_HDR_rodata   = "\t\.rdata\n\t\.align 2\n";
287     $T_HDR_closure  = "\t\.data\n\t\.align 2\n";
288     $T_HDR_info     = "\t\.text\n\t\.align 2\n";
289     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
290     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
291
292     #--------------------------------------------------------#
293     } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ ) {
294                                 # Apple PowerPC Darwin/MacOS X.
295     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
296     $T_US           = '_'; # _ if symbols have an underscore on the front
297     $T_PRE_APP      = 'DOESNT APPLY'; # regexp that says what comes before APP/NO_APP
298     $T_CONST_LBL    = '^\LC\d+:'; # regexp for what such a lbl looks like
299     $T_POST_LBL     = ':';
300
301     $T_MOVE_DIRVS   = '^(\s*(\.align \d+|\.text|\.data|\.const_data|\.cstring|\.non_lazy_symbol_pointer|\.const|\.static_const|\.literal4|\.literal8|\.static_data|\.globl \S+|\.section .*|\.lcomm.*)\n)';
302     $T_COPY_DIRVS   = '\.(globl|lcomm)';
303
304     $T_DOT_WORD     = '\.(long|short|byte|fill|space)';
305     $T_DOT_GLOBAL   = '\.globl';
306     $T_HDR_toc      = "\.toc\n";
307     $T_HDR_literal  = "\t\.const\n\t\.align 2\n";
308     $T_HDR_misc     = "\t\.text\n\t\.align 2\n";
309     $T_HDR_data     = "\t\.data\n\t\.align 2\n";
310     $T_HDR_rodata   = "\t\.const\n\t\.align 2\n";
311     $T_HDR_relrodata= "\t\.const_data\n\t\.align 2\n";
312     $T_HDR_closure  = "\t\.data\n\t\.align 2\n";
313     $T_HDR_info     = "\t\.text\n\t\.align 2\n";
314     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
315     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
316
317     #--------------------------------------------------------#
318     } elsif ( $TargetPlatform =~ /^powerpc-.*-linux/ ) {
319                                 # PowerPC Linux
320     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
321     $T_US           = ''; # _ if symbols have an underscore on the front
322     $T_PRE_APP      = '^#'; # regexp that says what comes before APP/NO_APP
323     $T_CONST_LBL    = '^\.LC\d+:'; # regexp for what such a lbl looks like
324     $T_POST_LBL     = ':';
325
326     $T_MOVE_DIRVS   = '^(\s*(\.(p2)?align\s+\d+(,\s*0x90)?|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.size\s+\S+\s*,\s*\d+|\.ident.*|\.local.*)\n)';
327     $T_COPY_DIRVS   = '^\s*\.(globl|type|size|local)';
328
329     $T_DOT_WORD     = '\.(long|short|byte|fill|space)';
330     $T_DOT_GLOBAL   = '\.globl';
331     $T_HDR_toc      = "\.toc\n";
332     $T_HDR_literal  = "\t\.section\t.rodata\n\t\.align 2\n";
333     $T_HDR_misc     = "\t\.text\n\t\.align 2\n";
334     $T_HDR_data     = "\t\.data\n\t\.align 2\n";
335     $T_HDR_rodata   = "\t\.section\t.rodata\n\t\.align 2\n";
336     $T_HDR_closure  = "\t\.data\n\t\.align 2\n";
337     $T_HDR_info     = "\t\.text\n\t\.align 2\n";
338     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
339     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
340
341     #--------------------------------------------------------#
342     } elsif ( $TargetPlatform =~ /^powerpc64-.*-linux/ ) {
343                                 # PowerPC 64 Linux
344     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
345     $T_US           = '\.'; # _ if symbols have an underscore on the front
346     $T_PRE_APP      = '^#'; # regexp that says what comes before APP/NO_APP
347     $T_CONST_LBL    = '^\.LC\d+:'; # regexp for what such a lbl looks like
348     $T_POST_LBL     = ':';
349
350     $T_MOVE_DIRVS   = '^(\s*(\.(p2)?align\s+\d+(,\s*0x90)?|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.size\s+\S+\s*,\s*\d+|\.ident.*|\.local.*)\n)';
351     $T_COPY_DIRVS   = '^\s*\.(globl|type|size|local)';
352
353     $T_DOT_WORD     = '\.(long|short|byte|fill|space)';
354     $T_DOT_GLOBAL   = '\.globl';
355     $T_HDR_toc      = "\.toc\n";
356     $T_HDR_literal  = "\t\.section\t\".toc\",\"aw\"\n";
357     $T_HDR_misc     = "\t\.text\n\t\.align 2\n";
358     $T_HDR_data     = "\t\.data\n\t\.align 2\n";
359     $T_HDR_rodata   = "\t\.section\t.rodata\n\t\.align 2\n";
360     $T_HDR_closure  = "\t\.data\n\t\.align 2\n";
361     $T_HDR_info     = "\t\.text\n\t\.align 2\n";
362     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
363     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
364
365     #--------------------------------------------------------#
366     } elsif ( $TargetPlatform =~ /^sparc-.*-(solaris2|openbsd)/ ) {
367
368     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
369     $T_US           = ''; # _ if symbols have an underscore on the front
370     $T_PRE_APP      = 'DOES NOT SEEM TO APPLY'; # regexp that says what comes before APP/NO_APP
371     $T_CONST_LBL    = '^\.LLC(\d+):$'; # regexp for what such a lbl looks like
372     $T_POST_LBL     = ':';
373
374     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*|\s*\.section.*|\s+\.type.*|\s+\.size.*)\n)';
375     $T_COPY_DIRVS   = '\.(global|proc|stab)';
376
377     $T_DOT_WORD     = '\.(long|word|byte|half|skip|uahalf|uaword)';
378     $T_DOT_GLOBAL   = '^\t\.global';
379     $T_HDR_literal  = "\.text\n\t\.align 8\n";
380     $T_HDR_misc     = "\.text\n\t\.align 4\n";
381     $T_HDR_data     = "\.data\n\t\.align 8\n";
382     $T_HDR_rodata   = "\.text\n\t\.align 4\n";
383     $T_HDR_closure  = "\.data\n\t\.align 4\n";
384     $T_HDR_info     = "\.text\n\t\.align 4\n";
385     $T_HDR_entry    = "\.text\n\t\.align 4\n";
386     $T_HDR_vector   = "\.text\n\t\.align 4\n";
387
388     #--------------------------------------------------------#
389     } elsif ( $TargetPlatform =~ /^sparc-.*-sunos4/ ) {
390
391     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
392     $T_US           = '_'; # _ if symbols have an underscore on the front
393     $T_PRE_APP      = '^# DOES NOT SEEM TO APPLY'; # regexp that says what comes before APP/NO_APP
394     $T_CONST_LBL    = '^LC(\d+):$';
395     $T_POST_LBL     = ':';
396
397     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*)\n)';
398     $T_COPY_DIRVS   = '\.(global|proc|stab)';
399
400     $T_DOT_WORD     = '\.word';
401     $T_DOT_GLOBAL   = '^\t\.global';
402     $T_HDR_literal  = "\.text\n\t\.align 8\n";
403     $T_HDR_misc     = "\.text\n\t\.align 4\n";
404     $T_HDR_data     = "\.data\n\t\.align 8\n";
405     $T_HDR_rodata   = "\.text\n\t\.align 4\n";
406     $T_HDR_closure  = "\.data\n\t\.align 4\n";
407     $T_HDR_info     = "\.text\n\t\.align 4\n";
408     $T_HDR_entry    = "\.text\n\t\.align 4\n";
409     $T_HDR_vector   = "\.text\n\t\.align 4\n";
410
411     #--------------------------------------------------------#
412     } elsif ( $TargetPlatform =~ /^sparc-.*-linux/ ) {
413     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
414     $T_US           = ''; # _ if symbols have an underscore on the front
415     $T_PRE_APP      = '#'; # regexp that says what comes before APP/NO_APP
416                            # Probably doesn't apply anyway
417     $T_CONST_LBL    = '^\.LLC(\d+):$'; # regexp for what such a lbl looks like
418     $T_POST_LBL     = ':';
419
420     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.seg|\.stab.*|\s+?\.section.*|\s+\.type.*|\s+\.size.*)\n)';
421     $T_COPY_DIRVS   = '\.(global|globl|proc|stab)';
422
423     $T_DOT_WORD     = '\.(long|word|nword|xword|byte|half|short|skip|uahalf|uaword)';
424     $T_DOT_GLOBAL   = '^\t\.global';
425     $T_HDR_literal  = "\.text\n\t\.align 8\n";
426     $T_HDR_misc     = "\.text\n\t\.align 4\n";
427     $T_HDR_data     = "\.data\n\t\.align 8\n";
428     $T_HDR_rodata   = "\.text\n\t\.align 4\n";
429     $T_HDR_closure  = "\.data\n\t\.align 4\n";
430     $T_HDR_info     = "\.text\n\t\.align 4\n";
431     $T_HDR_entry    = "\.text\n\t\.align 4\n";
432     $T_HDR_vector   = "\.text\n\t\.align 4\n";
433
434     #--------------------------------------------------------#
435     } else {
436         print STDERR "$Pgm: don't know how to mangle assembly language for: $TargetPlatform\n";
437         exit 1;
438     }
439
440     if($T_HDR_relrodata eq "") {
441             # default values:
442             # relrodata defaults to rodata.
443         $T_HDR_relrodata = $T_HDR_rodata;
444     }
445
446 if ( 0 ) {
447 print STDERR "T_STABBY: $T_STABBY\n";
448 print STDERR "T_US: $T_US\n";
449 print STDERR "T_PRE_APP: $T_PRE_APP\n";
450 print STDERR "T_CONST_LBL: $T_CONST_LBL\n";
451 print STDERR "T_POST_LBL: $T_POST_LBL\n";
452 if ( $TargetPlatform =~ /^i386-/ ) {
453     print STDERR "T_X86_PRE_LLBL_PAT: $T_X86_PRE_LLBL_PAT\n";
454     print STDERR "T_X86_PRE_LLBL: $T_X86_PRE_LLBL\n";
455     print STDERR "T_X86_BADJMP: $T_X86_BADJMP\n";
456 }
457 print STDERR "T_MOVE_DIRVS: $T_MOVE_DIRVS\n";
458 print STDERR "T_COPY_DIRVS: $T_COPY_DIRVS\n";
459 print STDERR "T_DOT_WORD: $T_DOT_WORD\n";
460 print STDERR "T_HDR_literal: $T_HDR_literal\n";
461 print STDERR "T_HDR_misc: $T_HDR_misc\n";
462 print STDERR "T_HDR_data: $T_HDR_data\n";
463 print STDERR "T_HDR_rodata: $T_HDR_rodata\n";
464 print STDERR "T_HDR_closure: $T_HDR_closure\n";
465 print STDERR "T_HDR_info: $T_HDR_info\n";
466 print STDERR "T_HDR_entry: $T_HDR_entry\n";
467 print STDERR "T_HDR_vector: $T_HDR_vector\n";
468 }
469
470 }
471 \end{code}
472
473 %************************************************************************
474 %*                                                                      *
475 \subsection{Mangle away}
476 %*                                                                      *
477 %************************************************************************
478
479 \begin{code}
480 sub mangle_asm {
481     local($in_asmf, $out_asmf) = @_;
482
483     # multi-line regexp matching:
484     local($*) = 1;
485     local($i, $c);
486
487
488     &init_TARGET_STUFF();
489     &init_FUNNY_THINGS();
490
491     open(INASM, "< $in_asmf")
492         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
493     open(OUTASM,"> $out_asmf")
494         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
495
496     # read whole file, divide into "chunks":
497     #   record some info about what we've found...
498
499     @chk = ();          # contents of the chunk
500     $numchks = 0;       # number of them
501     @chkcat = ();       # what category of thing in each chunk
502     @chksymb = ();      # what symbol(base) is defined in this chunk
503     %entrychk = ();     # ditto, its entry code
504     %closurechk = ();   # ditto, the (static) closure
505     %srtchk = ();       # ditto, its SRT (for top-level things)
506     %infochk = ();      # given a symbol base, say what chunk its info tbl is in
507     %vectorchk = ();    # ditto, return vector table
508     $EXTERN_DECLS = ''; # .globl <foo> .text (MIPS only)
509
510     $i = 0; $chkcat[0] = 'misc'; $chk[0] = '';
511
512     while (<INASM>) {
513         tr/\r//d if $TargetPlatform =~ /-mingw32$/; # In case Perl doesn't convert line endings
514         next if $T_STABBY && /^\.stab.*${T_US}__stg_split_marker/o;
515         next if $T_STABBY && /^\.stab.*ghc.*c_ID/;
516         next if /^\t\.def.*endef$/;
517         next if /${T_PRE_APP}(NO_)?APP/o; 
518         next if /^;/ && $TargetPlatform =~ /^hppa/;
519
520         next if /(^$|^\t\.file\t|^ # )/ && $TargetPlatform =~ /^(mips|ia64)-/;
521
522         if ( $TargetPlatform =~ /^mips-/ 
523           && /^\t\.(globl\S+\.text|comm\t)/ ) {
524             $EXTERN_DECLS .= $_ unless /(__DISCARD__|\b(PK_|ASSIGN_)(FLT|DBL)\b)/;
525         # Treat .comm variables as data.  These show up in two (known) places:
526         #
527         #    - the module_registered variable used in the __stginit fragment.
528         #      even though these are declared static and initialised, gcc 3.3
529         #      likes to make them .comm, presumably to save space in the
530         #      object file.
531         #
532         #    - global variables used to pass arguments from C to STG in
533         #      a foreign export.  (is this still true? --SDM)
534         # 
535         } elsif ( /^\t\.comm.*$/ ) {
536             $chk[++$i]   = $_;
537             $chkcat[$i]  = 'data';
538             $chksymb[$i] = '';
539
540         # Labels ending "_str": these are literal strings.
541         } elsif ( /^${T_US}([A-Za-z0-9_]+)_str${T_POST_LBL}$/ ) {
542             $chk[++$i]   = $_;
543             $chkcat[$i]  = 'rodata';
544             $chksymb[$i] = '';
545         } elsif ( $TargetPlatform =~ /-darwin/
546                 && (/^\s*\.subsections_via_symbols/
547                   ||/^\s*\.no_dead_strip.*/)) {
548             # Don't allow Apple's linker to do any dead-stripping of symbols
549             # in this file, because it will mess up info-tables in mangled
550             # code.
551             # The .no_dead_strip directives are actually put there by
552             # the gcc3 "used" attribute on entry points.
553         
554         } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ && ( 
555                    /^\s*\.picsymbol_stub/
556                 || /^\s*\.section __TEXT,__picsymbol_stub1,.*/
557                 || /^\s*\.section __TEXT,__picsymbolstub1,.*/
558                 || /^\s*\.symbol_stub/
559                 || /^\s*\.section __TEXT,__symbol_stub1,.*/
560                 || /^\s*\.section __TEXT,__symbolstub1,.*/
561                 || /^\s*\.lazy_symbol_pointer/
562                 || /^\s*\.non_lazy_symbol_pointer/ ))
563         {
564             $chk[++$i]   = $_;
565             $chkcat[$i]  = 'dyld';
566             $chksymb[$i] = '';
567
568         } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ && $chkcat[$i] eq 'dyld' && /^\s*\.data/)
569         {       # non_lazy_symbol_ptrs that point to local symbols
570             $chk[++$i]   = $_;
571             $chkcat[$i]  = 'dyld';
572             $chksymb[$i] = '';
573
574         } elsif ( /^\s+/ ) { # most common case first -- a simple line!
575             # duplicated from the bottom
576
577             $chk[$i] .= $_;
578
579         } elsif ( /\.\.ng:$/ && $TargetPlatform =~ /^alpha-/ ) {
580             # Alphas: Local labels not to be confused with new chunks
581             $chk[$i] .= $_;
582         # NB: all the rest start with a non-space
583
584         } elsif ( $TargetPlatform =~ /^mips-/
585                && /^\d+:/ ) { # a funny-looking very-local label
586             $chk[$i] .= $_;
587
588         } elsif ( /$T_CONST_LBL/o ) {
589             $chk[++$i]   = $_;
590             $chkcat[$i]  = 'literal';
591             $chksymb[$i] = $1;
592
593         } elsif ( /^${T_US}__stg_split_marker(\d*)${T_POST_LBL}$/o ) {
594             $chk[++$i]   = $_;
595             $chkcat[$i]  = 'splitmarker';
596             $chksymb[$i] = $1;
597
598         } elsif ( /^${T_US}([A-Za-z0-9_]+)_info${T_POST_LBL}$/o ) {
599             $symb = $1;
600             $chk[++$i]   = $_;
601             $chkcat[$i]  = 'infotbl';
602             $chksymb[$i] = $symb;
603
604             die "Info table already? $symb; $i\n" if defined($infochk{$symb});
605
606             $infochk{$symb} = $i;
607
608         } elsif ( /^${T_US}([A-Za-z0-9_]+)_(entry|ret)${T_POST_LBL}$/o ) {
609             $chk[++$i]   = $_;
610             $chkcat[$i]  = 'entry';
611             $chksymb[$i] = $1;
612
613             $entrychk{$1} = $i;
614
615         } elsif ( /^${T_US}([A-Za-z0-9_]+)_closure${T_POST_LBL}$/o ) {
616             $chk[++$i]   = $_;
617             $chkcat[$i]  = 'closure';
618             $chksymb[$i] = $1;
619
620             $closurechk{$1} = $i;
621
622         } elsif ( /^${T_US}([A-Za-z0-9_]+)_srt${T_POST_LBL}$/o ) {
623             $chk[++$i]   = $_;
624             $chkcat[$i]  = 'srt';
625             $chksymb[$i] = $1;
626
627             $srtchk{$1} = $i;
628
629         } elsif ( /^${T_US}([A-Za-z0-9_]+)_ct${T_POST_LBL}$/o ) {
630             $chk[++$i]   = $_;
631             $chkcat[$i]  = 'data';
632             $chksymb[$i] = '';
633
634         } elsif ( /^${T_US}(stg_ap_stack_entries|stg_stack_save_entries|stg_arg_bitmaps)${T_POST_LBL}$/o ) {
635             $chk[++$i]   = $_;
636             $chkcat[$i]  = 'data';
637             $chksymb[$i] = '';
638
639         } elsif ( /^(${T_US}__gnu_compiled_c|gcc2_compiled\.)${T_POST_LBL}/o ) {
640             ; # toss it
641
642         } elsif ( /^${T_US}[A-Za-z0-9_]+\.\d+${T_POST_LBL}$/o
643                || /^${T_US}.*_CAT${T_POST_LBL}$/o               # PROF: _entryname_CAT
644                || /^${T_US}.*_done${T_POST_LBL}$/o              # PROF: _module_done
645                || /^${T_US}_module_registered${T_POST_LBL}$/o   # PROF: _module_registered
646                ) {
647             $chk[++$i]   = $_;
648             $chkcat[$i]  = 'data';
649             $chksymb[$i] = '';
650
651         } elsif ( /^([A-Za-z0-9_]+)\s+\.comm/ && $TargetPlatform =~ /^hppa/ ) {
652             $chk[++$i]   = $_;
653             $chkcat[$i]  = 'bss';
654             $chksymb[$i] = '';
655
656         } elsif ( /^${T_US}([A-Za-z0-9_]+)_cc(s)?${T_POST_LBL}$/o ) {
657             # all CC_ symbols go in the data section...
658             $chk[++$i]   = $_;
659             $chkcat[$i]  = 'data';
660             $chksymb[$i] = '';
661
662         } elsif ( /^${T_US}([A-Za-z0-9_]+)_(alt|dflt)${T_POST_LBL}$/o ) {
663             $chk[++$i]   = $_;
664             $chkcat[$i]  = 'misc';
665             $chksymb[$i] = '';
666         } elsif ( /^${T_US}([A-Za-z0-9_]+)_vtbl${T_POST_LBL}$/o ) {
667             $chk[++$i]   = $_;
668             $chkcat[$i]  = 'vector';
669             $chksymb[$i] = $1;
670
671             $vectorchk{$1} = $i;
672
673         } elsif ( $TargetPlatform =~ /^i386-.*-solaris2/
674              &&   /^[A-Za-z0-9][A-Za-z0-9_]*:/ ) {
675             # Some Solaris system headers contain function definitions (as
676             # opposed to mere prototypes), which end up in the .hc file when
677             # a Haskell module foreign imports the corresponding system 
678             # functions (most notably stat()).  We put them into the text 
679             # segment.  Note that this currently does not extend to function
680             # names starting with an underscore. 
681             # - chak 7/2001
682             $chk[++$i]   = $_;
683             $chkcat[$i]  = 'misc';
684             $chksymb[$i] = $1;
685
686         } elsif ( /^${T_US}[A-Za-z0-9_]/o
687                 && ( $TargetPlatform !~ /^hppa/ # need to avoid local labels in this case
688                    || ! /^L\$\d+$/ ) 
689                 && ( $TargetPlatform !~ /^powerpc64/ # we need to avoid local labels in this case
690                    || ! /^\.L\d+:$/ ) ) {
691             local($thing);
692             chop($thing = $_);
693             $thing =~ s/:$//;
694             $chk[++$i]   = $_;
695             $chksymb[$i] = '';
696             if (
697                        /^${T_US}stg_.*${T_POST_LBL}$/o          # RTS internals
698                     || /^${T_US}__stg_.*${T_POST_LBL}$/o        # more RTS internals
699                     || /^${T_US}__fexp_.*${T_POST_LBL}$/o       # foreign export
700                     || /^${T_US}.*_slow${T_POST_LBL}$/o         # slow entry
701                     || /^${T_US}__stginit.*${T_POST_LBL}$/o     # __stginit<module>
702                     || /^${T_US}.*_btm${T_POST_LBL}$/o          # large bitmaps
703                     || /^${T_US}.*_fast${T_POST_LBL}$/o         # primops
704                     || /^_uname:/o                              # x86/Solaris2
705                 )
706             {
707                 $chkcat[$i]  = 'misc';
708             } elsif (
709                        /^${T_US}.*_srtd${T_POST_LBL}$/o          # large bitmaps
710                     || /^${T_US}.*_closure_tbl${T_POST_LBL}$/o  # closure tables
711                 )
712             {
713                 $chkcat[$i] = 'relrodata';
714             } else
715             {
716                 print STDERR "Warning: retaining unknown function \`$thing' in output from C compiler\n";
717                 $chkcat[$i]  = 'unknown';
718             }
719
720         } elsif ( $TargetPlatform =~ /^powerpc-.*-linux/ && /^\.LCTOC1 = /o ) {
721                 # PowerPC Linux's large-model PIC (-fPIC) generates a gobal offset
722                 # table "by hand". Be sure to copy it over.
723                 # Note that this label and all entries in the table should actually
724                 # go into the .got2 section, but it isn't easy to distinguish them
725                 # from other constant literals (.LC\d+), so we just put everything
726                 # in .rodata.
727             $chk[++$i]   = $_;
728             $chkcat[$i]  = 'literal';
729             $chksymb[$i] = 'LCTOC1';
730         } else { # simple line (duplicated at the top)
731
732             $chk[$i] .= $_;
733         }
734     }
735     $numchks = $#chk + 1;
736
737     # open CHUNKS, ">/tmp/chunks1" or die "Cannot open /tmp/chunks1: $!\n";
738     # for (my $i = 0; $i < @chk; ++$i) { print CHUNKS "======= $i =======\n", $chk[$i] }
739     # close CHUNKS;
740
741     # the division into chunks is imperfect;
742     # we throw some things over the fence into the next
743     # chunk.
744     #
745     # also, there are things we would like to know
746     # about the whole module before we start spitting
747     # output.
748
749     local($FIRST_MANGLABLE) = ($TargetPlatform =~ /^(alpha-|hppa|mips-)/) ? 1 : 0;
750     local($FIRST_TOSSABLE ) = ($TargetPlatform =~ /^(hppa|mips-)/) ? 1 : 0;
751
752 #   print STDERR "first chunk to mangle: $FIRST_MANGLABLE\n";
753
754     # Alphas: NB: we start meddling at chunk 1, not chunk 0
755     # The first ".rdata" is quite magical; as of GCC 2.7.x, it
756     # spits a ".quad 0" in after the very first ".rdata"; we
757     # detect this special case (tossing the ".quad 0")!
758     local($magic_rdata_seen) = 0;
759   
760     # HPPAs, MIPSen: also start medding at chunk 1
761
762     for ($i = $FIRST_TOSSABLE; $i < $numchks; $i++) {
763         $c = $chk[$i]; # convenience copy
764
765 #       print STDERR "\nCHK $i (BEFORE) (",$chkcat[$i],"):\n", $c;
766
767         # toss all prologue stuff; HPPA is pretty weird
768         # (see elsewhere)
769         $c = &hppa_mash_prologue($c) if $TargetPlatform =~ /^hppa-/;
770
771         # be slightly paranoid to make sure there's
772         # nothing surprising in there
773         if ( $c =~ /--- BEGIN ---/ ) {
774             if (($p, $r) = split(/--- BEGIN ---/, $c)) {
775
776                 # remove junk whitespace around the split point
777                 $p =~ s/\t+$//;
778                 $r =~ s/^\s*\n//;
779
780                 if ($TargetPlatform =~ /^i386-/) {
781                     $p =~ s/^\tpushl\s+\%edi\n//;
782                     $p =~ s/^\tpushl\s+\%esi\n//;
783                     $p =~ s/^\tpushl\s+\%ebx\n//;
784                     $p =~ s/^\tmovl\s+\%esi,\s*\d*\(\%esp\)\n//;
785                     $p =~ s/^\tmovl\s+\%edi,\s*\d*\(\%esp\)\n//;
786                     $p =~ s/^\tsubl\s+\$\d+,\s*\%esp\n//;
787                     $p =~ s/^\tmovl\s+\$\d+,\s*\%eax\n\tcall\s+__alloca\n// if ($TargetPlatform =~ /^.*-cygwin32/);
788
789                     # GCC 3.1 is in the habit of adding spurious writes to the
790                     # stack in the prologue.  Just to be on the safe side,
791                     # chuck these over the fence into the main code.
792                     while ($p =~ /^\tmovl\s+\$\d+,\s*\d*\(\%esp\)\n/) {
793                           # print "Spurious instruction: $&";
794                           $p = $` . $';
795                           $r = $& . $r;
796                     }
797
798                 } elsif ($TargetPlatform =~ /^x86_64-/) {
799                     $p =~ s/^\tpushq\s+\%r(bx|bp|12|13|14)\n//g;
800                     $p =~ s/^\tmovq\s+\%r(bx|bp|12|13|14),\s*\d*\(\%rsp\)\n//g;
801                     $p =~ s/^\tsubq\s+\$\d+,\s*\%rsp\n//;
802
803                 } elsif ($TargetPlatform =~ /^ia64-/) {
804                     $p =~ s/^\t\.prologue .*\n//;
805                     $p =~ s/^\t\.save ar\.pfs, r\d+\n\talloc r\d+ = ar\.pfs, 0, 3[12], \d+, 0\n//;
806                     $p =~ s/^\t\.fframe \d+\n\tadds r12 = -\d+, r12\n//;
807                     $p =~ s/^\t\.save rp, r\d+\n\tmov r\d+ = b0\n//;
808                     $p =~ s/^\t\.(mii|mmi)\n//g;        # bundling is no longer sensible
809                     $p =~ s/^\t;;\n//g;         # discard stops
810                     $p =~ s/^\t\/\/.*\n//g;     # gcc inserts timings in // comments
811
812                     # GCC 3.3 saves r1 in the prologue, move this to the body
813                     if ($p =~ /^\tmov r\d+ = r1\n/) {
814                           $p = $` . $';
815                           $r = $& . $r;
816                     }
817                 } elsif ($TargetPlatform =~ /^m68k-/) {
818                     $p =~ s/^\tlink a6,#-?\d.*\n//;
819                     $p =~ s/^\tpea a6@\n\tmovel sp,a6\n//;    
820                                 # The above showed up in the asm code,
821                                 # so I added it here.
822                                 # I hope it's correct.
823                                 # CaS
824                     $p =~ s/^\tmovel d2,sp\@-\n//;
825                     $p =~ s/^\tmovel d5,sp\@-\n//; # SMmark.* only?
826                     $p =~ s/^\tmoveml \#0x[0-9a-f]+,sp\@-\n//; # SMmark.* only?
827                 } elsif ($TargetPlatform =~ /^mips-/) {
828                     # the .frame/.mask/.fmask that we use is the same
829                     # as that produced by GCC for miniInterpret; this
830                     # gives GDB some chance of figuring out what happened
831                     $FRAME = "\t.frame\t\$sp,2168,\$31\n\t.mask\t0x90000000,-4\n\t.fmask\t0x00000000,0\n";
832                     $p =~ s/^\t\.(frame).*\n/__FRAME__/g;
833                     $p =~ s/^\t\.(mask|fmask).*\n//g;
834                     $p =~ s/^\t\.cprestore.*\n/\t\.cprestore 416\n/; # 16 + 100 4-byte args
835                     $p =~ s/^\tsubu\t\$sp,\$sp,\d+\n//;
836                     $p =~ s/^\tsw\t\$31,\d+\(\$sp\)\n//;
837                     $p =~ s/^\tsw\t\$fp,\d+\(\$sp\)\n//;
838                     $p =~ s/^\tsw\t\$28,\d+\(\$sp\)\n//;
839                     $p =~ s/__FRAME__/$FRAME/;
840                 } elsif ($TargetPlatform =~ /^powerpc-apple-.*/) {
841                     $pcrel_label = $p;
842                     $pcrel_label =~ s/(.|\n)*^(\"?L\d+\$pb\"?):\n(.|\n)*/$2/ or $pcrel_label = "";
843
844                     $p =~ s/^\tmflr r0\n//;
845                     $p =~ s/^\tbl saveFP # f\d+\n//;
846                     $p =~ s/^\tbl saveFP ; save f\d+-f\d+\n//;
847                     $p =~ s/^\"?L\d+\$pb\"?:\n//;
848                     $p =~ s/^\tstmw r\d+,-\d+\(r1\)\n//;
849                     $p =~ s/^\tstfd f\d+,-\d+\(r1\)\n//g;
850                     $p =~ s/^\tstw r0,\d+\(r1\)\n//g;
851                     $p =~ s/^\tstwu r1,-\d+\(r1\)\n//; 
852                     $p =~ s/^\tstw r\d+,-\d+\(r1\)\n//g; 
853                     $p =~ s/^\tbcl 20,31,L\d+\$pb\n//;
854                     $p =~ s/^L\d+\$pb:\n//;
855                     $p =~ s/^\tmflr r31\n//;
856
857                     # This is bad: GCC 3 seems to zero-fill some local variables in the prologue
858                     # under some circumstances, only when generating position dependent code.
859                     # I have no idea why, and I don't think it is necessary, so let's toss it.
860                     $p =~ s/^\tli r\d+,0\n//g;
861                     $p =~ s/^\tstw r\d+,\d+\(r1\)\n//g;
862                 } elsif ($TargetPlatform =~ /^powerpc-.*-linux/) {
863                     $p =~ s/^\tmflr 0\n//;
864                     $p =~ s/^\tstmw \d+,\d+\(1\)\n//;
865                     $p =~ s/^\tstfd \d+,\d+\(1\)\n//g;
866                     $p =~ s/^\tstw r0,8\(1\)\n//;
867                     $p =~ s/^\tstwu 1,-\d+\(1\)\n//; 
868                     $p =~ s/^\tstw \d+,\d+\(1\)\n//g; 
869                     
870                         # GCC's "large-model" PIC (-fPIC)
871                     $pcrel_label = $p;
872                     $pcrel_label =~ s/(.|\n)*^.LCF(\d+):\n(.|\n)*/$2/ or $pcrel_label = "";
873
874                     $p =~ s/^\tbcl 20,31,.LCF\d+\n//;
875                     $p =~ s/^.LCF\d+:\n//;
876                     $p =~ s/^\tmflr 30\n//;
877                     $p =~ s/^\tlwz 0,\.LCL\d+-\.LCF\d+\(30\)\n//;
878                     $p =~ s/^\tadd 30,0,30\n//;
879
880                     # This is bad: GCC 3 seems to zero-fill some local variables in the prologue
881                     # under some circumstances, only when generating position dependent code.
882                     # I have no idea why, and I don't think it is necessary, so let's toss it.
883                     $p =~ s/^\tli \d+,0\n//g;
884                     $p =~ s/^\tstw \d+,\d+\(1\)\n//g;
885                 } elsif ($TargetPlatform =~ /^powerpc64-.*-linux/) {
886                     $p =~ s/^\tmr 31,1\n//;
887                     $p =~ s/^\tmflr 0\n//;
888                     $p =~ s/^\tstmw \d+,\d+\(1\)\n//;
889                     $p =~ s/^\tstfd \d+,-?\d+\(1\)\n//g;
890                     $p =~ s/^\tstd r0,8\(1\)\n//;
891                     $p =~ s/^\tstdu 1,-\d+\(1\)\n//; 
892                     $p =~ s/^\tstd \d+,-?\d+\(1\)\n//g; 
893                     
894                         # GCC's "large-model" PIC (-fPIC)
895                     $pcrel_label = $p;
896                     $pcrel_label =~ s/(.|\n)*^.LCF(\d+):\n(.|\n)*/$2/ or $pcrel_label = "";
897
898                     $p =~ s/^\tbcl 20,31,.LCF\d+\n//;
899                     $p =~ s/^.LCF\d+:\n//;
900                     $p =~ s/^\tmflr 30\n//;
901                     $p =~ s/^\tlwz 0,\.LCL\d+-\.LCF\d+\(30\)\n//;
902                     $p =~ s/^\tadd 30,0,30\n//;
903
904                     # This is bad: GCC 3 seems to zero-fill some local variables in the prologue
905                     # under some circumstances, only when generating position dependent code.
906                     # I have no idea why, and I don't think it is necessary, so let's toss it.
907                     $p =~ s/^\tli \d+,0\n//g;
908                     $p =~ s/^\tstd \d+,\d+\(1\)\n//g;
909                 } else {
910                     print STDERR "$Pgm: unknown prologue mangling? $TargetPlatform\n";
911                 }
912                 
913                 # HWL HACK: dont die, just print a warning
914                 #print stderr  "HWL: this should die! Prologue junk?: $p\n" if $p =~ /^\t[^\.]/;
915                 die "Prologue junk?: $p\n" if $p =~ /^\s+[^\s\.]/;
916                 
917                 # For PIC, we want to keep part of the prologue
918                 if ($TargetPlatform =~ /^powerpc-apple-.*/ && $pcrel_label ne "") {
919                     # Darwin: load the current instruction pointer into register r31
920                     $p .= "bcl 20,31,$pcrel_label\n";
921                     $p .= "$pcrel_label:\n";
922                     $p .= "\tmflr r31\n";
923                 } elsif ($TargetPlatform =~ /^powerpc-.*-linux/ && $pcrel_label ne "") {
924                     # Linux: load the GOT pointer into register 30
925                     $p .= "\tbcl 20,31,.LCF$pcrel_label\n";
926                     $p .= ".LCF$pcrel_label:\n";
927                     $p .= "\tmflr 30\n";
928                     $p .= "\tlwz 0,.LCL$pcrel_label-.LCF$pcrel_label(30)\n";
929                     $p .= "\tadd 30,0,30\n";
930                 }
931                 
932                 # glue together what's left
933                 $c = $p . $r;
934             }
935         }
936
937         if ( $TargetPlatform =~ /^mips-/ ) {
938             # MIPS: first, this basic sequence may occur "--- END ---" or not
939             $c =~ s/^\tlw\t\$31,\d+\(\$sp\)\n\taddu\t\$sp,\$sp,\d+\n\tj\t\$31\n\t\.end/\t\.end/;
940         }
941
942         # toss all epilogue stuff; again, paranoidly
943         if ( $c =~ /--- END ---/ ) {
944             if (($r, $e) = split(/--- END ---/, $c)) {
945                 if ($TargetPlatform =~ /^i386-/) {
946                     $e =~ s/^\tret\n//;
947                     $e =~ s/^\tpopl\s+\%edi\n//;
948                     $e =~ s/^\tpopl\s+\%esi\n//;
949                     $e =~ s/^\tpopl\s+\%edx\n//;
950                     $e =~ s/^\tpopl\s+\%ecx\n//;
951                     $e =~ s/^\taddl\s+\$\d+,\s*\%esp\n//;
952                     $e =~ s/^\tsubl\s+\$-\d+,\s*\%esp\n//;
953                 } elsif ($TargetPlatform =~ /^ia64-/) {
954                     $e =~ s/^\tmov ar\.pfs = r\d+\n//;
955                     $e =~ s/^\tmov b0 = r\d+\n//;
956                     $e =~ s/^\t\.restore sp\n\tadds r12 = \d+, r12\n//;
957                     $e =~ s/^\tbr\.ret\.sptk\.many b0\n//;
958                     $e =~ s/^\t\.(mii|mmi|mib)\n//g;    # bundling is no longer sensible
959                     $e =~ s/^\t;;\n//g;                 # discard stops - stop at end of body is sufficient
960                     $e =~ s/^\t\/\/.*\n//g;             # gcc inserts timings in // comments
961                 } elsif ($TargetPlatform =~ /^m68k-/) {
962                     $e =~ s/^\tunlk a6\n//;
963                     $e =~ s/^\trts\n//;
964                 } elsif ($TargetPlatform =~ /^mips-/) {
965                     $e =~ s/^\tlw\t\$31,\d+\(\$sp\)\n//;
966                     $e =~ s/^\tlw\t\$fp,\d+\(\$sp\)\n//;
967                     $e =~ s/^\taddu\t\$sp,\$sp,\d+\n//;
968                     $e =~ s/^\tj\t\$31\n//;
969                 } elsif ($TargetPlatform =~ /^powerpc-apple-.*/) {
970                     $e =~ s/^\taddi r1,r1,\d+\n//;
971                     $e =~ s/^\tlwz r\d+,\d+\(r1\)\n//; 
972                     $e =~ s/^\tlmw r\d+,-\d+\(r1\)\n//;
973                     $e =~ s/^\tmtlr r0\n//;
974                     $e =~ s/^\tblr\n//;
975                     $e =~ s/^\tb restFP ;.*\n//;
976                 } elsif ($TargetPlatform =~ /^powerpc64-.*-linux/) {
977                     $e =~ s/^\tmr 3,0\n//;
978                     $e =~ s/^\taddi 1,1,\d+\n//;
979                     $e =~ s/^\tld 0,16\(1\)\n//;
980                     $e =~ s/^\tmtlr 0\n//;
981
982                     # callee-save registers
983                     $e =~ s/^\tld \d+,-?\d+\(1\)\n//g;
984                     $e =~ s/^\tlfd \d+,-?\d+\(1\)\n//g;
985
986                     # get rid of the debug junk along with the blr
987                     $e =~ s/^\tblr\n\t.long .*\n\t.byte .*\n//;
988
989                     # incase we missed it with the last one get the blr alone
990                     $e =~ s/^\tblr\n//;
991                 } else {
992                     print STDERR "$Pgm: unknown epilogue mangling? $TargetPlatform\n";
993                 }
994
995                 print STDERR "WARNING: Epilogue junk?: $e\n" if $e =~ /^\t\s*[^\.\s\n]/;
996
997                 # glue together what's left
998                 $c = $r . $e;
999                 $c =~ s/\n\t\n/\n/; # junk blank line
1000             }
1001         }
1002
1003         # On SPARCs, we don't do --- BEGIN/END ---, we just
1004         # toss the register-windowing save/restore/ret* instructions
1005         # directly unless they've been generated by function definitions in header
1006         # files on Solaris:
1007         if ( $TargetPlatform =~ /^sparc-/ ) {
1008             if ( ! ( $TargetPlatform =~ /solaris2$/ && $chkcat[$i] eq 'unknown' )) {
1009                 $c =~ s/^\t(save.*|restore.*|ret|retl)\n//g;
1010             }
1011             # throw away PROLOGUE comments
1012             $c =~ s/^\t!#PROLOGUE# 0\n\t!#PROLOGUE# 1\n//;
1013         }
1014
1015         # On Alphas, the prologue mangling is done a little later (below)
1016
1017         # toss all calls to __DISCARD__
1018         $c =~ s/^\t(call|jbsr|jal)\s+${T_US}__DISCARD__\n//go;
1019         $c =~ s/^\tjsr\s+\$26\s*,\s*${T_US}__DISCARD__\n//go if $TargetPlatform =~ /^alpha-/;
1020         $c =~ s/^\tbl\s+L___DISCARD__\$stub\n//go if $TargetPlatform =~ /^powerpc-apple-.*/;
1021         $c =~ s/^\tbl\s+__DISCARD__(\@plt)?\n//go if $TargetPlatform =~ /^powerpc-.*-linux/;
1022         $c =~ s/^\tbl\s+\.__DISCARD__\n\s+nop\n//go if $TargetPlatform =~ /^powerpc64-.*-linux/;
1023
1024         # IA64: mangle tailcalls into jumps here
1025         if ($TargetPlatform =~ /^ia64-/) {
1026             while ($c =~ s/^\tbr\.call\.sptk\.many b0 = (.*)\n(?:^\.L([0-9]*):\n)?(?:\t;;\n)?(?:\tmov r1 = r\d+\n)?(?:\t;;\n)?\t--- TAILCALL ---\n(?:\t;;\n\tbr \.L\d+\n)?/\tbr\.few $1\n/) {
1027                 # Eek, the gcc optimiser is getting smarter... if we see a jump to the --- TAILCALL ---
1028                 # marker then we reapply the substitution at the source sites
1029                 $c =~ s/^\tbr \.L$2\n/\t--- TAILCALL ---\n/g if ($2);
1030             }
1031         }
1032
1033         # MIPS: that may leave some gratuitous asm macros around
1034         # (no harm done; but we get rid of them to be tidier)
1035         $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/
1036             if $TargetPlatform =~ /^mips-/;
1037
1038         # toss stack adjustment after DoSparks
1039         $c =~ s/^(\tjbsr _DoSparks\n)\taddqw #8,sp/$1/g
1040                 if $TargetPlatform =~ /^m68k-/; # this looks old...
1041
1042         if ( $TargetPlatform =~ /^alpha-/ &&
1043            ! $magic_rdata_seen &&
1044            $c =~ /^\s*\.rdata\n\t\.quad 0\n\t\.align \d\n/ ) {
1045             $c =~ s/^\s*\.rdata\n\t\.quad 0\n\t\.align (\d)\n/\.rdata\n\t\.align $1\n/;
1046             $magic_rdata_seen = 1;
1047         }
1048
1049         # pick some end-things and move them to the next chunk
1050
1051         # pin a funny end-thing on (for easier matching):
1052         $c .= 'FUNNY#END#THING';
1053
1054         while ( $c =~ /${T_MOVE_DIRVS}FUNNY#END#THING/o ) {
1055
1056             $to_move = $1;
1057
1058             # on x86 we try not to copy any directives into a literal
1059             # chunk, rather we keep looking for the next real chunk.  This
1060             # is because we get things like
1061             #
1062             #    .globl blah_closure
1063             #    .LC32
1064             #           .string "..."
1065             #    blah_closure:
1066             #           ...
1067             #
1068             if ( $TargetPlatform =~ /^(i386|sparc|powerpc)/ && $to_move =~ /${T_COPY_DIRVS}/ ) {
1069                 $j = $i + 1;
1070                 while ( $j < $numchks  && $chk[$j] =~ /$T_CONST_LBL/) {
1071                         $j++;
1072                 }
1073                 if ( $j < $numchks ) {
1074                         $chk[$j] = $to_move . $chk[$j];
1075                 }
1076             }
1077
1078             elsif ( $i < ($numchks - 1)
1079               && ( $to_move =~ /${T_COPY_DIRVS}/
1080                 || ($TargetPlatform =~ /^hppa/ && $to_move =~ /align/ && $chkcat[$i+1] eq 'literal') )) {
1081                 $chk[$i + 1] = $to_move . $chk[$i + 1];
1082                 # otherwise they're tossed
1083             }
1084
1085             $c =~ s/${T_MOVE_DIRVS}FUNNY#END#THING/FUNNY#END#THING/o;
1086         }
1087
1088         if ( $TargetPlatform =~ /^alpha-/ && $c =~ /^\t\.ent\s+(\S+)/ ) {
1089             $ent = $1;
1090             # toss all prologue stuff, except for loading gp, and the ..ng address
1091             unless ($c =~ /\.ent.*\n\$.*\.\.ng:/) {
1092                 if (($p, $r) = split(/^\t\.prologue/, $c)) {
1093                     if (($keep, $junk) = split(/\.\.ng:/, $p)) {
1094                         $keep =~ s/^\t\.frame.*\n/\t.frame \$30,0,\$26,0\n/;
1095                         $keep =~ s/^\t\.(mask|fmask).*\n//g;
1096                         $c = $keep . "..ng:\n";
1097                     } else {
1098                         print STDERR "malformed code block ($ent)?\n"
1099                     }
1100                 }
1101                 $c .= "\t.prologue" . $r;
1102             }
1103         }
1104   
1105         $c =~ s/FUNNY#END#THING//;
1106
1107 #       print STDERR "\nCHK $i (AFTER) (",$chkcat[$i],"):\n", $c;
1108
1109         $chk[$i] = $c; # update w/ convenience copy
1110     }
1111
1112     # open CHUNKS, ">/tmp/chunks2" or die "Cannot open /tmp/chunks2: $!\n";
1113     # for (my $i = 0; $i < @chk; ++$i) { print CHUNKS "======= $i =======\n", $chk[$i] }
1114     # close CHUNKS;
1115
1116     if ( $TargetPlatform =~ /^alpha-/ ) {
1117         # print out the header stuff first
1118         $chk[0] =~ s/^(\t\.file.*)"(ghc\d+\.c)"/$1"$ifile_root.hc"/;
1119         print OUTASM $chk[0];
1120
1121     } elsif ( $TargetPlatform =~ /^hppa/ ) {
1122         print OUTASM $chk[0];
1123
1124     } elsif ( $TargetPlatform =~ /^mips-/ ) {
1125         $chk[0] = "\t\.file\t1 \"$ifile_root.hc\"\n" . $chk[0];
1126
1127         # get rid of horrible "<dollar>Revision: .*$" strings
1128         local(@lines0) = split(/\n/, $chk[0]);
1129         local($z) = 0;
1130         while ( $z <= $#lines0 ) {
1131             if ( $lines0[$z] =~ /^\t\.byte\t0x24,0x52,0x65,0x76,0x69,0x73,0x69,0x6f$/ ) {
1132                 undef($lines0[$z]);
1133                 $z++;
1134                 while ( $z <= $#lines0 ) {
1135                     undef($lines0[$z]);
1136                     last if $lines0[$z] =~ /[,\t]0x0$/;
1137                     $z++;
1138                 }
1139             }
1140             $z++;
1141         }
1142         $chk[0] = join("\n", @lines0);
1143         $chk[0] =~ s/\n\n+/\n/;
1144         print OUTASM $chk[0];
1145     }
1146
1147     # print out all the literal strings next
1148     for ($i = 0; $i < $numchks; $i++) {
1149         if ( $chkcat[$i] eq 'literal' ) {
1150
1151             # HACK: try to detect 16-byte constants and align them
1152             # on a 16-byte boundary.  x86_64 sometimes needs 128-bit
1153             # aligned constants.
1154             if ( $TargetPlatform =~ /^x86_64/ ) { 
1155                 $z = $chk[$i];
1156                 if ($z =~ /(\.long.*\n.*\.long.*\n.*\.long.*\n.*\.long|\.quad.*\n.*\.quad)/) {
1157                     print OUTASM $T_HDR_literal16;
1158                 } else {
1159                     print OUTASM $T_HDR_literal;
1160                 }
1161             } else {
1162                 print OUTASM $T_HDR_literal;
1163             }
1164
1165             print OUTASM $chk[$i];
1166             print OUTASM "; end literal\n" if $TargetPlatform =~ /^hppa/; # for the splitter
1167
1168             $chkcat[$i] = 'DONE ALREADY';
1169         }
1170     }
1171
1172     # on the HPPA, print out all the bss next
1173     if ( $TargetPlatform =~ /^hppa/ ) {
1174         for ($i = 1; $i < $numchks; $i++) {
1175             if ( $chkcat[$i] eq 'bss' ) {
1176                 print OUTASM "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$BSS\$\n\t.align 4\n";
1177                 print OUTASM $chk[$i];
1178
1179                 $chkcat[$i] = 'DONE ALREADY';
1180             }
1181         }
1182     }
1183
1184     for ($i = $FIRST_MANGLABLE; $i < $numchks; $i++) {
1185 #       print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n";
1186
1187         next if $chkcat[$i] eq 'DONE ALREADY';
1188
1189         if ( $chkcat[$i] eq 'misc' || $chkcat[$i] eq 'unknown' ) {
1190             if ($chk[$i] ne '') {
1191                 print OUTASM $T_HDR_misc;
1192                 &print_doctored($chk[$i], 0);
1193             }
1194
1195         } elsif ( $chkcat[$i] eq 'toss' ) {
1196             print STDERR "*** NB: TOSSING code for $chksymb[$i] !!! ***\n";
1197
1198         } elsif ( $chkcat[$i] eq 'data' ) {
1199             if ($chk[$i] ne '') {
1200                 print OUTASM $T_HDR_data;
1201                 print OUTASM $chk[$i];
1202             }
1203
1204         } elsif ( $chkcat[$i] eq 'splitmarker' ) {
1205             # we can just re-constitute this one...
1206             # NB: we emit _three_ underscores no matter what,
1207             # so ghc-split doesn't have to care.
1208             print OUTASM "___stg_split_marker",$chksymb[$i],"${T_POST_LBL}\n";
1209
1210         } elsif ( $chkcat[$i] eq 'closure'
1211                || $chkcat[$i] eq 'srt'
1212                || $chkcat[$i] eq 'infotbl'
1213                || $chkcat[$i] eq 'entry') { # do them in that order
1214             $symb = $chksymb[$i];
1215
1216             # CLOSURE
1217             if ( defined($closurechk{$symb}) ) {
1218                 print OUTASM $T_HDR_closure;
1219                 print OUTASM $chk[$closurechk{$symb}];
1220                 $chkcat[$closurechk{$symb}] = 'DONE ALREADY';
1221             }
1222
1223             # SRT
1224             if ( defined($srtchk{$symb}) ) {
1225                 print OUTASM $T_HDR_relrodata;
1226                 print OUTASM $chk[$srtchk{$symb}];
1227                 $chkcat[$srtchk{$symb}] = 'DONE ALREADY';
1228             }
1229
1230             # INFO TABLE
1231             if ( defined($infochk{$symb}) ) {
1232
1233                 print OUTASM $T_HDR_info;
1234                 print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1);
1235                 
1236                 # entry code will be put here!
1237
1238                 $chkcat[$infochk{$symb}] = 'DONE ALREADY';
1239             }
1240
1241             # ENTRY POINT
1242             if ( defined($entrychk{$symb}) ) {
1243
1244                 $c = $chk[$entrychk{$symb}];
1245
1246                 # If this is an entry point with an info table,
1247                 # eliminate the entry symbol and all directives involving it.
1248                 if (defined($infochk{$symb}) && $TargetPlatform !~ /^ia64-/) {
1249                         @o = ();
1250                         foreach $l (split(/\n/,$c)) {
1251                             next if $l =~ /^.*$symb_(entry|ret)${T_POST_LBL}/;
1252
1253                             # If we have .type/.size direrctives involving foo_entry,
1254                             # then make them refer to foo_info instead.  The information
1255                             # in these directives is used by the cachegrind annotator,
1256                             # so it is worthwhile keeping.
1257                             if ($l =~ /^\s*\.(type|size).*$symb_(entry|ret)/) {
1258                                 $l =~ s/$symb(_entry|_ret)/${symb}_info/g;
1259                                 push(@o,$l);
1260                                 next;
1261                             }
1262                             next if $l =~ /^\s*\..*$symb.*\n?/;
1263                             push(@o,$l);
1264                         }
1265                         $c = join("\n",@o) . "\n";
1266                 }
1267
1268                 print OUTASM $T_HDR_entry;
1269
1270                 &print_doctored($c, 1); # NB: the 1!!!
1271
1272                 $chkcat[$entrychk{$symb}] = 'DONE ALREADY';
1273             }
1274             
1275         } elsif ( $chkcat[$i] eq 'vector' ) {
1276             $symb = $chksymb[$i];
1277
1278             # VECTOR TABLE
1279             if ( defined($vectorchk{$symb}) ) {
1280                 print OUTASM $T_HDR_vector;
1281                 print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0);
1282
1283                 # direct return code will be put here!
1284                 $chkcat[$vectorchk{$symb}] = 'DONE ALREADY';
1285
1286             } elsif ( $TargetPlatform =~ /^alpha-/ ) {
1287                 # Alphas: the commented nop is for the splitter, to ensure
1288                 # that no module ends with a label as the very last
1289                 # thing.  (The linker will adjust the label to point
1290                 # to the first code word of the next module linked in,
1291                 # even if alignment constraints cause the label to move!)
1292
1293                 print OUTASM "\t# nop\n";
1294             }
1295             
1296         } elsif ( $chkcat[$i] eq 'rodata' ) {
1297                 print OUTASM $T_HDR_rodata;
1298                 print OUTASM $chk[$i];
1299                 $chkcat[$i] = 'DONE ALREADY';
1300         } elsif ( $chkcat[$i] eq 'relrodata' ) {
1301                 print OUTASM $T_HDR_relrodata;
1302                 print OUTASM $chk[$i];
1303                 $chkcat[$i] = 'DONE ALREADY';
1304         } elsif ( $chkcat[$i] eq 'toc' ) {
1305             # silly optimisation to print tocs, since they come in groups...
1306             print OUTASM $T_HDR_toc;
1307             local($j)   = $i;
1308             while ($chkcat[$j] eq 'toc')
1309               { if (   $chk[$j] !~ /\.tc UpdatePAP\[TC\]/ # not needed: always turned into a jump.
1310                    ) 
1311                 {
1312                   print OUTASM $chk[$j];
1313                 }
1314                 $chkcat[$j] = 'DONE ALREADY';
1315                 $j++;
1316             }
1317             
1318         } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ && $chkcat[$i] eq 'dyld' ) {
1319             # powerpc-apple: dynamic linker stubs
1320             if($chk[$i] !~ /\.indirect_symbol ___DISCARD__/)
1321             {   # print them out unchanged, but remove the stubs for __DISCARD__
1322                 print OUTASM $chk[$i];
1323             }
1324         } else {
1325             &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm: $TargetPlatform)\n$chkcat[$i]\n$chk[$i]\n");
1326         }
1327     }
1328
1329     print OUTASM $EXTERN_DECLS if $TargetPlatform =~ /^mips-/;
1330
1331     # finished
1332     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
1333     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
1334 }
1335 \end{code}
1336
1337 \begin{code}
1338 sub hppa_mash_prologue { # OK, epilogue, too
1339     local($_) = @_;
1340
1341     # toss all prologue stuff
1342     s/^\s+\.ENTRY[^\0]*--- BEGIN ---/\t.ENTRY/;
1343
1344     # Lie about our .CALLINFO
1345     s/^\s+\.CALLINFO.*$/\t.CALLINFO NO_CALLS,NO_UNWIND/;
1346
1347     # Get rid of P'
1348
1349     s/LP'/L'/g;
1350     s/RP'/R'/g;
1351
1352     # toss all epilogue stuff
1353     s/^\s+--- END ---[^\0]*\.EXIT/\t.EXIT/;
1354
1355     # Sorry; we moved the _info stuff to the code segment.
1356     s/_info,DATA/_info,CODE/g;
1357
1358     return($_);
1359 }
1360 \end{code}
1361
1362 \begin{code}
1363 sub print_doctored {
1364     local($_, $need_fallthru_patch) = @_;
1365
1366     if ( $TargetPlatform !~ /^i386-/ 
1367       || ! /^\t[a-z]/  # no instructions in here, apparently
1368       || /^${T_US}__stginit_[A-Za-z0-9_]+${T_POST_LBL}/) {
1369         print OUTASM $_;
1370         return;
1371     }
1372     # OK, must do some x86 **HACKING**
1373
1374     local($entry_patch) = '';
1375     local($exit_patch)  = '';
1376
1377     # gotta watch out for weird instructions that
1378     # invisibly smash various regs:
1379     #   rep*    %ecx used for counting
1380     #   scas*   %edi used for destination index
1381     #   cmps*   %e[sd]i used for indices
1382     #   loop*   %ecx used for counting
1383     #
1384     # SIGH.
1385
1386     # We cater for:
1387     #  * use of STG reg [ nn(%ebx) ] where no machine reg avail
1388     #
1389     #  * GCC used an "STG reg" for its own purposes
1390     #
1391     #  * some secret uses of machine reg, requiring STG reg
1392     #    to be saved/restored
1393
1394     # The most dangerous "GCC uses" of an "STG reg" are when
1395     # the reg holds the target of a jmp -- it's tricky to
1396     # insert the patch-up code before we get to the target!
1397     # So here we change the jmps:
1398
1399     # --------------------------------------------------------
1400     # it can happen that we have jumps of the form...
1401     #   jmp *<something involving %esp>
1402     # or
1403     #   jmp <something involving another naughty register...>
1404     #
1405     # a reasonably-common case is:
1406     #
1407     #   movl $_blah,<bad-reg>
1408     #   jmp  *<bad-reg>
1409     #
1410     s/^\tmovl\s+\$${T_US}(.*),\s*(\%e[acd]x)\n\tjmp\s+\*\2/\tjmp $T_US$1/g;
1411
1412     # Catch things like
1413     #
1414     #    movl -4(%ebx), %eax
1415     #    jmp  *%eax
1416     # 
1417     # and optimise:
1418     #
1419     s/^\tmovl\s+(-?\d*\(\%e(bx|si)\)),\s*(\%e[acd]x)\n\tjmp\s+\*\3/\tjmp\t\*$1/g;
1420
1421     if ($StolenX86Regs <= 2 ) { # YURGH! spurious uses of esi?
1422         s/^\tmovl\s+(.*),\s*\%esi\n\tjmp\s+\*%esi\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1423         s/^\tjmp\s+\*(.*\(.*\%esi.*\))\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1424         s/^\tjmp\s+\*\%esi\n/\tmovl \%esi,\%eax\n\tjmp \*\%eax\n/g;
1425         die "$Pgm: (mangler) still have jump involving \%esi!\n$_"
1426             if /(jmp|call)\s+.*\%esi/;
1427     }
1428     if ($StolenX86Regs <= 3 ) { # spurious uses of edi?
1429         s/^\tmovl\s+(.*),\s*\%edi\n\tjmp\s+\*%edi\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1430         s/^\tjmp\s+\*(.*\(.*\%edi.*\))\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1431         s/^\tjmp\s+\*\%edi\n/\tmovl \%edi,\%eax\n\tjmp \*\%eax\n/g;
1432         die "$Pgm: (mangler) still have jump involving \%edi!\n$_"
1433             if /(jmp|call)\s+.*\%edi/;
1434     }
1435
1436     # OK, now we can decide what our patch-up code is going to
1437     # be:
1438
1439     # Offsets into register table - you'd better update these magic
1440     # numbers should you change its contents!
1441     # local($OFFSET_R1)=0;  No offset for R1 in new RTS.
1442     local($OFFSET_Hp)=88;
1443
1444         # Note funky ".=" stuff; we're *adding* to these _patch guys
1445     if ( $StolenX86Regs <= 2
1446          && ( /[^0-9]\(\%ebx\)/ || /\%esi/ || /^\tcmps/ ) ) { # R1 (esi)
1447         $entry_patch .= "\tmovl \%esi,(\%ebx)\n";
1448         $exit_patch  .= "\tmovl (\%ebx),\%esi\n";
1449
1450         # nothing for call_{entry,exit} because %esi is callee-save
1451     }
1452     if ( $StolenX86Regs <= 3
1453          && ( /${OFFSET_Hp}\(\%ebx\)/ || /\%edi/ || /^\t(scas|cmps)/ ) ) { # Hp (edi)
1454         $entry_patch .= "\tmovl \%edi,${OFFSET_Hp}(\%ebx)\n";
1455         $exit_patch  .= "\tmovl ${OFFSET_Hp}(\%ebx),\%edi\n";
1456
1457         # nothing for call_{entry,exit} because %edi is callee-save
1458     }
1459
1460     # --------------------------------------------------------
1461     # next, here we go with non-%esp patching!
1462     #
1463     s/^(\t[a-z])/$entry_patch$1/; # before first instruction
1464
1465 # Before calling GC we must set up the exit condition before the call
1466 # and entry condition when we come back
1467
1468     # fix _all_ non-local jumps:
1469
1470     s/^\tjmp\s+\*${T_X86_PRE_LLBL_PAT}/\tJMP___SL/go;
1471     s/^\tjmp\s+${T_X86_PRE_LLBL_PAT}/\tJMP___L/go;
1472
1473     s/^(\tjmp\s+.*\n)/$exit_patch$1/g; # here's the fix...
1474
1475     s/^\tJMP___SL/\tjmp \*${T_X86_PRE_LLBL}/go;
1476     s/^\tJMP___L/\tjmp ${T_X86_PRE_LLBL}/go;
1477
1478     if ($StolenX86Regs == 2 ) {
1479         die "ARGH! Jump uses \%esi or \%edi with -monly-2-regs:\n$_" 
1480             if /^\t(jmp|call)\s+.*\%e(si|di)/;
1481     } elsif ($StolenX86Regs == 3 ) {
1482         die "ARGH! Jump uses \%edi with -monly-3-regs:\n$_" 
1483             if /^\t(jmp|call)\s+.*\%edi/;
1484     }
1485
1486     # --------------------------------------------------------
1487     # that's it -- print it
1488     #
1489     #die "Funny jumps?\n$_" if /${T_X86_BADJMP}/o; # paranoia
1490
1491     print OUTASM $_;
1492
1493     if ( $need_fallthru_patch ) { # exit patch for end of slow entry code
1494         print OUTASM $exit_patch;
1495         # ToDo: make it not print if there is a "jmp" at the end
1496     }
1497 }
1498 \end{code}
1499
1500 \begin{code}
1501 sub init_FUNNY_THINGS {
1502     %KNOWN_FUNNY_THING = (
1503         # example
1504         # "${T_US}stg_.*{T_POST_LBL}", 1,  
1505     );
1506 }
1507 \end{code}
1508
1509 The following table reversal is used for both info tables and return
1510 vectors.  In both cases, we remove the first entry from the table,
1511 reverse the table, put the label at the end, and paste some code
1512 (that which is normally referred to by the first entry in the table)
1513 right after the table itself.  (The code pasting is done elsewhere.)
1514
1515 \begin{code}
1516 sub rev_tbl {
1517     local($symb, $tbl, $discard1) = @_;
1518
1519     return ($tbl) if ($TargetPlatform =~ /^ia64-/);
1520
1521     local($before) = '';
1522     local($label) = '';
1523     local(@imports) = (); # hppa only
1524     local(@words) = ();
1525     local($after) = '';
1526     local(@lines) = split(/\n/, $tbl);
1527     local($i, $j);
1528
1529     # Deal with the header...
1530     for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t?${T_DOT_WORD}\s+/o; $i++) {
1531         $label .= $lines[$i] . "\n",
1532             next if $lines[$i] =~ /^[A-Za-z0-9_]+_info${T_POST_LBL}$/o
1533                  || $lines[$i] =~ /${T_DOT_GLOBAL}/o
1534                  || $lines[$i] =~ /^${T_US}\S+_vtbl${T_POST_LBL}$/o;
1535
1536         $before .= $lines[$i] . "\n"; # otherwise...
1537     }
1538
1539     $infoname = $label;
1540     $infoname =~ s/(.|\n)*^([A-Za-z0-9_]+_info)${T_POST_LBL}$(.|\n)*/\2/;
1541     
1542     # Grab the table data...
1543     if ( $TargetPlatform !~ /^hppa/ ) {
1544         for ( ; $i <= $#lines && $lines[$i] =~ /^\t?${T_DOT_WORD}\s+/o; $i++) {
1545             $line = $lines[$i];
1546             # Convert addresses of SRTs, slow entrypoints and large bitmaps
1547             # to offsets (relative to the info label),
1548             # in order to support position independent code.
1549             $line =~ s/$infoname/0/
1550             || $line =~ s/([A-Za-z0-9_]+_srtd)$/\1 - $infoname/
1551             || $line =~ s/([A-Za-z0-9_]+_srt(\+\d+)?)$/\1 - $infoname/
1552             || $line =~ s/([A-Za-z0-9_]+_slow)$/\1 - $infoname/
1553             || $line =~ s/([A-Za-z0-9_]+_btm)$/\1 - $infoname/
1554             || $line =~ s/([A-Za-z0-9_]+_alt)$/\1 - $infoname/
1555             || $line =~ s/([A-Za-z0-9_]+_dflt)$/\1 - $infoname/
1556             || $line =~ s/([A-Za-z0-9_]+_ret)$/\1 - $infoname/;
1557             push(@words, $line);
1558         }
1559     } else { # hppa weirdness
1560         for ( ; $i <= $#lines && $lines[$i] =~ /^\s+(${T_DOT_WORD}|\.IMPORT)/; $i++) {
1561             # FIXME: the RTS now expects offsets instead of addresses
1562             # for all labels in info tables.
1563             if ($lines[$i] =~ /^\s+\.IMPORT/) {
1564                 push(@imports, $lines[$i]);
1565             } else {
1566                 # We don't use HP's ``function pointers''
1567                 # We just use labels in code space, like normal people
1568                 $lines[$i] =~ s/P%//;
1569                 push(@words, $lines[$i]);
1570             }
1571         }
1572     }
1573
1574     # Now throw away any initial zero word from the table.  This is a hack
1575     # that lets us reduce the size of info tables when the SRT field is not
1576     # needed: see comments StgFunInfoTable in InfoTables.h.
1577     #
1578     # The .zero business is for Linux/ELF.
1579     # The .skip business is for Sparc/Solaris/ELF.
1580     # The .blockz business is for HPPA.
1581 #    if ($discard1) {
1582 #       if ($words[0] =~ /^\t?(${T_DOT_WORD}\s+0|\.zero\s+4|\.skip\s+4|\.blockz\s+4)/) {
1583 #               shift(@words);
1584 #       }
1585 #    }
1586
1587     for (; $i <= $#lines; $i++) {
1588         $after .= $lines[$i] . "\n";
1589     }
1590
1591     # Alphas: If we have anonymous text (not part of a procedure), the
1592     # linker may complain about missing exception information.  Bleh.
1593     # To suppress this, we place a .ent/.end pair around the code.
1594     # At the same time, we have to be careful and not enclose any leading
1595     # .file/.loc directives.
1596     if ( $TargetPlatform =~ /^alpha-/ && $label =~ /^([A-Za-z0-9_]+):$/) {
1597         local ($ident) = $1;
1598         $before =~ s/^((\s*\.(file|loc)\s+[^\n]*\n)*)/$1\t.ent $ident\n/;
1599         $after .= "\t.end $ident\n";
1600     }
1601
1602     # Alphas: The heroic Simon Marlow found a bug in the Digital UNIX
1603     # assembler (!) wherein .quad constants inside .text sections are
1604     # first narrowed to 32 bits then sign-extended back to 64 bits.
1605     # This obviously screws up our 64-bit bitmaps, so we work around
1606     # the bug by replacing .quad with .align 3 + .long + .long [ccshan]
1607     if ( $TargetPlatform =~ /^alpha-/ ) {
1608         foreach (@words) {
1609             if (/^\s*\.quad\s+([-+0-9].*\S)\s*$/ && length $1 >= 10) {
1610                 local ($number) = $1;
1611                 if ($number =~ /^([-+])?(0x?)?([0-9]+)$/) {
1612                     local ($sign, $base, $digits) = ($1, $2, $3);
1613                     $base = (10, 8, 16)[length $base];
1614                     local ($hi, $lo) = (0, 0);
1615                     foreach $i (split(//, $digits)) {
1616                         $j = $lo * $base + $i;
1617                         $lo = $j % 4294967296;
1618                         $hi = $hi * $base + ($j - $lo) / 4294967296;
1619                     }
1620                     ($hi, $lo) = (4294967295 - $hi, 4294967296 - $lo)
1621                         if $sign eq "-";
1622                     $_ = "\t.align 3\n\t.long $lo\n\t.long $hi\n";
1623                     # printf STDERR "TURNING %s into 0x %08x %08x\n", $number, $hi, $lo;
1624                 } else {
1625                     print STDERR "Cannot handle \".quad $number\" in info table\n";
1626                     exit 1;
1627                 }
1628             }
1629         }
1630     }
1631
1632     $tbl = $before
1633          . (($TargetPlatform !~ /^hppa/) ? '' : join("\n", @imports) . "\n")
1634          . join("\n", @words) . "\n"
1635          . $label . $after;
1636
1637 #   print STDERR "before=$before\n";
1638 #   print STDERR "label=$label\n";
1639 #   print STDERR "words=",(reverse @words),"\n";
1640 #   print STDERR "after=$after\n";
1641
1642     $tbl;
1643 }
1644 \end{code}
1645
1646 The HP is a major nuisance.  The threaded code mangler moved info
1647 tables from data space to code space, but unthreaded code in the RTS
1648 still has references to info tables in data space.  Since the HP
1649 linker is very precise about where symbols live, we need to patch the
1650 references in the unthreaded RTS as well.
1651
1652 \begin{code}
1653 sub mini_mangle_asm_hppa {
1654     local($in_asmf, $out_asmf) = @_;
1655
1656     open(INASM, "< $in_asmf")
1657         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
1658     open(OUTASM,"> $out_asmf")
1659         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
1660
1661     while (<INASM>) {
1662         s/_info,DATA/_info,CODE/;   # Move _info references to code space
1663         s/P%_PR/_PR/;
1664         print OUTASM;
1665     }
1666
1667     # finished:
1668     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
1669     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
1670 }
1671
1672 \end{code}
1673
1674 \begin{code}
1675 sub tidy_up_and_die {
1676     local($return_val, $msg) = @_;
1677     print STDERR $msg;
1678     exit (($return_val == 0) ? 0 : 1);
1679 }
1680 \end{code}