125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#!/usr/bin/perl
225b3c049e70834cf33790a28643ab058b507b35cBen Cheng# Copyright (C) 2002-2013 Xiph.org Foundation
325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng# Redistribution and use in source and binary forms, with or without
525b3c049e70834cf33790a28643ab058b507b35cBen Cheng# modification, are permitted provided that the following conditions
625b3c049e70834cf33790a28643ab058b507b35cBen Cheng# are met:
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#
825b3c049e70834cf33790a28643ab058b507b35cBen Cheng# - Redistributions of source code must retain the above copyright
925b3c049e70834cf33790a28643ab058b507b35cBen Cheng# notice, this list of conditions and the following disclaimer.
1025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#
1125b3c049e70834cf33790a28643ab058b507b35cBen Cheng# - Redistributions in binary form must reproduce the above copyright
1225b3c049e70834cf33790a28643ab058b507b35cBen Cheng# notice, this list of conditions and the following disclaimer in the
1325b3c049e70834cf33790a28643ab058b507b35cBen Cheng# documentation and/or other materials provided with the distribution.
1425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#
1525b3c049e70834cf33790a28643ab058b507b35cBen Cheng# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1625b3c049e70834cf33790a28643ab058b507b35cBen Cheng# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1725b3c049e70834cf33790a28643ab058b507b35cBen Cheng# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1825b3c049e70834cf33790a28643ab058b507b35cBen Cheng# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
1925b3c049e70834cf33790a28643ab058b507b35cBen Cheng# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2025b3c049e70834cf33790a28643ab058b507b35cBen Cheng# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2525b3c049e70834cf33790a28643ab058b507b35cBen Cheng# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2725b3c049e70834cf33790a28643ab058b507b35cBen Chengmy $bigend;  # little/big endian
2825b3c049e70834cf33790a28643ab058b507b35cBen Chengmy $nxstack;
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng$nxstack = 0;
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3225b3c049e70834cf33790a28643ab058b507b35cBen Chengeval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if $running_under_some_shell;
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3525b3c049e70834cf33790a28643ab058b507b35cBen Chengwhile ($ARGV[0] =~ /^-/) {
3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    $_ = shift;
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  last if /^--/;
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (/^-n/) {
3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    $nflag++;
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    next;
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    die "I don't recognize this switch: $_\\n";
4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng$printit++ unless $nflag;
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng$\ = "\n";      # automatically add newline on print
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng$n=0;
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng$thumb = 0;     # ARM mode by default, not Thumb.
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng@proc_stack = ();
51
52printf ("    .syntax unified\n");
53
54LINE:
55while (<>) {
56
57    # For ADRLs we need to add a new line after the substituted one.
58    $addPadding = 0;
59
60    # First, we do not dare to touch *anything* inside double quotes, do we?
61    # Second, if you want a dollar character in the string,
62    # insert two of them -- that's how ARM C and assembler treat strings.
63    s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1:   .ascii \"/   && do { s/\$\$/\$/g; next };
64    s/\bDCB\b[ \t]*\"/.ascii \"/                          && do { s/\$\$/\$/g; next };
65    s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/                    && do { s/\$\$/\$/g; next };
66    # If there's nothing on a line but a comment, don't try to apply any further
67    #  substitutions (this is a cheap hack to avoid mucking up the license header)
68    s/^([ \t]*);/$1@/                                     && do { s/\$\$/\$/g; next };
69    # If substituted -- leave immediately !
70
71    s/@/,:/;
72    s/;/@/;
73    while ( /@.*'/ ) {
74      s/(@.*)'/$1/g;
75    }
76    s/\{FALSE\}/0/g;
77    s/\{TRUE\}/1/g;
78    s/\{(\w\w\w\w+)\}/$1/g;
79    s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/;
80    s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/;
81    s/\bIMPORT\b/.extern/;
82    s/\bEXPORT\b/.global/;
83    s/^(\s+)\[/$1IF/;
84    s/^(\s+)\|/$1ELSE/;
85    s/^(\s+)\]/$1ENDIF/;
86    s/IF *:DEF:/ .ifdef/;
87    s/IF *:LNOT: *:DEF:/ .ifndef/;
88    s/ELSE/ .else/;
89    s/ENDIF/ .endif/;
90
91    if( /\bIF\b/ ) {
92      s/\bIF\b/ .if/;
93      s/=/==/;
94    }
95    if ( $n == 2) {
96        s/\$/\\/g;
97    }
98    if ($n == 1) {
99        s/\$//g;
100        s/label//g;
101    $n = 2;
102      }
103    if ( /MACRO/ ) {
104      s/MACRO *\n/.macro/;
105      $n=1;
106    }
107    if ( /\bMEND\b/ ) {
108      s/\bMEND\b/.endm/;
109      $n=0;
110    }
111
112    # ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there.
113    #
114    if ( /\bAREA\b/ ) {
115        my $align;
116        $align = "2";
117        if ( /ALIGN=(\d+)/ ) {
118            $align = $1;
119        }
120        if ( /CODE/ ) {
121            $nxstack = 1;
122        }
123        s/^(.+)CODE(.+)READONLY(.*)/    .text/;
124        s/^(.+)DATA(.+)READONLY(.*)/    .section .rdata/;
125        s/^(.+)\|\|\.data\|\|(.+)/    .data/;
126        s/^(.+)\|\|\.bss\|\|(.+)/    .bss/;
127        s/$/;   .p2align $align/;
128        # Enable NEON instructions but don't produce a binary that requires
129        # ARMv7. RVCT does not have equivalent directives, so we just do this
130        # for all CODE areas.
131        if ( /.text/ ) {
132            # Separating .arch, .fpu, etc., by semicolons does not work (gas
133            # thinks the semicolon is part of the arch name, even when there's
134            # whitespace separating them). Sadly this means our line numbers
135            # won't match the original source file (we could use the .line
136            # directive, which is documented to be obsolete, but then gdb will
137            # show the wrong line in the translated source file).
138            s/$/;   .arch armv7-a\n   .fpu neon\n   .object_arch armv4t/;
139        }
140    }
141
142    s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/;       # ||.constdata$3||
143    s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/;               # ||.bss$2||
144    s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/;             # ||.data$2||
145    s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/;
146    s/^(\s+)\%(\s)/    .space $1/;
147
148    s/\|(.+)\.(\d+)\|/\.$1_$2/;                     # |L80.123| -> .L80_123
149    s/\bCODE32\b/.code 32/ && do {$thumb = 0};
150    s/\bCODE16\b/.code 16/ && do {$thumb = 1};
151    if (/\bPROC\b/)
152    {
153        my $prefix;
154        my $proc;
155        /^([A-Za-z_\.]\w+)\b/;
156        $proc = $1;
157        $prefix = "";
158        if ($proc)
159        {
160            $prefix = $prefix.sprintf("\t.type\t%s, %%function; ",$proc);
161            push(@proc_stack, $proc);
162            s/^[A-Za-z_\.]\w+/$&:/;
163        }
164        $prefix = $prefix."\t.thumb_func; " if ($thumb);
165        s/\bPROC\b/@ $&/;
166        $_ = $prefix.$_;
167    }
168    s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/;
169    s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/;
170    if (/\bENDP\b/)
171    {
172        my $proc;
173        s/\bENDP\b/@ $&/;
174        $proc = pop(@proc_stack);
175        $_ = "\t.size $proc, .-$proc".$_ if ($proc);
176    }
177    s/\bSUBT\b/@ $&/;
178    s/\bDATA\b/@ $&/;   # DATA directive is deprecated -- Asm guide, p.7-25
179    s/\bKEEP\b/@ $&/;
180    s/\bEXPORTAS\b/@ $&/;
181    s/\|\|(.)+\bEQU\b/@ $&/;
182    s/\|\|([\w\$]+)\|\|/$1/;
183    s/\bENTRY\b/@ $&/;
184    s/\bASSERT\b/@ $&/;
185    s/\bGBLL\b/@ $&/;
186    s/\bGBLA\b/@ $&/;
187    s/^\W+OPT\b/@ $&/;
188    s/:OR:/|/g;
189    s/:SHL:/<</g;
190    s/:SHR:/>>/g;
191    s/:AND:/&/g;
192    s/:LAND:/&&/g;
193    s/CPSR/cpsr/;
194    s/SPSR/spsr/;
195    s/ALIGN$/.balign 4/;
196    s/ALIGN\s+([0-9x]+)$/.balign $1/;
197    s/psr_cxsf/psr_all/;
198    s/LTORG/.ltorg/;
199    s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/;
200    s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/;
201    s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/;
202    s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/;
203
204    #  {PC} + 0xdeadfeed  -->  . + 0xdeadfeed
205    s/\{PC\} \+/ \. +/;
206
207    # Single hex constant on the line !
208    #
209    # >>> NOTE <<<
210    #   Double-precision floats in gcc are always mixed-endian, which means
211    #   bytes in two words are little-endian, but words are big-endian.
212    #   So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address
213    #   and 0xfeed0000 at high address.
214    #
215    s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/;
216    # Only decimal constants on the line, no hex !
217    s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/;
218
219    # Single hex constant on the line !
220#    s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/;
221    # Only decimal constants on the line, no hex !
222#    s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/;
223    s/\bDCFS[ \t]+0x/.word 0x/;
224    s/\bDCFS\b/.float/;
225
226    s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/;
227    s/\bDCD\b/.word/;
228    s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/;
229    s/\bDCW\b/.short/;
230    s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/;
231    s/\bDCB\b/.byte/;
232    s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/;
233    s/^[A-Za-z_\.]\w+/$&:/;
234    s/^(\d+)/$1:/;
235    s/\%(\d+)/$1b_or_f/;
236    s/\%[Bb](\d+)/$1b/;
237    s/\%[Ff](\d+)/$1f/;
238    s/\%[Ff][Tt](\d+)/$1f/;
239    s/&([\dA-Fa-f]+)/0x$1/;
240    if ( /\b2_[01]+\b/ ) {
241      s/\b2_([01]+)\b/conv$1&&&&/g;
242      while ( /[01][01][01][01]&&&&/ ) {
243        s/0000&&&&/&&&&0/g;
244        s/0001&&&&/&&&&1/g;
245        s/0010&&&&/&&&&2/g;
246        s/0011&&&&/&&&&3/g;
247        s/0100&&&&/&&&&4/g;
248        s/0101&&&&/&&&&5/g;
249        s/0110&&&&/&&&&6/g;
250        s/0111&&&&/&&&&7/g;
251        s/1000&&&&/&&&&8/g;
252        s/1001&&&&/&&&&9/g;
253        s/1010&&&&/&&&&A/g;
254        s/1011&&&&/&&&&B/g;
255        s/1100&&&&/&&&&C/g;
256        s/1101&&&&/&&&&D/g;
257        s/1110&&&&/&&&&E/g;
258        s/1111&&&&/&&&&F/g;
259      }
260      s/000&&&&/&&&&0/g;
261      s/001&&&&/&&&&1/g;
262      s/010&&&&/&&&&2/g;
263      s/011&&&&/&&&&3/g;
264      s/100&&&&/&&&&4/g;
265      s/101&&&&/&&&&5/g;
266      s/110&&&&/&&&&6/g;
267      s/111&&&&/&&&&7/g;
268      s/00&&&&/&&&&0/g;
269      s/01&&&&/&&&&1/g;
270      s/10&&&&/&&&&2/g;
271      s/11&&&&/&&&&3/g;
272      s/0&&&&/&&&&0/g;
273      s/1&&&&/&&&&1/g;
274      s/conv&&&&/0x/g;
275    }
276
277    if ( /commandline/)
278    {
279        if( /-bigend/)
280        {
281            $bigend=1;
282        }
283    }
284
285    if ( /\bDCDU\b/ )
286    {
287        my $cmd=$_;
288        my $value;
289        my $prefix;
290        my $w1;
291        my $w2;
292        my $w3;
293        my $w4;
294
295        s/\s+DCDU\b/@ $&/;
296
297        $cmd =~ /\bDCDU\b\s+0x(\d+)/;
298        $value = $1;
299        $value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
300        $w1 = $1;
301        $w2 = $2;
302        $w3 = $3;
303        $w4 = $4;
304
305        if( $bigend ne "")
306        {
307            # big endian
308            $prefix = "\t.byte\t0x".$w1.";".
309                      "\t.byte\t0x".$w2.";".
310                      "\t.byte\t0x".$w3.";".
311                      "\t.byte\t0x".$w4."; ";
312        }
313        else
314        {
315            # little endian
316            $prefix = "\t.byte\t0x".$w4.";".
317                      "\t.byte\t0x".$w3.";".
318                      "\t.byte\t0x".$w2.";".
319                      "\t.byte\t0x".$w1."; ";
320        }
321        $_=$prefix.$_;
322    }
323
324    if ( /\badrl\b/i )
325    {
326        s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i;
327        $addPadding = 1;
328    }
329    s/\bEND\b/@ END/;
330} continue {
331    printf ("%s", $_) if $printit;
332    if ($addPadding != 0)
333    {
334        printf ("   mov r0,r0\n");
335        $addPadding = 0;
336    }
337}
338#If we had a code section, mark that this object doesn't need an executable
339# stack.
340if ($nxstack) {
341    printf ("    .section\t.note.GNU-stack,\"\",\%\%progbits\n");
342}
343