openssl/crypto/perlasm/x86gas.pl
H.J. Lu 96f0b8addd x86: Always generate .note.gnu.property section for ELF outputs
We should always generate .note.gnu.property section in x86 assembly
codes for ELF outputs to mark Intel CET support since all input files
must be marked with Intel CET support in order for linker to mark output
with Intel CET support.

Verified with

$ CC="gcc -Wl,-z,cet-report=error" ./Configure shared linux-x86 -fcf-protection
$ make
$ make test

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11044)
2020-02-08 06:24:44 -08:00

287 lines
6.5 KiB
Perl

#! /usr/bin/env perl
# Copyright 2007-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
package x86gas;
*out=\@::out;
$::lbdecor=$::aout?"L":".L"; # local label decoration
$nmdecor=($::aout or $::coff)?"_":""; # external name decoration
$initseg="";
$align=16;
$align=log($align)/log(2) if ($::aout);
$com_start="#" if ($::aout or $::coff);
sub opsize()
{ my $reg=shift;
if ($reg =~ m/^%e/o) { "l"; }
elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; }
elsif ($reg =~ m/^%[yxm]/o) { undef; }
else { "w"; }
}
# swap arguments;
# expand opcode with size suffix;
# prefix numeric constants with $;
sub ::generic
{ my($opcode,@arg)=@_;
my($suffix,$dst,$src);
@arg=reverse(@arg);
for (@arg)
{ s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o; # gp registers
s/^([xy]?mm[0-7])$/%$1/o; # xmm/mmx registers
s/^(\-?[0-9]+)$/\$$1/o; # constants
s/^(\-?0x[0-9a-f]+)$/\$$1/o; # constants
}
$dst = $arg[$#arg] if ($#arg>=0);
$src = $arg[$#arg-1] if ($#arg>=1);
if ($dst =~ m/^%/o) { $suffix=&opsize($dst); }
elsif ($src =~ m/^%/o) { $suffix=&opsize($src); }
else { $suffix="l"; }
undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o);
if ($#_==0) { &::emit($opcode); }
elsif ($#_==1 && $opcode =~ m/^(call|clflush|j|loop|set)/o)
{ &::emit($opcode,@arg); }
else { &::emit($opcode.$suffix,@arg);}
1;
}
#
# opcodes not covered by ::generic above, mostly inconsistent namings...
#
sub ::movzx { &::movzb(@_); }
sub ::pushfd { &::pushfl; }
sub ::popfd { &::popfl; }
sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); }
sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); }
sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
sub ::call_ptr { &::generic("call","*$_[0]"); }
sub ::jmp_ptr { &::generic("jmp","*$_[0]"); }
*::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386);
sub ::DWP
{ my($addr,$reg1,$reg2,$idx)=@_;
my $ret="";
if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
$addr =~ s/^\s+//;
# prepend global references with optional underscore
$addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
$reg1 = "%$reg1" if ($reg1);
$reg2 = "%$reg2" if ($reg2);
$ret .= $addr if (($addr ne "") && ($addr ne 0));
if ($reg2)
{ $idx!= 0 or $idx=1;
$ret .= "($reg1,$reg2,$idx)";
}
elsif ($reg1)
{ $ret .= "($reg1)"; }
$ret;
}
sub ::QWP { &::DWP(@_); }
sub ::BP { &::DWP(@_); }
sub ::WP { &::DWP(@_); }
sub ::BC { @_; }
sub ::DWC { @_; }
sub ::file
{ push(@out,".text\n"); }
sub ::function_begin_B
{ my $func=shift;
my $global=($func !~ /^_/);
my $begin="${::lbdecor}_${func}_begin";
&::LABEL($func,$global?"$begin":"$nmdecor$func");
$func=$nmdecor.$func;
push(@out,".globl\t$func\n") if ($global);
if ($::coff)
{ push(@out,".def\t$func;\t.scl\t".(3-$global).";\t.type\t32;\t.endef\n"); }
elsif (($::aout and !$::pic) or $::macosx)
{ }
else
{ push(@out,".type $func,\@function\n"); }
push(@out,".align\t$align\n");
push(@out,"$func:\n");
push(@out,"$begin:\n") if ($global);
&::endbranch();
$::stack=4;
}
sub ::function_end_B
{ my $func=shift;
push(@out,".size\t$nmdecor$func,.-".&::LABEL($func)."\n") if ($::elf);
$::stack=0;
&::wipe_labels();
}
sub ::comment
{
if (!defined($com_start) or $::elf)
{ # Regarding $::elf above...
# GNU and SVR4 as'es use different comment delimiters,
push(@out,"\n"); # so we just skip ELF comments...
return;
}
foreach (@_)
{
if (/^\s*$/)
{ push(@out,"\n"); }
else
{ push(@out,"\t$com_start $_ $com_end\n"); }
}
}
sub ::external_label
{ foreach(@_) { &::LABEL($_,$nmdecor.$_); } }
sub ::public_label
{ push(@out,".globl\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); }
sub ::file_end
{ if ($::macosx)
{ if (%non_lazy_ptr)
{ push(@out,".section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
foreach $i (keys %non_lazy_ptr)
{ push(@out,"$non_lazy_ptr{$i}:\n.indirect_symbol\t$i\n.long\t0\n"); }
}
}
if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) {
my $tmp=".comm\t${nmdecor}OPENSSL_ia32cap_P,16";
if ($::macosx) { push (@out,"$tmp,2\n"); }
elsif ($::elf) { push (@out,"$tmp,4\n"); }
else { push (@out,"$tmp\n"); }
}
push(@out,$initseg) if ($initseg);
if ($::elf) {
push(@out,"
.section \".note.gnu.property\", \"a\"
.p2align 2
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.asciz \"GNU\"
1:
.p2align 2
.long 0xc0000002
.long 3f - 2f
2:
.long 3
3:
.p2align 2
4:
");
}
}
sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); }
sub ::data_short{ push(@out,".value\t".join(',',@_)."\n"); }
sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); }
sub ::align
{ my $val=$_[0];
if ($::aout)
{ $val=int(log($val)/log(2));
$val.=",0x90";
}
push(@out,".align\t$val\n");
}
sub ::picmeup
{ my($dst,$sym,$base,$reflabel)=@_;
if (($::pic && ($::elf || $::aout)) || $::macosx)
{ if (!defined($base))
{ &::call(&::label("PIC_me_up"));
&::set_label("PIC_me_up");
&::blindpop($dst);
$base=$dst;
$reflabel=&::label("PIC_me_up");
}
if ($::macosx)
{ my $indirect=&::static_label("$nmdecor$sym\$non_lazy_ptr");
&::mov($dst,&::DWP("$indirect-$reflabel",$base));
$non_lazy_ptr{"$nmdecor$sym"}=$indirect;
}
elsif ($sym eq "OPENSSL_ia32cap_P" && $::elf>0)
{ &::lea($dst,&::DWP("$sym-$reflabel",$base)); }
else
{ &::lea($dst,&::DWP("_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
$base));
&::mov($dst,&::DWP("$sym\@GOT",$dst));
}
}
else
{ &::lea($dst,&::DWP($sym)); }
}
sub ::initseg
{ my $f=$nmdecor.shift;
if ($::android)
{ $initseg.=<<___;
.section .init_array
.align 4
.long $f
___
}
elsif ($::elf)
{ $initseg.=<<___;
.section .init
call $f
___
}
elsif ($::coff)
{ $initseg.=<<___; # applies to both Cygwin and Mingw
.section .ctors
.long $f
___
}
elsif ($::macosx)
{ $initseg.=<<___;
.mod_init_func
.align 2
.long $f
___
}
elsif ($::aout)
{ my $ctor="${nmdecor}_GLOBAL_\$I\$$f";
$initseg.=".text\n";
$initseg.=".type $ctor,\@function\n" if ($::pic);
$initseg.=<<___; # OpenBSD way...
.globl $ctor
.align 2
$ctor:
jmp $f
___
}
}
sub ::dataseg
{ push(@out,".data\n"); }
*::hidden = sub { push(@out,".hidden\t$nmdecor$_[0]\n"); } if ($::elf);
1;