1#!/usr/bin/env perl
2
3# ARM assembler distiller by <appro>.
4
5use strict;
6
7my $flavour = shift;
8my $output = shift;
9open STDOUT,">$output" || die "can't open $output: $!";
10
11$flavour = "linux32" if (!$flavour or $flavour eq "void");
12
13my %GLOBALS;
14my $dotinlocallabels=($flavour=~/linux/)?1:0;
15
16################################################################
17# directives which need special treatment on different platforms
18################################################################
19my $arch = sub {
20    if ($flavour =~ /linux/)	{ ".arch\t".join(',',@_); }
21    else			{ ""; }
22};
23my $fpu = sub {
24    if ($flavour =~ /linux/)	{ ".fpu\t".join(',',@_); }
25    else			{ ""; }
26};
27my $hidden = sub {
28    if ($flavour =~ /ios/)	{ ".private_extern\t".join(',',@_); }
29    else			{ ".hidden\t".join(',',@_); }
30};
31my $comm = sub {
32    my @args = split(/,\s*/,shift);
33    my $name = @args[0];
34    my $global = \$GLOBALS{$name};
35    my $ret;
36
37    if ($flavour =~ /ios32/)	{
38	$ret = ".comm\t_$name,@args[1]\n";
39	$ret .= ".non_lazy_symbol_pointer\n";
40	$ret .= "$name:\n";
41	$ret .= ".indirect_symbol\t_$name\n";
42	$ret .= ".long\t0";
43	$name = "_$name";
44    } else			{ $ret = ".comm\t".join(',',@args); }
45
46    $$global = $name;
47    $ret;
48};
49my $globl = sub {
50    my $name = shift;
51    my $global = \$GLOBALS{$name};
52    my $ret;
53
54    SWITCH: for ($flavour) {
55	/ios/		&& do { $name = "_$name";
56				last;
57			      };
58    }
59
60    $ret = ".globl	$name\n";
61    # All symbols in assembly files are hidden.
62    $ret .= &$hidden($name);
63    $$global = $name;
64    $ret;
65};
66my $global = $globl;
67my $extern = sub {
68    &$globl(@_);
69    return;	# return nothing
70};
71my $type = sub {
72    if ($flavour =~ /linux/)	{ ".type\t".join(',',@_); }
73    else			{ ""; }
74};
75my $size = sub {
76    if ($flavour =~ /linux/)	{ ".size\t".join(',',@_); }
77    else			{ ""; }
78};
79my $inst = sub {
80    if ($flavour =~ /linux/)    { ".inst\t".join(',',@_); }
81    else                        { ".long\t".join(',',@_); }
82};
83my $asciz = sub {
84    my $line = join(",",@_);
85    if ($line =~ /^"(.*)"$/)
86    {	".byte	" . join(",",unpack("C*",$1),0) . "\n.align	2";	}
87    else
88    {	"";	}
89};
90
91sub range {
92  my ($r,$sfx,$start,$end) = @_;
93
94    join(",",map("$r$_$sfx",($start..$end)));
95}
96
97sub expand_line {
98  my $line = shift;
99  my @ret = ();
100
101    pos($line)=0;
102
103    while ($line =~ m/\G[^@\/\{\"]*/g) {
104	if ($line =~ m/\G(@|\/\/|$)/gc) {
105	    last;
106	}
107	elsif ($line =~ m/\G\{/gc) {
108	    my $saved_pos = pos($line);
109	    $line =~ s/\G([rdqv])([0-9]+)([^\-]*)\-\1([0-9]+)\3/range($1,$3,$2,$4)/e;
110	    pos($line) = $saved_pos;
111	    $line =~ m/\G[^\}]*\}/g;
112	}
113	elsif ($line =~ m/\G\"/gc) {
114	    $line =~ m/\G[^\"]*\"/g;
115	}
116    }
117
118    $line =~ s/\b(\w+)/$GLOBALS{$1} or $1/ge;
119
120    return $line;
121}
122
123print "#if defined(__arm__)\n" if ($flavour eq "linux32");
124print "#if defined(__aarch64__)\n" if ($flavour eq "linux64");
125
126while(my $line=<>) {
127
128    if ($line =~ m/^\s*(#|@|\/\/)/)	{ print $line; next; }
129
130    $line =~ s|/\*.*\*/||;	# get rid of C-style comments...
131    $line =~ s|^\s+||;		# ... and skip white spaces in beginning...
132    $line =~ s|\s+$||;		# ... and at the end
133
134    {
135	$line =~ s|[\b\.]L(\w{2,})|L$1|g;	# common denominator for Locallabel
136	$line =~ s|\bL(\w{2,})|\.L$1|g	if ($dotinlocallabels);
137    }
138
139    {
140	$line =~ s|(^[\.\w]+)\:\s*||;
141	my $label = $1;
142	if ($label) {
143	    printf "%s:",($GLOBALS{$label} or $label);
144	}
145    }
146
147    if ($line !~ m/^[#@]/) {
148	$line =~ s|^\s*(\.?)(\S+)\s*||;
149	my $c = $1; $c = "\t" if ($c eq "");
150	my $mnemonic = $2;
151	my $opcode;
152	if ($mnemonic =~ m/([^\.]+)\.([^\.]+)/) {
153	    $opcode = eval("\$$1_$2");
154	} else {
155	    $opcode = eval("\$$mnemonic");
156	}
157
158	my $arg=expand_line($line);
159
160	if (ref($opcode) eq 'CODE') {
161		$line = &$opcode($arg);
162	} elsif ($mnemonic)         {
163		$line = $c.$mnemonic;
164		$line.= "\t$arg" if ($arg ne "");
165	}
166    }
167
168    print $line if ($line);
169    print "\n";
170}
171
172print "#endif\n" if ($flavour eq "linux32" || $flavour eq "linux64");
173
174close STDOUT;
175