diff options
-rwxr-xr-x | tools/darwin/depends/gas-preprocessor/gas-preprocessor.pl | 161 |
1 files changed, 135 insertions, 26 deletions
diff --git a/tools/darwin/depends/gas-preprocessor/gas-preprocessor.pl b/tools/darwin/depends/gas-preprocessor/gas-preprocessor.pl index fb81883d0f..3d7aee7ee0 100755 --- a/tools/darwin/depends/gas-preprocessor/gas-preprocessor.pl +++ b/tools/darwin/depends/gas-preprocessor/gas-preprocessor.pl @@ -13,6 +13,16 @@ use strict; my @gcc_cmd = @ARGV; my @preprocess_c_cmd; +my $fix_unreq = $^O eq "darwin"; + +if ($gcc_cmd[0] eq "-fix-unreq") { + $fix_unreq = 1; + shift @gcc_cmd; +} elsif ($gcc_cmd[0] eq "-no-fix-unreq") { + $fix_unreq = 0; + shift @gcc_cmd; +} + if (grep /\.c$/, @gcc_cmd) { # C file (inline asm?) - compile @preprocess_c_cmd = (@gcc_cmd, "-S"); @@ -22,6 +32,19 @@ if (grep /\.c$/, @gcc_cmd) { } else { die "Unrecognized input filetype"; } + +# if compiling, avoid creating an output file named '-.o' +if ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) { + foreach my $i (@gcc_cmd) { + if ($i =~ /\.[csS]$/) { + my $outputfile = $i; + $outputfile =~ s/\.[csS]$/.o/; + push(@gcc_cmd, "-o"); + push(@gcc_cmd, $outputfile); + last; + } + } +} @gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd; @preprocess_c_cmd = map { /\.o$/ ? "-" : $_ } @preprocess_c_cmd; @@ -87,6 +110,8 @@ while (<ASMFILE>) { s/\.ltorg/$comm.ltorg/x; s/\.size/$comm.size/x; s/\.fpu/$comm.fpu/x; + s/\.arch/$comm.arch/x; + s/\.object_arch/$comm.object_arch/x; # the syntax for these is a little different s/\.global/.globl/x; @@ -103,6 +128,41 @@ while (<ASMFILE>) { parse_line($_); } +sub handle_if { + my $line = $_[0]; + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if ($line =~ /\.if(n?)([a-z]*)\s+(.*)/) { + my $result = $1 eq "n"; + my $type = $2; + my $expr = $3; + + if ($type eq "b") { + $expr =~ s/\s//g; + $result ^= $expr eq ""; + } elsif ($type eq "c") { + if ($expr =~ /(.*)\s*,\s*(.*)/) { + $result ^= $1 eq $2; + } else { + die "argument to .ifc not recognized"; + } + } elsif ($type eq "") { + $result ^= eval($expr) != 0; + } elsif ($type eq "eq") { + $result = eval($expr) == 0; + } elsif ($type eq "lt") { + $result = eval($expr) < 0; + } else { + chomp($line); + die "unhandled .if varient. \"$line\""; + } + push (@ifstack, $result); + return 1; + } else { + return 0; + } +} + sub parse_line { my $line = @_[0]; @@ -121,11 +181,15 @@ sub parse_line { } elsif (/\.else/) { $ifstack[-1] = !$ifstack[-1]; return; + } elsif (handle_if($line)) { + return; } # discard lines in false .if blocks - if ($ifstack[-1] <= 0) { - return; + foreach my $i (0 .. $#ifstack) { + if ($ifstack[$i] <= 0) { + return; + } } } @@ -179,26 +243,7 @@ sub expand_macros { # handle .if directives; apple's assembler doesn't support important non-basic ones # evaluating them is also needed to handle recursive macros - if ($line =~ /\.if(n?)([a-z]*)\s+(.*)/) { - my $result = $1 eq "n"; - my $type = $2; - my $expr = $3; - - if ($type eq "b") { - $expr =~ s/\s//g; - $result ^= $expr eq ""; - } elsif ($type eq "c") { - if ($expr =~ /(.*)\s*,\s*(.*)/) { - $result ^= $1 eq $2; - } else { - die "argument to .ifc not recognized"; - } - } elsif ($type eq "") { - $result ^= eval($expr) != 0; - } else { - die "unhandled .if varient"; - } - push (@ifstack, $result); + if (handle_if($line)) { return; } @@ -217,17 +262,32 @@ sub expand_macros { # parameters can be blank my @arglist = split(/,/, $3); my @args; + my @args_seperator; + + my $comma_sep_required = 0; foreach (@arglist) { + # allow for + and - in macro arguments + $_ =~ s/\s*\+\s*/+/; + $_ =~ s/\s*\-\s*/-/; + my @whitespace_split = split(/\s+/, $_); if (!@whitespace_split) { push(@args, ''); + push(@args_seperator, ''); } else { foreach (@whitespace_split) { + #print ("arglist = \"$_\"\n"); if (length($_)) { push(@args, $_); + my $sep = $comma_sep_required ? "," : " "; + push(@args_seperator, $sep); + #print ("sep = \"$sep\", arg = \"$_\"\n"); + $comma_sep_required = 0; } } } + + $comma_sep_required = 1; } my %replacements; @@ -238,7 +298,7 @@ sub expand_macros { # construct hashtable of text to replace foreach my $i (0 .. $#args) { my $argname = $macro_args{$macro}[$i]; - + my @macro_args = @{ $macro_args{$macro} }; if ($args[$i] =~ m/=/) { # arg=val references the argument name # XXX: I'm not sure what the expected behaviour if a lot of @@ -250,7 +310,9 @@ sub expand_macros { # XXX: is vararg allowed on arguments before the last? $argname = $macro_args{$macro}[-1]; if ($argname =~ s/:vararg$//) { - $replacements{$argname} .= ", $args[$i]"; + #print "macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\n"; + #$replacements{$argname} .= ", $args[$i]"; + $replacements{$argname} .= "$args_seperator[$i] $args[$i]"; } else { die "Too many arguments to macro $macro"; } @@ -278,6 +340,7 @@ sub expand_macros { close(ASMFILE) or exit 1; open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler"; +#open(ASMFILE, ">/tmp/a.S") or die "Error running assembler"; my @sections; my $num_repts; @@ -286,6 +349,10 @@ my $rept_lines; my %literal_labels; # for ldr <reg>, =<expr> my $literal_num = 0; +my $in_irp = 0; +my @irp_args; +my $irp_param; + # pass 2: parse .rept and .if variants # NOTE: since we don't implement a proper parser, using .rept with a # variable assigned from .set is not supported @@ -330,6 +397,15 @@ foreach my $line (@pass1_lines) { } } + # old gas versions store upper and lower case names on .req, + # but they remove only one on .unreq + if ($fix_unreq) { + if ($line =~ /\.unreq\s+(.*)/) { + $line = ".unreq " . lc($1) . "\n"; + print ASMFILE ".unreq " . uc($1) . "\n"; + } + } + if ($line =~ /\.rept\s+(.*)/) { $num_repts = $1; $rept_lines = "\n"; @@ -340,11 +416,43 @@ foreach my $line (@pass1_lines) { $rept_lines .= "$1\n"; } $num_repts = eval($num_repts); + } elsif ($line =~ /\.irp\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + $rept_lines = "\n"; + $irp_param = $1; + + # only use whitespace as the separator + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(/\s+/, $irp_arglist); + } elsif ($line =~ /\.irpc\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + $rept_lines = "\n"; + $irp_param = $1; + + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(//, $irp_arglist); } elsif ($line =~ /\.endr/) { - for (1 .. $num_repts) { - print ASMFILE $rept_lines; + if ($in_irp != 0) { + foreach my $i (@irp_args) { + my $line = $rept_lines; + $line =~ s/\\$irp_param/$i/g; + $line =~ s/\\\(\)//g; # remove \() + print ASMFILE $line; + } + } else { + for (1 .. $num_repts) { + print ASMFILE $rept_lines; + } } $rept_lines = ''; + $in_irp = 0; + @irp_args = ''; } elsif ($rept_lines) { $rept_lines .= $line; } else { @@ -358,3 +466,4 @@ foreach my $literal (keys %literal_labels) { } close(ASMFILE) or exit 1; +#exit 1 |