summaryrefslogtreecommitdiffstats
path: root/crypto/perlasm/x86_64-xlate.pl
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/perlasm/x86_64-xlate.pl')
-rwxr-xr-xcrypto/perlasm/x86_64-xlate.pl169
1 files changed, 162 insertions, 7 deletions
diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl
index 6b93cfb84f..80fe1ff197 100755
--- a/crypto/perlasm/x86_64-xlate.pl
+++ b/crypto/perlasm/x86_64-xlate.pl
@@ -156,6 +156,65 @@ _____
}
my $current_segment;
+#
+# I could not find equivalent of .previous directive for MASM (Microsoft
+# assembler ML). Using of .previous got introduced to .pl files with
+# placing of various constants into .rodata sections (segments).
+# Each .rodata section is terminated by .previous directive which
+# restores the preceding section to .rodata:
+#
+# .text
+# ; this is is the text section/segment
+# .rodata
+# ; constant definitions go here
+# .previous
+# ; the .text section which precedes .rodata got restored here
+#
+# The equivalent form for masm reads as follows:
+#
+# .text$ SEGMENT ALIGN(256) 'CODE'
+# ; this is is the text section/segment
+# .text$ ENDS
+# .rdata SEGMENT READONLY ALIGN(64)
+# ; constant definitions go here
+# .rdata$ ENDS
+# .text$ SEGMENT ALIGN(256) 'CODE'
+# ; text section follows
+# .text$ ENDS
+#
+# The .previous directive typically terminates .roadata segments/sections which
+# hold definitions of constants. In order to place constants into .rdata
+# segments when using masm we need to introduce a segment_stack array so we can
+# emit proper ENDS directive whenever we see .previous.
+#
+# The code is tailored to work current set of .pl/asm files. There are some
+# inconsistencies. For example .text section is the first section in all those
+# files except ecp_nistz256. So we need to take that into account.
+#
+# ; stack is empty
+# .text
+# ; push '.text ' section twice, the stack looks as
+# ; follows:
+# ; ('.text', '.text')
+# .rodata
+# ; pop() so we can generate proper 'ENDS' for masm.
+# ; stack looks like:
+# ; ('.text')
+# ; push '.rodata', so we can create corresponding ENDS for masm.
+# ; stack looks like:
+# ; ('.rodata', '.text')
+# .previous
+# ; pop() '.rodata' from stack, so we create '.rodata ENDS'
+# ; in masm flavour. For nasm flavour we just pop() because
+# ; nasm does not use .rodata ENDS to close the current section
+# ; the stack content is like this:
+# ; ('.text', '.text')
+# ; pop() again to find a previous section we need to restore.
+# ; Depending on flavour we either generate .section .text
+# ; or .text SEGMENT. The stack looks like:
+# ; ('.text')
+#
+my @segment_stack = ();
my $current_function;
my %globals;
@@ -844,7 +903,21 @@ my %globals;
} elsif (!$elf && $dir =~ /\.align/) {
$self->{value} = ".p2align\t" . (log($$line)/log(2));
} elsif ($dir eq ".section") {
- $current_segment=$$line;
+ #
+ # get rid off align option, it's not supported/tolerated
+ # by gcc. openssl project introduced the option as an aid
+ # to deal with nasm/masm assembly.
+ #
+ $self->{value} =~ s/(.+)\s+align\s*=.*$/$1/;
+ #
+ # $$line may still contains align= option. We do care
+ # about section type here.
+ #
+ $current_segment = $$line;
+ $current_segment =~ s/([^\s]+).*$/$1/;
+ if (!$elf && $current_segment eq ".rodata") {
+ if ($flavour eq "macosx") { $self->{value} = ".section\t__DATA,__const"; }
+ }
if (!$elf && $current_segment eq ".init") {
if ($flavour eq "macosx") { $self->{value} = ".mod_init_func"; }
elsif ($flavour eq "mingw64") { $self->{value} = ".section\t.ctors"; }
@@ -857,6 +930,8 @@ my %globals;
} elsif ($dir =~ /\.comm/) {
$self->{value} = "$dir\t$prefix$$line";
$self->{value} =~ s|,([0-9]+),([0-9]+)$|",$1,".log($2)/log(2)|e if ($flavour eq "macosx");
+ } elsif ($dir =~ /\.previous/) {
+ $self->{value} = "" if ($flavour eq "mingw64");
}
$$line = "";
return $self;
@@ -866,10 +941,21 @@ my %globals;
SWITCH: for ($dir) {
/\.text/ && do { my $v=undef;
if ($nasm) {
+ $current_segment = pop(@segment_stack);
+ if (not $current_segment) {
+ push(@segment_stack, ".text");
+ }
$v="section .text code align=64\n";
+ $current_segment = ".text";
+ push(@segment_stack, $current_segment);
} else {
+ $current_segment = pop(@segment_stack);
+ if (not $current_segment) {
+ push(@segment_stack, ".text\$");
+ }
$v="$current_segment\tENDS\n" if ($current_segment);
$current_segment = ".text\$";
+ push(@segment_stack, $current_segment);
$v.="$current_segment\tSEGMENT ";
$v.=$masm>=$masmref ? "ALIGN(256)" : "PAGE";
$v.=" 'CODE'";
@@ -881,36 +967,75 @@ my %globals;
if ($nasm) {
$v="section .data data align=8\n";
} else {
+ $current_segment = pop(@segment_stack);
$v="$current_segment\tENDS\n" if ($current_segment);
$current_segment = "_DATA";
+ push(@segment_stack, $current_segment);
$v.="$current_segment\tSEGMENT";
}
$self->{value} = $v;
last;
};
/\.section/ && do { my $v=undef;
- $$line =~ s/([^,]*).*/$1/;
+ my $align=undef;
+ #
+ # $$line may currently contain something like this
+ # .rodata align = 64
+ # align part is optional
+ #
+ $align = $$line;
+ $align =~ s/(.*)(align\s*=\s*\d+$)/$2/;
+ $$line =~ s/(.*)(\s+align\s*=\s*\d+$)/$1/;
$$line = ".CRT\$XCU" if ($$line eq ".init");
+ $$line = ".rdata" if ($$line eq ".rodata");
if ($nasm) {
+ $current_segment = pop(@segment_stack);
+ if (not $current_segment) {
+ #
+ # This is a hack which deals with ecp_nistz256-x86_64.pl,
+ # The precomputed curve is stored in the first section
+ # in .asm file. Pushing extra .text section here
+ # allows our poor man's solution to stick to assumption
+ # .text section is always the first.
+ #
+ push(@segment_stack, ".text");
+ }
$v="section $$line";
- if ($$line=~/\.([px])data/) {
- $v.=" rdata align=";
- $v.=$1 eq "p"? 4 : 8;
+ if ($$line=~/\.([prx])data/) {
+ if ($align =~ /align\s*=\s*(\d+)/) {
+ $v.= " rdata align=$1" ;
+ } else {
+ $v.=" rdata align=";
+ $v.=$1 eq "p"? 4 : 8;
+ }
} elsif ($$line=~/\.CRT\$/i) {
$v.=" rdata align=8";
}
} else {
+ $current_segment = pop(@segment_stack);
+ if (not $current_segment) {
+ #
+ # same hack for masm to keep ecp_nistz256-x86_64.pl
+ # happy.
+ #
+ push(@segment_stack, ".text\$");
+ }
$v="$current_segment\tENDS\n" if ($current_segment);
$v.="$$line\tSEGMENT";
- if ($$line=~/\.([px])data/) {
+ if ($$line=~/\.([prx])data/) {
$v.=" READONLY";
- $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref);
+ if ($align =~ /align\s*=\s*(\d+)$/) {
+ $v.=" ALIGN($1)" if ($masm>=$masmref);
+ } else {
+ $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref);
+ }
} elsif ($$line=~/\.CRT\$/i) {
$v.=" READONLY ";
$v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD";
}
}
$current_segment = $$line;
+ push(@segment_stack, $$line);
$self->{value} = $v;
last;
};
@@ -973,14 +1098,44 @@ my %globals;
if ($nasm) {
$v.="common $prefix@str[0] @str[1]";
} else {
+ $current_segment = pop(@segment_stack);;
$v="$current_segment\tENDS\n" if ($current_segment);
$current_segment = "_DATA";
+ push(@segment_stack, $current_segment);
$v.="$current_segment\tSEGMENT\n";
$v.="COMM @str[0]:DWORD:".@str[1]/4;
}
$self->{value} = $v;
last;
};
+ /^.previous/ && do {
+ my $v=undef;
+ if ($nasm) {
+ pop(@segment_stack); # pop ourselves, we don't need to emit END directive
+ # pop section so we can emit proper .section name.
+ $current_segment = pop(@segment_stack);
+ $v="section $current_segment";
+ # Hack again:
+ # push section/segment to stack. The .previous is currently paired
+ # with .rodata only. We have to keep extra '.text' on stack for
+ # situation where there is for example .pdata section 'terminated'
+ # by new '.text' section.
+ #
+ push(@segment_stack, $current_segment);
+ } else {
+ $current_segment = pop(@segment_stack);
+ $v="$current_segment\tENDS\n" if ($current_segment);
+ $current_segment = pop(@segment_stack);
+ if ($current_segment =~ /\.text\$/) {
+ $v.="$current_segment\tSEGMENT ";
+ $v.=$masm>=$masmref ? "ALIGN(256)" : "PAGE";
+ $v.=" 'CODE'";
+ push(@segment_stack, $current_segment);
+ }
+ }
+ $self->{value} = $v;
+ last;
+ };
}
$$line = "";
}