Work around a NASM bug
I did not have "find a bug in the assembler" on my bingo card today, but
here we are.
NASM 2.15, prior to 2.15.04, has a bug where, if a section that already
exists is referenced again with alignment qualifiers, it incorrect adds
padding and mangles the output. See
https://bugzilla.nasm.us/show_bug.cgi?id=3392701.
Work around this by suppressing the perlasm-emitted qualifiers the
second time a section is emitted. We likely don't need these qualifiers
because, for all sections we care about, NASM's defaults are fine, but
perlasm tries to align .text more aggressively than the default, so let
it do that.
Bug: chromium:1422018
Change-Id: Iade5702c139b70772d4957a83c8f9be86c8af97c
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/57825
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl
index b8802c5..16a7846 100755
--- a/crypto/perlasm/x86_64-xlate.pl
+++ b/crypto/perlasm/x86_64-xlate.pl
@@ -1029,6 +1029,27 @@
}
}
{ package directive; # pick up directives, which start with .
+ my %sections;
+ sub nasm_section {
+ my ($name, $qualifiers) = @_;
+ my $ret = "section\t$name";
+ if (exists $sections{$name}) {
+ # Work around https://bugzilla.nasm.us/show_bug.cgi?id=3392701. Only
+ # emit section qualifiers the first time a section is referenced.
+ # For all subsequent references, require the qualifiers match and
+ # omit them.
+ #
+ # See also https://crbug.com/1422018 and b/270643835.
+ my $old = $sections{$name};
+ die "Inconsistent qualifiers: $qualifiers vs $old" if ($qualifiers ne "" && $qualifiers ne $old);
+ } else {
+ $sections{$name} = $qualifiers;
+ if ($qualifiers ne "") {
+ $ret .= " $qualifiers";
+ }
+ }
+ return $ret;
+ }
sub re {
my ($class, $line) = @_;
my $self = {};
@@ -1137,7 +1158,7 @@
SWITCH: for ($dir) {
/\.text/ && do { my $v=undef;
if ($nasm) {
- $v="section .text code align=64\n";
+ $v=nasm_section(".text", "code align=64")."\n";
} else {
$v="$current_segment\tENDS\n" if ($current_segment);
$current_segment = ".text\$";
@@ -1150,7 +1171,7 @@
};
/\.data/ && do { my $v=undef;
if ($nasm) {
- $v="section .data data align=8\n";
+ $v=nasm_section(".data", "data align=8")."\n";
} else {
$v="$current_segment\tENDS\n" if ($current_segment);
$current_segment = "_DATA";
@@ -1164,13 +1185,14 @@
$$line = ".CRT\$XCU" if ($$line eq ".init");
$$line = ".rdata" if ($$line eq ".rodata");
if ($nasm) {
- $v="section $$line";
+ my $qualifiers = "";
if ($$line=~/\.([prx])data/) {
- $v.=" rdata align=";
- $v.=$1 eq "p"? 4 : 8;
+ $qualifiers = "rdata align=";
+ $qualifiers .= $1 eq "p"? 4 : 8;
} elsif ($$line=~/\.CRT\$/i) {
- $v.=" rdata align=8";
+ $qualifiers = "rdata align=8";
}
+ $v = nasm_section($$line, $qualifiers);
} else {
$v="$current_segment\tENDS\n" if ($current_segment);
$v.="$$line\tSEGMENT";