michael@0: #!/usr/bin/perl michael@0: ## michael@0: ## Copyright (c) 2010 The WebM project authors. All Rights Reserved. michael@0: ## michael@0: ## Use of this source code is governed by a BSD-style license michael@0: ## that can be found in the LICENSE file in the root of the source michael@0: ## tree. An additional intellectual property rights grant can be found michael@0: ## in the file PATENTS. All contributing project authors may michael@0: ## be found in the AUTHORS file in the root of the source tree. michael@0: ## michael@0: michael@0: michael@0: # ads2gas.pl michael@0: # Author: Eric Fung (efung (at) acm.org) michael@0: # michael@0: # Convert ARM Developer Suite 1.0.1 syntax assembly source to GNU as format michael@0: # michael@0: # Usage: cat inputfile | perl ads2gas.pl > outputfile michael@0: # michael@0: michael@0: use FindBin; michael@0: use lib $FindBin::Bin; michael@0: use thumb; michael@0: michael@0: my $thumb = 0; michael@0: michael@0: foreach my $arg (@ARGV) { michael@0: $thumb = 1 if ($arg eq "-thumb"); michael@0: } michael@0: michael@0: print "@ This file was created from a .asm file\n"; michael@0: print "@ using the ads2gas.pl script.\n"; michael@0: print "\t.equ DO1STROUNDING, 0\n"; michael@0: if ($thumb) { michael@0: print "\t.syntax unified\n"; michael@0: print "\t.thumb\n"; michael@0: } michael@0: michael@0: # Stack of procedure names. michael@0: @proc_stack = (); michael@0: michael@0: while () michael@0: { michael@0: undef $comment; michael@0: undef $line; michael@0: $comment_char = ";"; michael@0: $comment_sub = "@"; michael@0: michael@0: # Handle comments. michael@0: if (/$comment_char/) michael@0: { michael@0: $comment = ""; michael@0: ($line, $comment) = /(.*?)$comment_char(.*)/; michael@0: $_ = $line; michael@0: } michael@0: michael@0: # Load and store alignment michael@0: s/@/,:/g; michael@0: michael@0: # Hexadecimal constants prefaced by 0x michael@0: s/#&/#0x/g; michael@0: michael@0: # Convert :OR: to | michael@0: s/:OR:/ | /g; michael@0: michael@0: # Convert :AND: to & michael@0: s/:AND:/ & /g; michael@0: michael@0: # Convert :NOT: to ~ michael@0: s/:NOT:/ ~ /g; michael@0: michael@0: # Convert :SHL: to << michael@0: s/:SHL:/ << /g; michael@0: michael@0: # Convert :SHR: to >> michael@0: s/:SHR:/ >> /g; michael@0: michael@0: # Convert ELSE to .else michael@0: s/\bELSE\b/.else/g; michael@0: michael@0: # Convert ENDIF to .endif michael@0: s/\bENDIF\b/.endif/g; michael@0: michael@0: # Convert ELSEIF to .elseif michael@0: s/\bELSEIF\b/.elseif/g; michael@0: michael@0: # Convert LTORG to .ltorg michael@0: s/\bLTORG\b/.ltorg/g; michael@0: michael@0: # Convert endfunc to nothing. michael@0: s/\bendfunc\b//ig; michael@0: michael@0: # Convert FUNCTION to nothing. michael@0: s/\bFUNCTION\b//g; michael@0: s/\bfunction\b//g; michael@0: michael@0: s/\bENTRY\b//g; michael@0: s/\bMSARMASM\b/0/g; michael@0: s/^\s+end\s+$//g; michael@0: michael@0: # Convert IF :DEF:to .if michael@0: # gcc doesn't have the ability to do a conditional michael@0: # if defined variable that is set by IF :DEF: on michael@0: # armasm, so convert it to a normal .if and then michael@0: # make sure to define a value elesewhere michael@0: if (s/\bIF :DEF:\b/.if /g) michael@0: { michael@0: s/=/==/g; michael@0: } michael@0: michael@0: # Convert IF to .if michael@0: if (s/\bIF\b/.if/g) michael@0: { michael@0: s/=+/==/g; michael@0: } michael@0: michael@0: # Convert INCLUDE to .INCLUDE "file" michael@0: s/INCLUDE(\s*)(.*)$/.include $1\"$2\"/; michael@0: michael@0: # Code directive (ARM vs Thumb) michael@0: s/CODE([0-9][0-9])/.code $1/; michael@0: michael@0: # No AREA required michael@0: # But ALIGNs in AREA must be obeyed michael@0: s/^\s*AREA.*ALIGN=([0-9])$/.text\n.p2align $1/; michael@0: # If no ALIGN, strip the AREA and align to 4 bytes michael@0: s/^\s*AREA.*$/.text\n.p2align 2/; michael@0: michael@0: # DCD to .word michael@0: # This one is for incoming symbols michael@0: s/DCD\s+\|(\w*)\|/.long $1/; michael@0: michael@0: # DCW to .short michael@0: s/DCW\s+\|(\w*)\|/.short $1/; michael@0: s/DCW(.*)/.short $1/; michael@0: michael@0: # Constants defined in scope michael@0: s/DCD(.*)/.long $1/; michael@0: s/DCB(.*)/.byte $1/; michael@0: michael@0: # RN to .req michael@0: if (s/RN\s+([Rr]\d+|lr)/.req $1/) michael@0: { michael@0: print; michael@0: print "$comment_sub$comment\n" if defined $comment; michael@0: next; michael@0: } michael@0: michael@0: # Make function visible to linker, and make additional symbol with michael@0: # prepended underscore michael@0: s/EXPORT\s+\|([\$\w]*)\|/.global $1 \n\t.type $1, function/; michael@0: s/IMPORT\s+\|([\$\w]*)\|/.global $1/; michael@0: michael@0: s/EXPORT\s+([\$\w]*)/.global $1/; michael@0: s/export\s+([\$\w]*)/.global $1/; michael@0: michael@0: # No vertical bars required; make additional symbol with prepended michael@0: # underscore michael@0: s/^\|(\$?\w+)\|/_$1\n\t$1:/g; michael@0: michael@0: # Labels need trailing colon michael@0: # s/^(\w+)/$1:/ if !/EQU/; michael@0: # put the colon at the end of the line in the macro michael@0: s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/; michael@0: michael@0: # ALIGN directive michael@0: s/\bALIGN\b/.balign/g; michael@0: michael@0: if ($thumb) { michael@0: # ARM code - we force everything to thumb with the declaration in the header michael@0: s/\sARM//g; michael@0: } else { michael@0: # ARM code michael@0: s/\sARM/.arm/g; michael@0: } michael@0: michael@0: # push/pop michael@0: s/(push\s+)(r\d+)/stmdb sp\!, \{$2\}/g; michael@0: s/(pop\s+)(r\d+)/ldmia sp\!, \{$2\}/g; michael@0: michael@0: # NEON code michael@0: s/(vld1.\d+\s+)(q\d+)/$1\{$2\}/g; michael@0: s/(vtbl.\d+\s+[^,]+),([^,]+)/$1,\{$2\}/g; michael@0: michael@0: if ($thumb) { michael@0: thumb::FixThumbInstructions($_, 0); michael@0: } michael@0: michael@0: # eabi_attributes numerical equivalents can be found in the michael@0: # "ARM IHI 0045C" document. michael@0: michael@0: # REQUIRE8 Stack is required to be 8-byte aligned michael@0: s/\sREQUIRE8/.eabi_attribute 24, 1 \@Tag_ABI_align_needed/g; michael@0: michael@0: # PRESERVE8 Stack 8-byte align is preserved michael@0: s/\sPRESERVE8/.eabi_attribute 25, 1 \@Tag_ABI_align_preserved/g; michael@0: michael@0: # Use PROC and ENDP to give the symbols a .size directive. michael@0: # This makes them show up properly in debugging tools like gdb and valgrind. michael@0: if (/\bPROC\b/) michael@0: { michael@0: my $proc; michael@0: /^_([\.0-9A-Z_a-z]\w+)\b/; michael@0: $proc = $1; michael@0: push(@proc_stack, $proc) if ($proc); michael@0: s/\bPROC\b/@ $&/; michael@0: } michael@0: if (/\bENDP\b/) michael@0: { michael@0: my $proc; michael@0: s/\bENDP\b/@ $&/; michael@0: $proc = pop(@proc_stack); michael@0: $_ = "\t.size $proc, .-$proc".$_ if ($proc); michael@0: } michael@0: michael@0: # EQU directive michael@0: s/(\S+\s+)EQU(\s+\S+)/.equ $1, $2/; michael@0: michael@0: # Begin macro definition michael@0: if (/\bMACRO\b/) { michael@0: $_ = ; michael@0: s/^/.macro/; michael@0: s/\$//g; # remove formal param reference michael@0: s/;/@/g; # change comment characters michael@0: } michael@0: michael@0: # For macros, use \ to reference formal params michael@0: s/\$/\\/g; # End macro definition michael@0: s/\bMEND\b/.endm/; # No need to tell it where to stop assembling michael@0: next if /^\s*END\s*$/; michael@0: print; michael@0: print "$comment_sub$comment\n" if defined $comment; michael@0: } michael@0: michael@0: # Mark that this object doesn't need an executable stack. michael@0: printf ("\t.section\t.note.GNU-stack,\"\",\%\%progbits\n");