• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#! /usr/bin/env perl
2# Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the Apache License 2.0 (the "License").  You may not use
5# this file except in compliance with the License.  You can obtain a copy
6# in the file LICENSE in the source distribution or at
7# https://www.openssl.org/source/license.html
8
9use strict;
10
11my $flavour = shift;
12my $output = shift;
13open STDOUT,">$output" || die "can't open $output: $!";
14
15$flavour = "linux32" if (!$flavour or $flavour eq "void");
16
17my %GLOBALS;
18my $dotinlocallabels=($flavour=~/linux/)?1:0;
19
20################################################################
21# directives which need special treatment on different platforms
22################################################################
23my $arch = sub {
24    if ($flavour =~ /linux/)	{ ".arch\t".join(',',@_); }
25    else			{ ""; }
26};
27my $fpu = sub {
28    if ($flavour =~ /linux/)	{ ".fpu\t".join(',',@_); }
29    else			{ ""; }
30};
31my $rodata = sub {
32    SWITCH: for ($flavour) {
33	/linux/		&& return ".section\t.rodata";
34	/ios/		&& return ".section\t__TEXT,__const";
35	last;
36    }
37};
38my $hidden = sub {
39    if ($flavour =~ /ios/)	{ ".private_extern\t".join(',',@_); }
40    else			{ ".hidden\t".join(',',@_); }
41};
42my $comm = sub {
43    my @args = split(/,\s*/,shift);
44    my $name = @args[0];
45    my $global = \$GLOBALS{$name};
46    my $ret;
47
48    if ($flavour =~ /ios32/)	{
49	$ret = ".comm\t_$name,@args[1]\n";
50	$ret .= ".non_lazy_symbol_pointer\n";
51	$ret .= "$name:\n";
52	$ret .= ".indirect_symbol\t_$name\n";
53	$ret .= ".long\t0";
54	$name = "_$name";
55    } else			{ $ret = ".comm\t".join(',',@args); }
56
57    $$global = $name;
58    $ret;
59};
60my $globl = sub {
61    my $name = shift;
62    my $global = \$GLOBALS{$name};
63    my $ret;
64
65    SWITCH: for ($flavour) {
66	/ios/		&& do { $name = "_$name";
67				last;
68			      };
69    }
70
71    $ret = ".globl	$name" if (!$ret);
72    $$global = $name;
73    $ret;
74};
75my $global = $globl;
76my $extern = sub {
77    &$globl(@_);
78    return;	# return nothing
79};
80my $type = sub {
81    if ($flavour =~ /linux/)	{ ".type\t".join(',',@_); }
82    elsif ($flavour =~ /ios32/)	{ if (join(',',@_) =~ /(\w+),%function/) {
83					"#ifdef __thumb2__\n".
84					".thumb_func	$1\n".
85					"#endif";
86				  }
87			        }
88    else			{ ""; }
89};
90my $size = sub {
91    if ($flavour =~ /linux/)	{ ".size\t".join(',',@_); }
92    else			{ ""; }
93};
94my $inst = sub {
95    if ($flavour =~ /linux/)    { ".inst\t".join(',',@_); }
96    else                        { ".long\t".join(',',@_); }
97};
98my $asciz = sub {
99    my $line = join(",",@_);
100    if ($line =~ /^"(.*)"$/)
101    {	".byte	" . join(",",unpack("C*",$1),0) . "\n.align	2";	}
102    else
103    {	"";	}
104};
105
106my $adrp = sub {
107    my ($args,$comment) = split(m|\s*//|,shift);
108    if ($flavour =~ /ios64/) {
109        "\tadrp\t$args\@PAGE";
110    } elsif ($flavour =~ /linux/) {
111        #
112        # there seem to be two forms of 'addrp' instruction
113        # to calculate offset:
114	#    addrp	x3,x3,:lo12:Lrcon
115        # and alternate form:
116	#    addrp	x3,x3,:#lo12:Lrcon
117        # the '#' is mandatory for some compilers
118        # so make sure our asm always uses '#' here.
119        #
120        $args =~ s/(\w+)#?:lo2:(\.?\w+)/$1#:lo2:$2/;
121        if ($flavour =~ /linux32/) {
122            "\tadr\t$args";
123        } else {
124            "\tadrp\t$args";
125        }
126    }
127} if (($flavour =~ /ios64/) || ($flavour =~ /linux/));
128
129sub range {
130  my ($r,$sfx,$start,$end) = @_;
131
132    join(",",map("$r$_$sfx",($start..$end)));
133}
134
135sub expand_line {
136  my $line = shift;
137  my @ret = ();
138
139    pos($line)=0;
140
141    while ($line =~ m/\G[^@\/\{\"]*/g) {
142	if ($line =~ m/\G(@|\/\/|$)/gc) {
143	    last;
144	}
145	elsif ($line =~ m/\G\{/gc) {
146	    my $saved_pos = pos($line);
147	    $line =~ s/\G([rdqv])([0-9]+)([^\-]*)\-\1([0-9]+)\3/range($1,$3,$2,$4)/e;
148	    pos($line) = $saved_pos;
149	    $line =~ m/\G[^\}]*\}/g;
150	}
151	elsif ($line =~ m/\G\"/gc) {
152	    $line =~ m/\G[^\"]*\"/g;
153	}
154    }
155
156    $line =~ s/\b(\w+)/$GLOBALS{$1} or $1/ge;
157
158    if ($flavour =~ /ios64/) {
159	$line =~ s/#?:lo12:(\w+)/$1\@PAGEOFF/;
160    } elsif($flavour =~ /linux/) {
161        #
162        # make '#' mandatory for :lo12: (similar to adrp above)
163        #
164	$line =~ s/#?:lo12:(\.?\w+)/\#:lo12:$1/;
165    }
166
167    return $line;
168}
169
170while(my $line=<>) {
171
172    if ($line =~ m/^\s*(#|@|\/\/)/)	{ print $line; next; }
173
174    $line =~ s|/\*.*\*/||;	# get rid of C-style comments...
175    $line =~ s|^\s+||;		# ... and skip whitespace in beginning...
176    $line =~ s|\s+$||;		# ... and at the end
177
178    {
179	$line =~ s|[\b\.]L(\w{2,})|L$1|g;	# common denominator for Locallabel
180	$line =~ s|\bL(\w{2,})|\.L$1|g	if ($dotinlocallabels);
181    }
182
183    {
184	$line =~ s|(^[\.\w]+)\:\s*||;
185	my $label = $1;
186	if ($label) {
187	    printf "%s:",($GLOBALS{$label} or $label);
188	}
189    }
190
191    if ($line !~ m/^[#@]/) {
192	$line =~ s|^\s*(\.?)(\S+)\s*||;
193	my $c = $1; $c = "\t" if ($c eq "");
194	my $mnemonic = $2;
195	my $opcode;
196	if ($mnemonic =~ m/([^\.]+)\.([^\.]+)/) {
197	    $opcode = eval("\$$1_$2");
198	} else {
199	    $opcode = eval("\$$mnemonic");
200	}
201
202	my $arg=expand_line($line);
203
204	if (ref($opcode) eq 'CODE') {
205		$line = &$opcode($arg);
206	} elsif ($mnemonic)         {
207		$line = $c.$mnemonic;
208		$line.= "\t$arg" if ($arg ne "");
209	}
210    }
211
212    print $line if ($line);
213    print "\n";
214}
215
216close STDOUT or die "error closing STDOUT: $!";
217