mirror of
https://github.com/openssl/openssl.git
synced 2024-12-09 05:51:54 +08:00
96f0b8addd
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)
287 lines
6.5 KiB
Perl
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;
|