x86_64-xlate.pl: implement indirect jump/calls, support for Win64 SEH.
This commit is contained in:
parent
5b331ab77a
commit
9b634c9b37
@ -20,7 +20,6 @@
|
|||||||
# Currently recognized limitations:
|
# Currently recognized limitations:
|
||||||
#
|
#
|
||||||
# - can't use multiple ops per line;
|
# - can't use multiple ops per line;
|
||||||
# - indirect calls and jumps are not supported;
|
|
||||||
#
|
#
|
||||||
# Dual-ABI styling rules.
|
# Dual-ABI styling rules.
|
||||||
#
|
#
|
||||||
@ -68,20 +67,23 @@ my $output = shift;
|
|||||||
my $win64=1 if ($output =~ /\.asm/);
|
my $win64=1 if ($output =~ /\.asm/);
|
||||||
|
|
||||||
my $masmref=8 + 50727*2**-32; # 8.00.50727 shipped with VS2005
|
my $masmref=8 + 50727*2**-32; # 8.00.50727 shipped with VS2005
|
||||||
my $masm=$masmref;
|
my $masm=0;
|
||||||
my $PTR=" PTR";
|
my $PTR=" PTR";
|
||||||
|
|
||||||
|
my $nasmref=2.03;
|
||||||
my $nasm=0;
|
my $nasm=0;
|
||||||
|
|
||||||
if ($win64)
|
if ($win64)
|
||||||
{ if ($ENV{ASM} =~ m/nasm/)
|
{ if ($ENV{ASM} =~ m/nasm/ && `nasm -v` =~ m/version ([0-9]+)\.([0-9]+)/i)
|
||||||
{ $nasm = 1; $PTR=""; }
|
{ $nasm = $1 + $2*0.01; $PTR=""; }
|
||||||
elsif (`ml64 2>&1` =~ m/Version ([0-9]+)\.([0-9]+)(\.([0-9]+))?/)
|
elsif (`ml64 2>&1` =~ m/Version ([0-9]+)\.([0-9]+)(\.([0-9]+))?/)
|
||||||
{ $masm = $1 + $2*2**-16 + $4*2**-32; }
|
{ $masm = $1 + $2*2**-16 + $4*2**-32; }
|
||||||
|
die "no assembler found on %PATH" if (!($nasm || $masm));
|
||||||
}
|
}
|
||||||
|
|
||||||
my $current_segment;
|
my $current_segment;
|
||||||
my $current_function;
|
my $current_function;
|
||||||
|
my %globals;
|
||||||
|
|
||||||
{ package opcode; # pick up opcodes
|
{ package opcode; # pick up opcodes
|
||||||
sub re {
|
sub re {
|
||||||
@ -98,7 +100,7 @@ my $current_function;
|
|||||||
if ($self->{op} =~ /^(movz)b.*/) { # movz is pain...
|
if ($self->{op} =~ /^(movz)b.*/) { # movz is pain...
|
||||||
$self->{op} = $1;
|
$self->{op} = $1;
|
||||||
$self->{sz} = "b";
|
$self->{sz} = "b";
|
||||||
} elsif ($self->{op} =~ /call/) {
|
} elsif ($self->{op} =~ /call|jmp/) {
|
||||||
$self->{sz} = ""
|
$self->{sz} = ""
|
||||||
} elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) {
|
} elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) {
|
||||||
$self->{op} = $1;
|
$self->{op} = $1;
|
||||||
@ -134,8 +136,6 @@ my $current_function;
|
|||||||
"mov rsi,QWORD${PTR}[16+rsp]\n\t";
|
"mov rsi,QWORD${PTR}[16+rsp]\n\t";
|
||||||
}
|
}
|
||||||
$self->{op} .= "DB\t0F3h,0C3h\t\t;repret";
|
$self->{op} .= "DB\t0F3h,0C3h\t\t;repret";
|
||||||
} elsif ($self->{op} =~ /^j/ && $nasm) {
|
|
||||||
$self->{op} .= " NEAR";
|
|
||||||
}
|
}
|
||||||
$self->{op};
|
$self->{op};
|
||||||
}
|
}
|
||||||
@ -176,9 +176,11 @@ my $current_function;
|
|||||||
local *line = shift;
|
local *line = shift;
|
||||||
undef $ret;
|
undef $ret;
|
||||||
|
|
||||||
if ($line =~ /^([^\(,]*)\(([%\w,]+)\)/) {
|
# optional * ---vvv--- appears in indirect jmp/call
|
||||||
$self->{label} = $1;
|
if ($line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) {
|
||||||
($self->{base},$self->{index},$self->{scale})=split(/,/,$2);
|
$self->{asterisk} = $1;
|
||||||
|
$self->{label} = $2;
|
||||||
|
($self->{base},$self->{index},$self->{scale})=split(/,/,$3);
|
||||||
$self->{scale} = 1 if (!defined($self->{scale}));
|
$self->{scale} = 1 if (!defined($self->{scale}));
|
||||||
$ret = $self;
|
$ret = $self;
|
||||||
$line = substr($line,@+[0]); $line =~ s/^\s+//;
|
$line = substr($line,@+[0]); $line =~ s/^\s+//;
|
||||||
@ -206,11 +208,11 @@ my $current_function;
|
|||||||
$self->{label} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg;
|
$self->{label} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg;
|
||||||
|
|
||||||
if (defined($self->{index})) {
|
if (defined($self->{index})) {
|
||||||
sprintf "%s(%%%s,%%%s,%d)",
|
sprintf "%s%s(%%%s,%%%s,%d)",$self->{asterisk},
|
||||||
$self->{label},$self->{base},
|
$self->{label},$self->{base},
|
||||||
$self->{index},$self->{scale};
|
$self->{index},$self->{scale};
|
||||||
} else {
|
} else {
|
||||||
sprintf "%s(%%%s)", $self->{label},$self->{base};
|
sprintf "%s%s(%%%s)", $self->{asterisk},$self->{label},$self->{base};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
%szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", l=>"DWORD$PTR", q=>"QWORD$PTR" );
|
%szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", l=>"DWORD$PTR", q=>"QWORD$PTR" );
|
||||||
@ -218,6 +220,7 @@ my $current_function;
|
|||||||
$self->{label} =~ s/\./\$/g;
|
$self->{label} =~ s/\./\$/g;
|
||||||
$self->{label} =~ s/0x([0-9a-f]+)/0$1h/ig;
|
$self->{label} =~ s/0x([0-9a-f]+)/0$1h/ig;
|
||||||
$self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/);
|
$self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/);
|
||||||
|
$sz="q" if ($self->{asterisk});
|
||||||
|
|
||||||
if (defined($self->{index})) {
|
if (defined($self->{index})) {
|
||||||
sprintf "%s[%s%s*%d+%s]",$szmap{$sz},
|
sprintf "%s[%s%s*%d+%s]",$szmap{$sz},
|
||||||
@ -241,9 +244,11 @@ my $current_function;
|
|||||||
local *line = shift;
|
local *line = shift;
|
||||||
undef $ret;
|
undef $ret;
|
||||||
|
|
||||||
if ($line =~ /^%(\w+)/) {
|
# optional * ---vvv--- appears in indirect jmp/call
|
||||||
|
if ($line =~ /^(\*?)%(\w+)/) {
|
||||||
bless $self,$class;
|
bless $self,$class;
|
||||||
$self->{value} = $1;
|
$self->{asterisk} = $1;
|
||||||
|
$self->{value} = $2;
|
||||||
$ret = $self;
|
$ret = $self;
|
||||||
$line = substr($line,@+[0]); $line =~ s/^\s+//;
|
$line = substr($line,@+[0]); $line =~ s/^\s+//;
|
||||||
}
|
}
|
||||||
@ -266,7 +271,8 @@ my $current_function;
|
|||||||
}
|
}
|
||||||
sub out {
|
sub out {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
sprintf $win64?"%s":"%%%s",$self->{value};
|
if (!$win64) { sprintf "%s%%%s",$self->{asterisk},$self->{value}; }
|
||||||
|
else { $self->{value}; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ package label; # pick up labels, which end with :
|
{ package label; # pick up labels, which end with :
|
||||||
@ -290,11 +296,14 @@ my $current_function;
|
|||||||
if (!$win64) {
|
if (!$win64) {
|
||||||
$self->{value};
|
$self->{value};
|
||||||
} elsif ($self->{value} ne "$current_function->{name}:") {
|
} elsif ($self->{value} ne "$current_function->{name}:") {
|
||||||
|
$self->{value} .= ":" if ($masm && $ret!~m/^\$/);
|
||||||
$self->{value};
|
$self->{value};
|
||||||
} elsif ($current_function->{abi} eq "svr4") {
|
} elsif ($current_function->{abi} eq "svr4") {
|
||||||
my $func = "$current_function->{name}".($nasm?":":"\tPROC")."\n".
|
my $func = "$current_function->{name}" .
|
||||||
" mov QWORD${PTR}[8+rsp],rdi\t;WIN64 prologue\n".
|
($nasm ? ":" : "\tPROC $current_function->{scope}") .
|
||||||
" mov QWORD${PTR}[16+rsp],rsi\n";
|
"\n";
|
||||||
|
$func .= " mov QWORD${PTR}[8+rsp],rdi\t;WIN64 prologue\n";
|
||||||
|
$func .= " mov QWORD${PTR}[16+rsp],rsi\n";
|
||||||
my $narg = $current_function->{narg};
|
my $narg = $current_function->{narg};
|
||||||
$narg=6 if (!defined($narg));
|
$narg=6 if (!defined($narg));
|
||||||
$func .= " mov rdi,rcx\n" if ($narg>0);
|
$func .= " mov rdi,rcx\n" if ($narg>0);
|
||||||
@ -305,7 +314,8 @@ my $current_function;
|
|||||||
$func .= " mov r9,QWORD${PTR}[48+rsp]\n" if ($narg>5);
|
$func .= " mov r9,QWORD${PTR}[48+rsp]\n" if ($narg>5);
|
||||||
$func .= "\n";
|
$func .= "\n";
|
||||||
} else {
|
} else {
|
||||||
"$current_function->{name}".($nasm?":":"\tPROC");
|
"$current_function->{name}".
|
||||||
|
($nasm ? ":" : "\tPROC $current_function->{scope}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,7 +336,11 @@ my $current_function;
|
|||||||
}
|
}
|
||||||
sub out {
|
sub out {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->{value};
|
if ($nasm && opcode->mnemonic()=~m/^j/) {
|
||||||
|
"NEAR ".$self->{value};
|
||||||
|
} else {
|
||||||
|
$self->{value};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ package directive; # pick up directives, which start with .
|
{ package directive; # pick up directives, which start with .
|
||||||
@ -368,16 +382,12 @@ my $current_function;
|
|||||||
undef $self->{value};
|
undef $self->{value};
|
||||||
$line = substr($line,@+[0]); $line =~ s/^\s+//;
|
$line = substr($line,@+[0]); $line =~ s/^\s+//;
|
||||||
SWITCH: for ($dir) {
|
SWITCH: for ($dir) {
|
||||||
/\.(text)/
|
/\.text/ && do { my $v=undef;
|
||||||
&& do { my $v=undef;
|
|
||||||
if ($nasm) {
|
if ($nasm) {
|
||||||
$v ="section .$1 code align=64\n";
|
$v="section .text code align=64\n";
|
||||||
$v.="default rel\n";
|
|
||||||
$v.="%define PUBLIC global";
|
|
||||||
} else {
|
} else {
|
||||||
$v="$current_segment\tENDS\n" if ($current_segment);
|
$v="$current_segment\tENDS\n" if ($current_segment);
|
||||||
$current_segment = "_$1\$";
|
$current_segment = ".text\$";
|
||||||
$current_segment =~ tr/[a-z]/[A-Z]/;
|
|
||||||
$v.="$current_segment\tSEGMENT ";
|
$v.="$current_segment\tSEGMENT ";
|
||||||
$v.=$masm>=$masmref ? "ALIGN(64)" : "PAGE";
|
$v.=$masm>=$masmref ? "ALIGN(64)" : "PAGE";
|
||||||
$v.=" 'CODE'";
|
$v.=" 'CODE'";
|
||||||
@ -385,20 +395,55 @@ my $current_function;
|
|||||||
$self->{value} = $v;
|
$self->{value} = $v;
|
||||||
last;
|
last;
|
||||||
};
|
};
|
||||||
/\.extern/ && do { $self->{value} = "EXTERN\t".$line;
|
/\.data/ && do { my $v=undef;
|
||||||
$self->{value} .= ":BYTE" if (!$nasm);
|
if ($nasm) {
|
||||||
|
$v="section .data data align=8\n";
|
||||||
|
} else {
|
||||||
|
$v="$current_segment\tENDS\n" if ($current_segment);
|
||||||
|
$current_segment = "_DATA";
|
||||||
|
$v.="$current_segment\tSEGMENT";
|
||||||
|
}
|
||||||
|
$self->{value} = $v;
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
/\.section/ && do { my $v=undef;
|
||||||
|
if ($nasm) {
|
||||||
|
$v="section $line";
|
||||||
|
if ($line=~/\.([px])data/) {
|
||||||
|
$v.=" rdata align=";
|
||||||
|
$v.=$1 eq "p"? 4 : 8;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$v="$current_segment\tENDS\n" if ($current_segment);
|
||||||
|
$v.="$line\tSEGMENT";
|
||||||
|
if ($line=~/\.([px])data/) {
|
||||||
|
$v.=" READONLY";
|
||||||
|
$v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$current_segment = $line;
|
||||||
|
$self->{value} = $v;
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
/\.extern/ && do { $self->{value} = "EXTERN\t".$line;
|
||||||
|
$self->{value} .= ":NEAR" if ($masm);
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
/\.globl/ && do { $self->{value} = "PUBLIC\t".$line;
|
||||||
|
$globals{$line} = $line;
|
||||||
last;
|
last;
|
||||||
};
|
};
|
||||||
/\.globl/ && do { $self->{value} = "PUBLIC\t".$line; last; };
|
|
||||||
/\.type/ && do { ($sym,$type,$narg) = split(',',$line);
|
/\.type/ && do { ($sym,$type,$narg) = split(',',$line);
|
||||||
if ($type eq "\@function") {
|
if ($type eq "\@function") {
|
||||||
undef $current_function;
|
undef $current_function;
|
||||||
$current_function->{name} = $sym;
|
$current_function->{name} = $sym;
|
||||||
$current_function->{abi} = "svr4";
|
$current_function->{abi} = "svr4";
|
||||||
$current_function->{narg} = $narg;
|
$current_function->{narg} = $narg;
|
||||||
|
$current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
|
||||||
} elsif ($type eq "\@abi-omnipotent") {
|
} elsif ($type eq "\@abi-omnipotent") {
|
||||||
undef $current_function;
|
undef $current_function;
|
||||||
$current_function->{name} = $sym;
|
$current_function->{name} = $sym;
|
||||||
|
$current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
|
||||||
}
|
}
|
||||||
last;
|
last;
|
||||||
};
|
};
|
||||||
@ -414,8 +459,10 @@ my $current_function;
|
|||||||
my $sz = substr($1,0,1);
|
my $sz = substr($1,0,1);
|
||||||
my $last = pop(@arr);
|
my $last = pop(@arr);
|
||||||
my $conv = sub { my $var=shift;
|
my $conv = sub { my $var=shift;
|
||||||
if ($var=~s/0x([0-9a-f]+)/0$1h/i) { $var; }
|
$var=~s/0x([0-9a-f]+)/0$1h/ig;
|
||||||
else { sprintf"0%Xh",$var; }
|
if ($current_segment=~/.[px]data/)
|
||||||
|
{ $var=~s/\b([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; }
|
||||||
|
$var;
|
||||||
};
|
};
|
||||||
|
|
||||||
$sz =~ tr/bvlq/BWDQ/;
|
$sz =~ tr/bvlq/BWDQ/;
|
||||||
@ -452,6 +499,16 @@ my $current_function;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($nasm) {
|
||||||
|
print <<___;
|
||||||
|
default rel
|
||||||
|
%define PUBLIC global
|
||||||
|
___
|
||||||
|
} elsif ($masm) {
|
||||||
|
print <<___;
|
||||||
|
OPTION DOTNAME
|
||||||
|
___
|
||||||
|
}
|
||||||
while($line=<>) {
|
while($line=<>) {
|
||||||
|
|
||||||
chomp($line);
|
chomp($line);
|
||||||
@ -508,7 +565,7 @@ while($line=<>) {
|
|||||||
print $line,"\n";
|
print $line,"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
print "\n$current_segment\tENDS\nEND\n" if ($current_segment);
|
print "\n$current_segment\tENDS\nEND\n" if ($current_segment && $masm);
|
||||||
|
|
||||||
close STDOUT;
|
close STDOUT;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user