1*2139Sjp161948#!/usr/bin/env perl 2*2139Sjp161948 3*2139Sjp161948# Ascetic x86_64 AT&T to MASM assembler translator by <appro>. 4*2139Sjp161948# 5*2139Sjp161948# Why AT&T to MASM and not vice versa? Several reasons. Because AT&T 6*2139Sjp161948# format is way easier to parse. Because it's simpler to "gear" from 7*2139Sjp161948# Unix ABI to Windows one [see cross-reference "card" at the end of 8*2139Sjp161948# file]. Because Linux targets were available first... 9*2139Sjp161948# 10*2139Sjp161948# In addition the script also "distills" code suitable for GNU 11*2139Sjp161948# assembler, so that it can be compiled with more rigid assemblers, 12*2139Sjp161948# such as Solaris /usr/ccs/bin/as. 13*2139Sjp161948# 14*2139Sjp161948# This translator is not designed to convert *arbitrary* assembler 15*2139Sjp161948# code from AT&T format to MASM one. It's designed to convert just 16*2139Sjp161948# enough to provide for dual-ABI OpenSSL modules development... 17*2139Sjp161948# There *are* limitations and you might have to modify your assembler 18*2139Sjp161948# code or this script to achieve the desired result... 19*2139Sjp161948# 20*2139Sjp161948# Currently recognized limitations: 21*2139Sjp161948# 22*2139Sjp161948# - can't use multiple ops per line; 23*2139Sjp161948# - indirect calls and jumps are not supported; 24*2139Sjp161948# 25*2139Sjp161948# Dual-ABI styling rules. 26*2139Sjp161948# 27*2139Sjp161948# 1. Adhere to Unix register and stack layout [see the end for 28*2139Sjp161948# explanation]. 29*2139Sjp161948# 2. Forget about "red zone," stick to more traditional blended 30*2139Sjp161948# stack frame allocation. If volatile storage is actually required 31*2139Sjp161948# that is. If not, just leave the stack as is. 32*2139Sjp161948# 3. Functions tagged with ".type name,@function" get crafted with 33*2139Sjp161948# unified Win64 prologue and epilogue automatically. If you want 34*2139Sjp161948# to take care of ABI differences yourself, tag functions as 35*2139Sjp161948# ".type name,@abi-omnipotent" instead. 36*2139Sjp161948# 4. To optimize the Win64 prologue you can specify number of input 37*2139Sjp161948# arguments as ".type name,@function,N." Keep in mind that if N is 38*2139Sjp161948# larger than 6, then you *have to* write "abi-omnipotent" code, 39*2139Sjp161948# because >6 cases can't be addressed with unified prologue. 40*2139Sjp161948# 5. Name local labels as .L*, do *not* use dynamic labels such as 1: 41*2139Sjp161948# (sorry about latter). 42*2139Sjp161948# 6. Don't use [or hand-code with .byte] "rep ret." "ret" mnemonic is 43*2139Sjp161948# required to identify the spots, where to inject Win64 epilogue! 44*2139Sjp161948# But on the pros, it's then prefixed with rep automatically:-) 45*2139Sjp161948# 7. Due to MASM limitations [and certain general counter-intuitivity 46*2139Sjp161948# of ip-relative addressing] generation of position-independent 47*2139Sjp161948# code is assisted by synthetic directive, .picmeup, which puts 48*2139Sjp161948# address of the *next* instruction into target register. 49*2139Sjp161948# 50*2139Sjp161948# Example 1: 51*2139Sjp161948# .picmeup %rax 52*2139Sjp161948# lea .Label-.(%rax),%rax 53*2139Sjp161948# Example 2: 54*2139Sjp161948# .picmeup %rcx 55*2139Sjp161948# .Lpic_point: 56*2139Sjp161948# ... 57*2139Sjp161948# lea .Label-.Lpic_point(%rcx),%rbp 58*2139Sjp161948 59*2139Sjp161948my $output = shift; 60*2139Sjp161948open STDOUT,">$output" || die "can't open $output: $!"; 61*2139Sjp161948 62*2139Sjp161948my $masm=1 if ($output =~ /\.asm/); 63*2139Sjp161948 64*2139Sjp161948my $current_segment; 65*2139Sjp161948my $current_function; 66*2139Sjp161948 67*2139Sjp161948{ package opcode; # pick up opcodes 68*2139Sjp161948 sub re { 69*2139Sjp161948 my $self = shift; # single instance in enough... 70*2139Sjp161948 local *line = shift; 71*2139Sjp161948 undef $ret; 72*2139Sjp161948 73*2139Sjp161948 if ($line =~ /^([a-z]+)/i) { 74*2139Sjp161948 $self->{op} = $1; 75*2139Sjp161948 $ret = $self; 76*2139Sjp161948 $line = substr($line,@+[0]); $line =~ s/^\s+//; 77*2139Sjp161948 78*2139Sjp161948 undef $self->{sz}; 79*2139Sjp161948 if ($self->{op} =~ /(movz)b.*/) { # movz is pain... 80*2139Sjp161948 $self->{op} = $1; 81*2139Sjp161948 $self->{sz} = "b"; 82*2139Sjp161948 } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])/) { 83*2139Sjp161948 $self->{op} = $1; 84*2139Sjp161948 $self->{sz} = $2; 85*2139Sjp161948 } 86*2139Sjp161948 } 87*2139Sjp161948 $ret; 88*2139Sjp161948 } 89*2139Sjp161948 sub size { 90*2139Sjp161948 my $self = shift; 91*2139Sjp161948 my $sz = shift; 92*2139Sjp161948 $self->{sz} = $sz if (defined($sz) && !defined($self->{sz})); 93*2139Sjp161948 $self->{sz}; 94*2139Sjp161948 } 95*2139Sjp161948 sub out { 96*2139Sjp161948 my $self = shift; 97*2139Sjp161948 if (!$masm) { 98*2139Sjp161948 if ($self->{op} eq "movz") { # movz in pain... 99*2139Sjp161948 sprintf "%s%s%s",$self->{op},$self->{sz},shift; 100*2139Sjp161948 } elsif ($self->{op} eq "ret") { 101*2139Sjp161948 ".byte 0xf3,0xc3"; 102*2139Sjp161948 } else { 103*2139Sjp161948 "$self->{op}$self->{sz}"; 104*2139Sjp161948 } 105*2139Sjp161948 } else { 106*2139Sjp161948 $self->{op} =~ s/movz/movzx/; 107*2139Sjp161948 if ($self->{op} eq "ret") { 108*2139Sjp161948 $self->{op} = ""; 109*2139Sjp161948 if ($current_function->{abi} eq "svr4") { 110*2139Sjp161948 $self->{op} = "mov rdi,QWORD PTR 8[rsp]\t;WIN64 epilogue\n\t". 111*2139Sjp161948 "mov rsi,QWORD PTR 16[rsp]\n\t"; 112*2139Sjp161948 } 113*2139Sjp161948 $self->{op} .= "DB\t0F3h,0C3h\t\t;repret"; 114*2139Sjp161948 } 115*2139Sjp161948 $self->{op}; 116*2139Sjp161948 } 117*2139Sjp161948 } 118*2139Sjp161948} 119*2139Sjp161948{ package const; # pick up constants, which start with $ 120*2139Sjp161948 sub re { 121*2139Sjp161948 my $self = shift; # single instance in enough... 122*2139Sjp161948 local *line = shift; 123*2139Sjp161948 undef $ret; 124*2139Sjp161948 125*2139Sjp161948 if ($line =~ /^\$([^,]+)/) { 126*2139Sjp161948 $self->{value} = $1; 127*2139Sjp161948 $ret = $self; 128*2139Sjp161948 $line = substr($line,@+[0]); $line =~ s/^\s+//; 129*2139Sjp161948 } 130*2139Sjp161948 $ret; 131*2139Sjp161948 } 132*2139Sjp161948 sub out { 133*2139Sjp161948 my $self = shift; 134*2139Sjp161948 135*2139Sjp161948 if (!$masm) { 136*2139Sjp161948 sprintf "\$%s",$self->{value}; 137*2139Sjp161948 } else { 138*2139Sjp161948 $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig; 139*2139Sjp161948 sprintf "%s",$self->{value}; 140*2139Sjp161948 } 141*2139Sjp161948 } 142*2139Sjp161948} 143*2139Sjp161948{ package ea; # pick up effective addresses: expr(%reg,%reg,scale) 144*2139Sjp161948 sub re { 145*2139Sjp161948 my $self = shift; # single instance in enough... 146*2139Sjp161948 local *line = shift; 147*2139Sjp161948 undef $ret; 148*2139Sjp161948 149*2139Sjp161948 if ($line =~ /^([^\(,]*)\(([%\w,]+)\)/) { 150*2139Sjp161948 $self->{label} = $1; 151*2139Sjp161948 ($self->{base},$self->{index},$self->{scale})=split(/,/,$2); 152*2139Sjp161948 $self->{scale} = 1 if (!defined($self->{scale})); 153*2139Sjp161948 $ret = $self; 154*2139Sjp161948 $line = substr($line,@+[0]); $line =~ s/^\s+//; 155*2139Sjp161948 156*2139Sjp161948 $self->{base} =~ s/^%//; 157*2139Sjp161948 $self->{index} =~ s/^%// if (defined($self->{index})); 158*2139Sjp161948 } 159*2139Sjp161948 $ret; 160*2139Sjp161948 } 161*2139Sjp161948 sub size {} 162*2139Sjp161948 sub out { 163*2139Sjp161948 my $self = shift; 164*2139Sjp161948 my $sz = shift; 165*2139Sjp161948 166*2139Sjp161948 if (!$masm) { 167*2139Sjp161948 # elder GNU assembler insists on 64-bit EAs:-( 168*2139Sjp161948 # on pros side, this results in more compact code:-) 169*2139Sjp161948 $self->{index} =~ s/^[er](.?[0-9xp])[d]?$/r\1/; 170*2139Sjp161948 $self->{base} =~ s/^[er](.?[0-9xp])[d]?$/r\1/; 171*2139Sjp161948 # Solaris /usr/ccs/bin/as can't handle multiplications 172*2139Sjp161948 # in $self->{label} 173*2139Sjp161948 $self->{label} =~ s/(?<![0-9a-f])(0[x0-9a-f]+)/oct($1)/eg; 174*2139Sjp161948 $self->{label} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg; 175*2139Sjp161948 176*2139Sjp161948 if (defined($self->{index})) { 177*2139Sjp161948 sprintf "%s(%%%s,%%%s,%d)", 178*2139Sjp161948 $self->{label},$self->{base}, 179*2139Sjp161948 $self->{index},$self->{scale}; 180*2139Sjp161948 } else { 181*2139Sjp161948 sprintf "%s(%%%s)", $self->{label},$self->{base}; 182*2139Sjp161948 } 183*2139Sjp161948 } else { 184*2139Sjp161948 %szmap = ( b=>"BYTE", w=>"WORD", l=>"DWORD", q=>"QWORD" ); 185*2139Sjp161948 186*2139Sjp161948 $self->{label} =~ s/\./\$/g; 187*2139Sjp161948 $self->{label} =~ s/0x([0-9a-f]+)/0$1h/ig; 188*2139Sjp161948 $self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/); 189*2139Sjp161948 190*2139Sjp161948 if (defined($self->{index})) { 191*2139Sjp161948 sprintf "%s PTR %s[%s*%d+%s]",$szmap{$sz}, 192*2139Sjp161948 $self->{label}, 193*2139Sjp161948 $self->{index},$self->{scale}, 194*2139Sjp161948 $self->{base}; 195*2139Sjp161948 } else { 196*2139Sjp161948 sprintf "%s PTR %s[%s]",$szmap{$sz}, 197*2139Sjp161948 $self->{label},$self->{base}; 198*2139Sjp161948 } 199*2139Sjp161948 } 200*2139Sjp161948 } 201*2139Sjp161948} 202*2139Sjp161948{ package register; # pick up registers, which start with %. 203*2139Sjp161948 sub re { 204*2139Sjp161948 my $class = shift; # muliple instances... 205*2139Sjp161948 my $self = {}; 206*2139Sjp161948 local *line = shift; 207*2139Sjp161948 undef $ret; 208*2139Sjp161948 209*2139Sjp161948 if ($line =~ /^%(\w+)/) { 210*2139Sjp161948 bless $self,$class; 211*2139Sjp161948 $self->{value} = $1; 212*2139Sjp161948 $ret = $self; 213*2139Sjp161948 $line = substr($line,@+[0]); $line =~ s/^\s+//; 214*2139Sjp161948 } 215*2139Sjp161948 $ret; 216*2139Sjp161948 } 217*2139Sjp161948 sub size { 218*2139Sjp161948 my $self = shift; 219*2139Sjp161948 undef $ret; 220*2139Sjp161948 221*2139Sjp161948 if ($self->{value} =~ /^r[\d]+b$/i) { $ret="b"; } 222*2139Sjp161948 elsif ($self->{value} =~ /^r[\d]+w$/i) { $ret="w"; } 223*2139Sjp161948 elsif ($self->{value} =~ /^r[\d]+d$/i) { $ret="l"; } 224*2139Sjp161948 elsif ($self->{value} =~ /^r[\w]+$/i) { $ret="q"; } 225*2139Sjp161948 elsif ($self->{value} =~ /^[a-d][hl]$/i){ $ret="b"; } 226*2139Sjp161948 elsif ($self->{value} =~ /^[\w]{2}l$/i) { $ret="b"; } 227*2139Sjp161948 elsif ($self->{value} =~ /^[\w]{2}$/i) { $ret="w"; } 228*2139Sjp161948 elsif ($self->{value} =~ /^e[a-z]{2}$/i){ $ret="l"; } 229*2139Sjp161948 230*2139Sjp161948 $ret; 231*2139Sjp161948 } 232*2139Sjp161948 sub out { 233*2139Sjp161948 my $self = shift; 234*2139Sjp161948 sprintf $masm?"%s":"%%%s",$self->{value}; 235*2139Sjp161948 } 236*2139Sjp161948} 237*2139Sjp161948{ package label; # pick up labels, which end with : 238*2139Sjp161948 sub re { 239*2139Sjp161948 my $self = shift; # single instance is enough... 240*2139Sjp161948 local *line = shift; 241*2139Sjp161948 undef $ret; 242*2139Sjp161948 243*2139Sjp161948 if ($line =~ /(^[\.\w]+\:)/) { 244*2139Sjp161948 $self->{value} = $1; 245*2139Sjp161948 $ret = $self; 246*2139Sjp161948 $line = substr($line,@+[0]); $line =~ s/^\s+//; 247*2139Sjp161948 248*2139Sjp161948 $self->{value} =~ s/\.L/\$L/ if ($masm); 249*2139Sjp161948 } 250*2139Sjp161948 $ret; 251*2139Sjp161948 } 252*2139Sjp161948 sub out { 253*2139Sjp161948 my $self = shift; 254*2139Sjp161948 255*2139Sjp161948 if (!$masm) { 256*2139Sjp161948 $self->{value}; 257*2139Sjp161948 } elsif ($self->{value} ne "$current_function->{name}:") { 258*2139Sjp161948 $self->{value}; 259*2139Sjp161948 } elsif ($current_function->{abi} eq "svr4") { 260*2139Sjp161948 my $func = "$current_function->{name} PROC\n". 261*2139Sjp161948 " mov QWORD PTR 8[rsp],rdi\t;WIN64 prologue\n". 262*2139Sjp161948 " mov QWORD PTR 16[rsp],rsi\n"; 263*2139Sjp161948 my $narg = $current_function->{narg}; 264*2139Sjp161948 $narg=6 if (!defined($narg)); 265*2139Sjp161948 $func .= " mov rdi,rcx\n" if ($narg>0); 266*2139Sjp161948 $func .= " mov rsi,rdx\n" if ($narg>1); 267*2139Sjp161948 $func .= " mov rdx,r8\n" if ($narg>2); 268*2139Sjp161948 $func .= " mov rcx,r9\n" if ($narg>3); 269*2139Sjp161948 $func .= " mov r8,QWORD PTR 40[rsp]\n" if ($narg>4); 270*2139Sjp161948 $func .= " mov r9,QWORD PTR 48[rsp]\n" if ($narg>5); 271*2139Sjp161948 $func .= "\n"; 272*2139Sjp161948 } else { 273*2139Sjp161948 "$current_function->{name} PROC"; 274*2139Sjp161948 } 275*2139Sjp161948 } 276*2139Sjp161948} 277*2139Sjp161948{ package expr; # pick up expressioins 278*2139Sjp161948 sub re { 279*2139Sjp161948 my $self = shift; # single instance is enough... 280*2139Sjp161948 local *line = shift; 281*2139Sjp161948 undef $ret; 282*2139Sjp161948 283*2139Sjp161948 if ($line =~ /(^[^,]+)/) { 284*2139Sjp161948 $self->{value} = $1; 285*2139Sjp161948 $ret = $self; 286*2139Sjp161948 $line = substr($line,@+[0]); $line =~ s/^\s+//; 287*2139Sjp161948 288*2139Sjp161948 $self->{value} =~ s/\.L/\$L/g if ($masm); 289*2139Sjp161948 } 290*2139Sjp161948 $ret; 291*2139Sjp161948 } 292*2139Sjp161948 sub out { 293*2139Sjp161948 my $self = shift; 294*2139Sjp161948 $self->{value}; 295*2139Sjp161948 } 296*2139Sjp161948} 297*2139Sjp161948{ package directive; # pick up directives, which start with . 298*2139Sjp161948 sub re { 299*2139Sjp161948 my $self = shift; # single instance is enough... 300*2139Sjp161948 local *line = shift; 301*2139Sjp161948 undef $ret; 302*2139Sjp161948 my $dir; 303*2139Sjp161948 my %opcode = # lea 2f-1f(%rip),%dst; 1: nop; 2: 304*2139Sjp161948 ( "%rax"=>0x01058d48, "%rcx"=>0x010d8d48, 305*2139Sjp161948 "%rdx"=>0x01158d48, "%rbx"=>0x011d8d48, 306*2139Sjp161948 "%rsp"=>0x01258d48, "%rbp"=>0x012d8d48, 307*2139Sjp161948 "%rsi"=>0x01358d48, "%rdi"=>0x013d8d48, 308*2139Sjp161948 "%r8" =>0x01058d4c, "%r9" =>0x010d8d4c, 309*2139Sjp161948 "%r10"=>0x01158d4c, "%r11"=>0x011d8d4c, 310*2139Sjp161948 "%r12"=>0x01258d4c, "%r13"=>0x012d8d4c, 311*2139Sjp161948 "%r14"=>0x01358d4c, "%r15"=>0x013d8d4c ); 312*2139Sjp161948 313*2139Sjp161948 if ($line =~ /^\s*(\.\w+)/) { 314*2139Sjp161948 if (!$masm) { 315*2139Sjp161948 $self->{value} = $1; 316*2139Sjp161948 $line =~ s/\@abi\-omnipotent/\@function/; 317*2139Sjp161948 $line =~ s/\@function.*/\@function/; 318*2139Sjp161948 if ($line =~ /\.picmeup\s+(%r[\w]+)/i) { 319*2139Sjp161948 $self->{value} = sprintf "\t.long\t0x%x,0x90000000",$opcode{$1}; 320*2139Sjp161948 } else { 321*2139Sjp161948 $self->{value} = $line; 322*2139Sjp161948 } 323*2139Sjp161948 $line = ""; 324*2139Sjp161948 return $self; 325*2139Sjp161948 } 326*2139Sjp161948 327*2139Sjp161948 $dir = $1; 328*2139Sjp161948 $ret = $self; 329*2139Sjp161948 undef $self->{value}; 330*2139Sjp161948 $line = substr($line,@+[0]); $line =~ s/^\s+//; 331*2139Sjp161948 SWITCH: for ($dir) { 332*2139Sjp161948 /\.(text)/ 333*2139Sjp161948 && do { my $v=undef; 334*2139Sjp161948 $v="$current_segment\tENDS\n" if ($current_segment); 335*2139Sjp161948 $current_segment = "_$1\$"; 336*2139Sjp161948 $current_segment =~ tr/[a-z]/[A-Z]/; 337*2139Sjp161948 $v.="$current_segment\tSEGMENT ALIGN(64) 'CODE'"; 338*2139Sjp161948 $self->{value} = $v; 339*2139Sjp161948 last; 340*2139Sjp161948 }; 341*2139Sjp161948 /\.globl/ && do { $self->{value} = "PUBLIC\t".$line; last; }; 342*2139Sjp161948 /\.type/ && do { ($sym,$type,$narg) = split(',',$line); 343*2139Sjp161948 if ($type eq "\@function") { 344*2139Sjp161948 undef $current_function; 345*2139Sjp161948 $current_function->{name} = $sym; 346*2139Sjp161948 $current_function->{abi} = "svr4"; 347*2139Sjp161948 $current_function->{narg} = $narg; 348*2139Sjp161948 } elsif ($type eq "\@abi-omnipotent") { 349*2139Sjp161948 undef $current_function; 350*2139Sjp161948 $current_function->{name} = $sym; 351*2139Sjp161948 } 352*2139Sjp161948 last; 353*2139Sjp161948 }; 354*2139Sjp161948 /\.size/ && do { if (defined($current_function)) { 355*2139Sjp161948 $self->{value}="$current_function->{name}\tENDP"; 356*2139Sjp161948 undef $current_function; 357*2139Sjp161948 } 358*2139Sjp161948 last; 359*2139Sjp161948 }; 360*2139Sjp161948 /\.align/ && do { $self->{value} = "ALIGN\t".$line; last; }; 361*2139Sjp161948 /\.(byte|value|long|quad)/ 362*2139Sjp161948 && do { my @arr = split(',',$line); 363*2139Sjp161948 my $sz = substr($1,0,1); 364*2139Sjp161948 my $last = pop(@arr); 365*2139Sjp161948 366*2139Sjp161948 $sz =~ tr/bvlq/BWDQ/; 367*2139Sjp161948 $self->{value} = "\tD$sz\t"; 368*2139Sjp161948 for (@arr) { $self->{value} .= sprintf"0%Xh,",oct; } 369*2139Sjp161948 $self->{value} .= sprintf"0%Xh",oct($last); 370*2139Sjp161948 last; 371*2139Sjp161948 }; 372*2139Sjp161948 /\.picmeup/ && do { $self->{value} = sprintf"\tDD\t 0%Xh,090000000h",$opcode{$line}; 373*2139Sjp161948 last; 374*2139Sjp161948 }; 375*2139Sjp161948 } 376*2139Sjp161948 $line = ""; 377*2139Sjp161948 } 378*2139Sjp161948 379*2139Sjp161948 $ret; 380*2139Sjp161948 } 381*2139Sjp161948 sub out { 382*2139Sjp161948 my $self = shift; 383*2139Sjp161948 $self->{value}; 384*2139Sjp161948 } 385*2139Sjp161948} 386*2139Sjp161948 387*2139Sjp161948while($line=<>) { 388*2139Sjp161948 389*2139Sjp161948 chomp($line); 390*2139Sjp161948 391*2139Sjp161948 $line =~ s|[#!].*$||; # get rid of asm-style comments... 392*2139Sjp161948 $line =~ s|/\*.*\*/||; # ... and C-style comments... 393*2139Sjp161948 $line =~ s|^\s+||; # ... and skip white spaces in beginning 394*2139Sjp161948 395*2139Sjp161948 undef $label; 396*2139Sjp161948 undef $opcode; 397*2139Sjp161948 undef $dst; 398*2139Sjp161948 undef $src; 399*2139Sjp161948 undef $sz; 400*2139Sjp161948 401*2139Sjp161948 if ($label=label->re(\$line)) { print $label->out(); } 402*2139Sjp161948 403*2139Sjp161948 if (directive->re(\$line)) { 404*2139Sjp161948 printf "%s",directive->out(); 405*2139Sjp161948 } elsif ($opcode=opcode->re(\$line)) { ARGUMENT: { 406*2139Sjp161948 407*2139Sjp161948 if ($src=register->re(\$line)) { opcode->size($src->size()); } 408*2139Sjp161948 elsif ($src=const->re(\$line)) { } 409*2139Sjp161948 elsif ($src=ea->re(\$line)) { } 410*2139Sjp161948 elsif ($src=expr->re(\$line)) { } 411*2139Sjp161948 412*2139Sjp161948 last ARGUMENT if ($line !~ /^,/); 413*2139Sjp161948 414*2139Sjp161948 $line = substr($line,1); $line =~ s/^\s+//; 415*2139Sjp161948 416*2139Sjp161948 if ($dst=register->re(\$line)) { opcode->size($dst->size()); } 417*2139Sjp161948 elsif ($dst=const->re(\$line)) { } 418*2139Sjp161948 elsif ($dst=ea->re(\$line)) { } 419*2139Sjp161948 420*2139Sjp161948 } # ARGUMENT: 421*2139Sjp161948 422*2139Sjp161948 $sz=opcode->size(); 423*2139Sjp161948 424*2139Sjp161948 if (defined($dst)) { 425*2139Sjp161948 if (!$masm) { 426*2139Sjp161948 printf "\t%s\t%s,%s", $opcode->out($dst->size()), 427*2139Sjp161948 $src->out($sz),$dst->out($sz); 428*2139Sjp161948 } else { 429*2139Sjp161948 printf "\t%s\t%s,%s", $opcode->out(), 430*2139Sjp161948 $dst->out($sz),$src->out($sz); 431*2139Sjp161948 } 432*2139Sjp161948 } elsif (defined($src)) { 433*2139Sjp161948 printf "\t%s\t%s",$opcode->out(),$src->out($sz); 434*2139Sjp161948 } else { 435*2139Sjp161948 printf "\t%s",$opcode->out(); 436*2139Sjp161948 } 437*2139Sjp161948 } 438*2139Sjp161948 439*2139Sjp161948 print $line,"\n"; 440*2139Sjp161948} 441*2139Sjp161948 442*2139Sjp161948print "\n$current_segment\tENDS\nEND\n" if ($masm); 443*2139Sjp161948 444*2139Sjp161948close STDOUT; 445*2139Sjp161948 446*2139Sjp161948################################################# 447*2139Sjp161948# Cross-reference x86_64 ABI "card" 448*2139Sjp161948# 449*2139Sjp161948# Unix Win64 450*2139Sjp161948# %rax * * 451*2139Sjp161948# %rbx - - 452*2139Sjp161948# %rcx #4 #1 453*2139Sjp161948# %rdx #3 #2 454*2139Sjp161948# %rsi #2 - 455*2139Sjp161948# %rdi #1 - 456*2139Sjp161948# %rbp - - 457*2139Sjp161948# %rsp - - 458*2139Sjp161948# %r8 #5 #3 459*2139Sjp161948# %r9 #6 #4 460*2139Sjp161948# %r10 * * 461*2139Sjp161948# %r11 * * 462*2139Sjp161948# %r12 - - 463*2139Sjp161948# %r13 - - 464*2139Sjp161948# %r14 - - 465*2139Sjp161948# %r15 - - 466*2139Sjp161948# 467*2139Sjp161948# (*) volatile register 468*2139Sjp161948# (-) preserved by callee 469*2139Sjp161948# (#) Nth argument, volatile 470*2139Sjp161948# 471*2139Sjp161948# In Unix terms top of stack is argument transfer area for arguments 472*2139Sjp161948# which could not be accomodated in registers. Or in other words 7th 473*2139Sjp161948# [integer] argument resides at 8(%rsp) upon function entry point. 474*2139Sjp161948# 128 bytes above %rsp constitute a "red zone" which is not touched 475*2139Sjp161948# by signal handlers and can be used as temporal storage without 476*2139Sjp161948# allocating a frame. 477*2139Sjp161948# 478*2139Sjp161948# In Win64 terms N*8 bytes on top of stack is argument transfer area, 479*2139Sjp161948# which belongs to/can be overwritten by callee. N is the number of 480*2139Sjp161948# arguments passed to callee, *but* not less than 4! This means that 481*2139Sjp161948# upon function entry point 5th argument resides at 40(%rsp), as well 482*2139Sjp161948# as that 32 bytes from 8(%rsp) can always be used as temporal 483*2139Sjp161948# storage [without allocating a frame]. 484*2139Sjp161948# 485*2139Sjp161948# All the above means that if assembler programmer adheres to Unix 486*2139Sjp161948# register and stack layout, but disregards the "red zone" existense, 487*2139Sjp161948# it's possible to use following prologue and epilogue to "gear" from 488*2139Sjp161948# Unix to Win64 ABI in leaf functions with not more than 6 arguments. 489*2139Sjp161948# 490*2139Sjp161948# omnipotent_function: 491*2139Sjp161948# ifdef WIN64 492*2139Sjp161948# movq %rdi,8(%rsp) 493*2139Sjp161948# movq %rsi,16(%rsp) 494*2139Sjp161948# movq %rcx,%rdi ; if 1st argument is actually present 495*2139Sjp161948# movq %rdx,%rsi ; if 2nd argument is actually ... 496*2139Sjp161948# movq %r8,%rdx ; if 3rd argument is ... 497*2139Sjp161948# movq %r9,%rcx ; if 4th argument ... 498*2139Sjp161948# movq 40(%rsp),%r8 ; if 5th ... 499*2139Sjp161948# movq 48(%rsp),%r9 ; if 6th ... 500*2139Sjp161948# endif 501*2139Sjp161948# ... 502*2139Sjp161948# ifdef WIN64 503*2139Sjp161948# movq 8(%rsp),%rdi 504*2139Sjp161948# movq 16(%rsp),%rsi 505*2139Sjp161948# endif 506*2139Sjp161948# ret 507