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