1#!/usr/bin/env perl
2##
3##  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
4##
5##  Use of this source code is governed by a BSD-style license
6##  that can be found in the LICENSE file in the root of the source
7##  tree. An additional intellectual property rights grant can be found
8##  in the file PATENTS.  All contributing project authors may
9##  be found in the AUTHORS file in the root of the source tree.
10##
11
12
13# ads2gas.pl
14# Author: Eric Fung (efung (at) acm.org)
15#
16# Convert ARM Developer Suite 1.0.1 syntax assembly source to GNU as format
17#
18# Usage: cat inputfile | perl ads2gas.pl > outputfile
19#
20
21use FindBin;
22use lib $FindBin::Bin;
23use thumb;
24
25my $thumb = 0;
26my $elf = 1;
27
28foreach my $arg (@ARGV) {
29    $thumb = 1 if ($arg eq "-thumb");
30    $elf = 0 if ($arg eq "-noelf");
31}
32
33print "@ This file was created from a .asm file\n";
34print "@  using the ads2gas.pl script.\n";
35print "\t.syntax unified\n";
36if ($thumb) {
37    print "\t.thumb\n";
38}
39
40# Stack of procedure names.
41@proc_stack = ();
42
43while (<STDIN>)
44{
45    undef $comment;
46    undef $line;
47    $comment_char = ";";
48    $comment_sub = "@";
49
50    # Handle comments.
51    if (/$comment_char/)
52    {
53      $comment = "";
54      ($line, $comment) = /(.*?)$comment_char(.*)/;
55      $_ = $line;
56    }
57
58    # Load and store alignment
59    s/@/,:/g;
60
61    # Hexadecimal constants prefaced by 0x
62    s/#&/#0x/g;
63
64    # Convert :OR: to |
65    s/:OR:/ | /g;
66
67    # Convert :AND: to &
68    s/:AND:/ & /g;
69
70    # Convert :NOT: to ~
71    s/:NOT:/ ~ /g;
72
73    # Convert :SHL: to <<
74    s/:SHL:/ << /g;
75
76    # Convert :SHR: to >>
77    s/:SHR:/ >> /g;
78
79    # Convert ELSE to .else
80    s/\bELSE\b/.else/g;
81
82    # Convert ENDIF to .endif
83    s/\bENDIF\b/.endif/g;
84
85    # Convert ELSEIF to .elseif
86    s/\bELSEIF\b/.elseif/g;
87
88    # Convert LTORG to .ltorg
89    s/\bLTORG\b/.ltorg/g;
90
91    # Convert endfunc to nothing.
92    s/\bendfunc\b//ig;
93
94    # Convert FUNCTION to nothing.
95    s/\bFUNCTION\b//g;
96    s/\bfunction\b//g;
97
98    s/\bENTRY\b//g;
99    s/\bMSARMASM\b/0/g;
100    s/^\s+end\s+$//g;
101
102    # Convert IF :DEF:to .if
103    # gcc doesn't have the ability to do a conditional
104    # if defined variable that is set by IF :DEF: on
105    # armasm, so convert it to a normal .if and then
106    # make sure to define a value elesewhere
107    if (s/\bIF :DEF:\b/.if /g)
108    {
109        s/=/==/g;
110    }
111
112    # Convert IF to .if
113    if (s/\bIF\b/.if/g)
114    {
115        s/=+/==/g;
116    }
117
118    # Convert INCLUDE to .INCLUDE "file"
119    s/INCLUDE(\s*)(.*)$/.include $1\"$2\"/;
120
121    # Code directive (ARM vs Thumb)
122    s/CODE([0-9][0-9])/.code $1/;
123
124    # No AREA required
125    # But ALIGNs in AREA must be obeyed
126    s/^\s*AREA.*ALIGN=([0-9])$/.text\n.p2align $1/;
127    # If no ALIGN, strip the AREA and align to 4 bytes
128    s/^\s*AREA.*$/.text\n.p2align 2/;
129
130    # DCD to .word
131    # This one is for incoming symbols
132    s/DCD\s+\|(\w*)\|/.long $1/;
133
134    # DCW to .short
135    s/DCW\s+\|(\w*)\|/.short $1/;
136    s/DCW(.*)/.short $1/;
137
138    # Constants defined in scope
139    s/DCD(.*)/.long $1/;
140    s/DCB(.*)/.byte $1/;
141
142    # Make function visible to linker, and make additional symbol with
143    # prepended underscore
144    if ($elf) {
145        s/EXPORT\s+\|([\$\w]*)\|/.global $1 \n\t.type $1, function/;
146    } else {
147        s/EXPORT\s+\|([\$\w]*)\|/.global $1/;
148    }
149    s/IMPORT\s+\|([\$\w]*)\|/.global $1/;
150
151    s/EXPORT\s+([\$\w]*)/.global $1/;
152    s/export\s+([\$\w]*)/.global $1/;
153
154    # No vertical bars required; make additional symbol with prepended
155    # underscore
156    s/^\|(\$?\w+)\|/_$1\n\t$1:/g;
157
158    # Labels need trailing colon
159#   s/^(\w+)/$1:/ if !/EQU/;
160    # put the colon at the end of the line in the macro
161    s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/;
162
163    # ALIGN directive
164    s/\bALIGN\b/.balign/g;
165
166    if ($thumb) {
167        # ARM code - we force everything to thumb with the declaration in the header
168        s/\sARM//g;
169    } else {
170        # ARM code
171        s/\sARM/.arm/g;
172    }
173
174    # push/pop
175    s/(push\s+)(r\d+)/stmdb sp\!, \{$2\}/g;
176    s/(pop\s+)(r\d+)/ldmia sp\!, \{$2\}/g;
177
178    # NEON code
179    s/(vld1.\d+\s+)(q\d+)/$1\{$2\}/g;
180    s/(vtbl.\d+\s+[^,]+),([^,]+)/$1,\{$2\}/g;
181
182    if ($thumb) {
183        thumb::FixThumbInstructions($_, 0);
184    }
185
186    # eabi_attributes numerical equivalents can be found in the
187    # "ARM IHI 0045C" document.
188
189    if ($elf) {
190        # REQUIRE8 Stack is required to be 8-byte aligned
191        s/\sREQUIRE8/.eabi_attribute 24, 1 \@Tag_ABI_align_needed/g;
192
193        # PRESERVE8 Stack 8-byte align is preserved
194        s/\sPRESERVE8/.eabi_attribute 25, 1 \@Tag_ABI_align_preserved/g;
195    } else {
196        s/\sREQUIRE8//;
197        s/\sPRESERVE8//;
198    }
199
200    # Use PROC and ENDP to give the symbols a .size directive.
201    # This makes them show up properly in debugging tools like gdb and valgrind.
202    if (/\bPROC\b/)
203    {
204        my $proc;
205        /^_([\.0-9A-Z_a-z]\w+)\b/;
206        $proc = $1;
207        push(@proc_stack, $proc) if ($proc);
208        s/\bPROC\b/@ $&/;
209    }
210    if (/\bENDP\b/)
211    {
212        my $proc;
213        s/\bENDP\b/@ $&/;
214        $proc = pop(@proc_stack);
215        $_ = "\t.size $proc, .-$proc".$_ if ($proc and $elf);
216    }
217
218    # EQU directive
219    s/(\S+\s+)EQU(\s+\S+)/.equ $1, $2/;
220
221    # Begin macro definition
222    if (/\bMACRO\b/) {
223        $_ = <STDIN>;
224        s/^/.macro/;
225        s/\$//g;                # remove formal param reference
226        s/;/@/g;                # change comment characters
227    }
228
229    # For macros, use \ to reference formal params
230    s/\$/\\/g;                  # End macro definition
231    s/\bMEND\b/.endm/;              # No need to tell it where to stop assembling
232    next if /^\s*END\s*$/;
233    print;
234    print "$comment_sub$comment\n" if defined $comment;
235}
236
237# Mark that this object doesn't need an executable stack.
238printf ("\t.section\t.note.GNU-stack,\"\",\%\%progbits\n") if $elf;
239