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