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