summaryrefslogtreecommitdiffstats
path: root/crypto/sha
diff options
context:
space:
mode:
authorAndy Polyakov <appro@openssl.org>2014-06-06 21:27:18 +0200
committerAndy Polyakov <appro@openssl.org>2014-06-10 22:51:15 +0200
commit3a97ebb16b0d1eaab83171b9220280dacd99bf04 (patch)
tree89717093f8561e28fc5e6c40e02c8411d8eb0f48 /crypto/sha
parent16f4d2e32f1ea6cfa668ae64493998ae51db7e51 (diff)
ARM assembly pack: get ARMv7 instruction endianness right.
Pointer out and suggested by: Ard Biesheuvel. (cherry picked from commit 5dcf70a1c57c2019bfad640fe14fd4a73212860a)
Diffstat (limited to 'crypto/sha')
-rw-r--r--crypto/sha/asm/sha1-armv4-large.pl20
-rw-r--r--crypto/sha/asm/sha256-armv4.pl20
-rw-r--r--crypto/sha/asm/sha512-armv4.pl3
3 files changed, 28 insertions, 15 deletions
diff --git a/crypto/sha/asm/sha1-armv4-large.pl b/crypto/sha/asm/sha1-armv4-large.pl
index 43a1b9fd7f..50bd07b331 100644
--- a/crypto/sha/asm/sha1-armv4-large.pl
+++ b/crypto/sha/asm/sha1-armv4-large.pl
@@ -631,7 +631,7 @@ $code.=<<___;
vst1.32 {$E\[0]},[$ctx]
vldmia sp!,{d8-d15}
- bx lr
+ ret @ bx lr
.size sha1_block_data_order_armv8,.-sha1_block_data_order_armv8
#endif
___
@@ -648,13 +648,18 @@ ___
sub unsha1 {
my ($mnemonic,$arg)=@_;
- $arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o
- &&
- sprintf ".long\t0x%08x\t@ %s %s",
- $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
- |(($2&7)<<17)|(($2&8)<<4)
- |(($3&7)<<1) |(($3&8)<<2),
+ if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) {
+ my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
+ |(($2&7)<<17)|(($2&8)<<4)
+ |(($3&7)<<1) |(($3&8)<<2);
+ # since ARMv7 instructions are always encoded little-endian.
+ # correct solution is to use .inst directive, but older
+ # assemblers don't implement it:-(
+ sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s",
+ $word&0xff,($word>>8)&0xff,
+ ($word>>16)&0xff,($word>>24)&0xff,
$mnemonic,$arg;
+ }
}
}
@@ -664,6 +669,7 @@ foreach (split($/,$code)) {
s/\b(sha1\w+)\s+(q.*)/unsha1($1,$2)/geo;
+ s/\bret\b/bx lr/o or
s/\bbx\s+lr\b/.word\t0xe12fff1e/o; # make it possible to compile with -march=armv4
print $_,$/;
diff --git a/crypto/sha/asm/sha256-armv4.pl b/crypto/sha/asm/sha256-armv4.pl
index 5e5c54ec18..505ca8f350 100644
--- a/crypto/sha/asm/sha256-armv4.pl
+++ b/crypto/sha/asm/sha256-armv4.pl
@@ -608,7 +608,7 @@ $code.=<<___;
vst1.32 {$ABCD,$EFGH},[$ctx]
- bx lr
+ ret @ bx lr
.size sha256_block_data_order_armv8,.-sha256_block_data_order_armv8
#endif
___
@@ -626,13 +626,18 @@ ___
sub unsha256 {
my ($mnemonic,$arg)=@_;
- $arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o
- &&
- sprintf ".long\t0x%08x\t@ %s %s",
- $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
- |(($2&7)<<17)|(($2&8)<<4)
- |(($3&7)<<1) |(($3&8)<<2),
+ if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) {
+ my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
+ |(($2&7)<<17)|(($2&8)<<4)
+ |(($3&7)<<1) |(($3&8)<<2);
+ # since ARMv7 instructions are always encoded little-endian.
+ # correct solution is to use .inst directive, but older
+ # assemblers don't implement it:-(
+ sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s",
+ $word&0xff,($word>>8)&0xff,
+ ($word>>16)&0xff,($word>>24)&0xff,
$mnemonic,$arg;
+ }
}
}
@@ -642,6 +647,7 @@ foreach (split($/,$code)) {
s/\b(sha256\w+)\s+(q.*)/unsha256($1,$2)/geo;
+ s/\bret\b/bx lr/go or
s/\bbx\s+lr\b/.word\t0xe12fff1e/go; # make it possible to compile with -march=armv4
print $_,"\n";
diff --git a/crypto/sha/asm/sha512-armv4.pl b/crypto/sha/asm/sha512-armv4.pl
index d3065794b3..1d5275b917 100644
--- a/crypto/sha/asm/sha512-armv4.pl
+++ b/crypto/sha/asm/sha512-armv4.pl
@@ -584,7 +584,7 @@ $code.=<<___;
bne .Loop_neon
vldmia sp!,{d8-d15} @ epilogue
- bx lr
+ ret @ bx lr
#endif
___
}
@@ -597,5 +597,6 @@ ___
$code =~ s/\`([^\`]*)\`/eval $1/gem;
$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
+$code =~ s/\bret\b/bx lr/gm;
print $code;
close STDOUT; # enforce flush