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