x86nasm.pl revision 55714
1#!/usr/local/bin/perl 2 3package x86nasm; 4 5$label="L000"; 6 7%lb=( 'eax', 'al', 8 'ebx', 'bl', 9 'ecx', 'cl', 10 'edx', 'dl', 11 'ax', 'al', 12 'bx', 'bl', 13 'cx', 'cl', 14 'dx', 'dl', 15 ); 16 17%hb=( 'eax', 'ah', 18 'ebx', 'bh', 19 'ecx', 'ch', 20 'edx', 'dh', 21 'ax', 'ah', 22 'bx', 'bh', 23 'cx', 'ch', 24 'dx', 'dh', 25 ); 26 27sub main'asm_init_output { @out=(); } 28sub main'asm_get_output { return(@out); } 29sub main'get_labels { return(@labels); } 30 31sub main'external_label 32{ 33 push(@labels,@_); 34 foreach (@_) { 35 push(@out, "extern\t_$_\n"); 36 } 37} 38 39sub main'LB 40 { 41 (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n"; 42 return($lb{$_[0]}); 43 } 44 45sub main'HB 46 { 47 (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n"; 48 return($hb{$_[0]}); 49 } 50 51sub main'BP 52 { 53 &get_mem("BYTE",@_); 54 } 55 56sub main'DWP 57 { 58 &get_mem("DWORD",@_); 59 } 60 61sub main'BC 62 { 63 return "BYTE @_"; 64 } 65 66sub main'DWC 67 { 68 return "DWORD @_"; 69 } 70 71sub main'stack_push 72 { 73 my($num)=@_; 74 $stack+=$num*4; 75 &main'sub("esp",$num*4); 76 } 77 78sub main'stack_pop 79 { 80 my($num)=@_; 81 $stack-=$num*4; 82 &main'add("esp",$num*4); 83 } 84 85sub get_mem 86 { 87 my($size,$addr,$reg1,$reg2,$idx)=@_; 88 my($t,$post); 89 my($ret)="["; 90 $addr =~ s/^\s+//; 91 if ($addr =~ /^(.+)\+(.+)$/) 92 { 93 $reg2=&conv($1); 94 $addr="_$2"; 95 } 96 elsif ($addr =~ /^[_a-zA-Z]/) 97 { 98 $addr="_$addr"; 99 } 100 101 $reg1="$regs{$reg1}" if defined($regs{$reg1}); 102 $reg2="$regs{$reg2}" if defined($regs{$reg2}); 103 if (($addr ne "") && ($addr ne 0)) 104 { 105 if ($addr !~ /^-/) 106 { $ret.="${addr}+"; } 107 else { $post=$addr; } 108 } 109 if ($reg2 ne "") 110 { 111 $t=""; 112 $t="*$idx" if ($idx != 0); 113 $reg1="+".$reg1 if ("$reg1$post" ne ""); 114 $ret.="$reg2$t$reg1$post]"; 115 } 116 else 117 { 118 $ret.="$reg1$post]" 119 } 120 return($ret); 121 } 122 123sub main'mov { &out2("mov",@_); } 124sub main'movb { &out2("mov",@_); } 125sub main'and { &out2("and",@_); } 126sub main'or { &out2("or",@_); } 127sub main'shl { &out2("shl",@_); } 128sub main'shr { &out2("shr",@_); } 129sub main'xor { &out2("xor",@_); } 130sub main'xorb { &out2("xor",@_); } 131sub main'add { &out2("add",@_); } 132sub main'adc { &out2("adc",@_); } 133sub main'sub { &out2("sub",@_); } 134sub main'rotl { &out2("rol",@_); } 135sub main'rotr { &out2("ror",@_); } 136sub main'exch { &out2("xchg",@_); } 137sub main'cmp { &out2("cmp",@_); } 138sub main'lea { &out2("lea",@_); } 139sub main'mul { &out1("mul",@_); } 140sub main'div { &out1("div",@_); } 141sub main'dec { &out1("dec",@_); } 142sub main'inc { &out1("inc",@_); } 143sub main'jmp { &out1("jmp",@_); } 144sub main'jmp_ptr { &out1p("jmp",@_); } 145 146# This is a bit of a kludge: declare all branches as NEAR. 147sub main'je { &out1("je NEAR",@_); } 148sub main'jle { &out1("jle NEAR",@_); } 149sub main'jz { &out1("jz NEAR",@_); } 150sub main'jge { &out1("jge NEAR",@_); } 151sub main'jl { &out1("jl NEAR",@_); } 152sub main'jb { &out1("jb NEAR",@_); } 153sub main'jc { &out1("jc NEAR",@_); } 154sub main'jnc { &out1("jnc NEAR",@_); } 155sub main'jnz { &out1("jnz NEAR",@_); } 156sub main'jne { &out1("jne NEAR",@_); } 157sub main'jno { &out1("jno NEAR",@_); } 158 159sub main'push { &out1("push",@_); $stack+=4; } 160sub main'pop { &out1("pop",@_); $stack-=4; } 161sub main'bswap { &out1("bswap",@_); &using486(); } 162sub main'not { &out1("not",@_); } 163sub main'call { &out1("call",'_'.$_[0]); } 164sub main'ret { &out0("ret"); } 165sub main'nop { &out0("nop"); } 166 167sub out2 168 { 169 my($name,$p1,$p2)=@_; 170 my($l,$t); 171 172 push(@out,"\t$name\t"); 173 $t=&conv($p1).","; 174 $l=length($t); 175 push(@out,$t); 176 $l=4-($l+9)/8; 177 push(@out,"\t" x $l); 178 push(@out,&conv($p2)); 179 push(@out,"\n"); 180 } 181 182sub out0 183 { 184 my($name)=@_; 185 186 push(@out,"\t$name\n"); 187 } 188 189sub out1 190 { 191 my($name,$p1)=@_; 192 my($l,$t); 193 push(@out,"\t$name\t".&conv($p1)."\n"); 194 } 195 196sub conv 197 { 198 my($p)=@_; 199 $p =~ s/0x([0-9A-Fa-f]+)/0$1h/; 200 return $p; 201 } 202 203sub using486 204 { 205 return if $using486; 206 $using486++; 207 grep(s/\.386/\.486/,@out); 208 } 209 210sub main'file 211 { 212 push(@out, "segment .text\n"); 213 } 214 215sub main'function_begin 216 { 217 my($func,$extra)=@_; 218 219 push(@labels,$func); 220 my($tmp)=<<"EOF"; 221global _$func 222_$func: 223 push ebp 224 push ebx 225 push esi 226 push edi 227EOF 228 push(@out,$tmp); 229 $stack=20; 230 } 231 232sub main'function_begin_B 233 { 234 my($func,$extra)=@_; 235 my($tmp)=<<"EOF"; 236global _$func 237_$func: 238EOF 239 push(@out,$tmp); 240 $stack=4; 241 } 242 243sub main'function_end 244 { 245 my($func)=@_; 246 247 my($tmp)=<<"EOF"; 248 pop edi 249 pop esi 250 pop ebx 251 pop ebp 252 ret 253EOF 254 push(@out,$tmp); 255 $stack=0; 256 %label=(); 257 } 258 259sub main'function_end_B 260 { 261 $stack=0; 262 %label=(); 263 } 264 265sub main'function_end_A 266 { 267 my($func)=@_; 268 269 my($tmp)=<<"EOF"; 270 pop edi 271 pop esi 272 pop ebx 273 pop ebp 274 ret 275EOF 276 push(@out,$tmp); 277 } 278 279sub main'file_end 280 { 281 } 282 283sub main'wparam 284 { 285 my($num)=@_; 286 287 return(&main'DWP($stack+$num*4,"esp","",0)); 288 } 289 290sub main'swtmp 291 { 292 return(&main'DWP($_[0]*4,"esp","",0)); 293 } 294 295# Should use swtmp, which is above esp. Linix can trash the stack above esp 296#sub main'wtmp 297# { 298# my($num)=@_; 299# 300# return(&main'DWP(-(($num+1)*4),"esp","",0)); 301# } 302 303sub main'comment 304 { 305 foreach (@_) 306 { 307 push(@out,"\t; $_\n"); 308 } 309 } 310 311sub main'label 312 { 313 if (!defined($label{$_[0]})) 314 { 315 $label{$_[0]}="\$${label}${_[0]}"; 316 $label++; 317 } 318 return($label{$_[0]}); 319 } 320 321sub main'set_label 322 { 323 if (!defined($label{$_[0]})) 324 { 325 $label{$_[0]}="${label}${_[0]}"; 326 $label++; 327 } 328 push(@out,"$label{$_[0]}:\n"); 329 } 330 331sub main'data_word 332 { 333 push(@out,"\tDD\t$_[0]\n"); 334 } 335 336sub out1p 337 { 338 my($name,$p1)=@_; 339 my($l,$t); 340 341 push(@out,"\t$name\t ".&conv($p1)."\n"); 342 } 343