1 { 2 Copyright (c) 1998-2002 by Florian Klaempfl 3 4 This unit implements an asmoutput class for i386 AT&T syntax 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20 **************************************************************************** 21 } 22 { This unit implements an asmoutput class for i386 AT&T syntax 23 } 24 unit agx86att; 25 26 {$i fpcdefs.inc} 27 28 interface 29 30 uses 31 cpubase,systems, 32 globtype,cgutils, 33 aasmtai,assemble,aggas; 34 35 type 36 Tx86ATTAssembler=class(TGNUassembler) 37 constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override; MakeCmdLinenull38 function MakeCmdLine: TCmdStr; override; 39 end; 40 41 Tx86AppleGNUAssembler=class(TAppleGNUassembler) 42 constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override; 43 end; 44 45 Tx86AoutGNUAssembler=class(TAoutGNUassembler) 46 constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override; 47 end; 48 49 50 Tx86InstrWriter=class(TCPUInstrWriter) 51 private 52 procedure WriteReference(var ref : treference); 53 procedure WriteOper(const o:toper); 54 procedure WriteOper_jmp(const o:toper); 55 protected 56 fskipPopcountSuffix: boolean; 57 { http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56656 } 58 fNoInterUnitMovQ: boolean; 59 public 60 procedure WriteInstruction(hp: tai);override; 61 end; 62 63 64 65 implementation 66 67 uses 68 cutils, 69 verbose, 70 itcpugas, 71 cgbase, 72 aasmcpu; 73 74 75 {**************************************************************************** 76 Tx86ATTAssembler 77 ****************************************************************************} 78 79 constructor Tx86ATTAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); 80 begin 81 inherited; 82 InstrWriter := Tx86InstrWriter.create(self); 83 end; 84 TX86ATTAssembler.MakeCmdLinenull85 function TX86ATTAssembler.MakeCmdLine: TCmdStr; 86 var 87 FormatName : string; 88 begin 89 result:=Inherited MakeCmdLine; 90 {$ifdef i386} 91 case target_info.system of 92 system_i386_go32v2: 93 FormatName:='coff'; 94 system_i386_wdosx, 95 system_i386_win32: 96 FormatName:='win32'; 97 system_i386_embedded: 98 FormatName:='obj'; 99 system_i386_linux, 100 system_i386_beos: 101 FormatName:='elf'; 102 system_i386_darwin: 103 FormatName:='macho32'; 104 else 105 FormatName:='elf'; 106 end; 107 {$endif i386} 108 {$ifdef x86_64} 109 case target_info.system of 110 system_x86_64_win64: 111 FormatName:='win64'; 112 system_x86_64_darwin: 113 FormatName:='macho64'; 114 system_x86_64_embedded: 115 FormatName:='obj'; 116 system_x86_64_linux: 117 FormatName:='elf64'; 118 else 119 FormatName:='elf64'; 120 end; 121 {$endif x86_64} 122 Replace(result,'$FORMAT',FormatName); 123 end; 124 125 {**************************************************************************** 126 Tx86AppleGNUAssembler 127 ****************************************************************************} 128 129 constructor Tx86AppleGNUAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); 130 begin 131 inherited; 132 InstrWriter := Tx86InstrWriter.create(self); 133 { Apple's assembler does not support a size suffix for popcount } 134 Tx86InstrWriter(InstrWriter).fskipPopcountSuffix := true; 135 { Apple's assembler is broken regarding some movq suffix handling } 136 Tx86InstrWriter(InstrWriter).fNoInterUnitMovQ := true; 137 end; 138 139 {**************************************************************************** 140 Tx86AoutGNUAssembler 141 ****************************************************************************} 142 143 constructor Tx86AoutGNUAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); 144 begin 145 inherited; 146 InstrWriter := Tx86InstrWriter.create(self); 147 end; 148 149 {**************************************************************************** 150 Tx86InstrWriter 151 ****************************************************************************} 152 153 procedure Tx86InstrWriter.WriteReference(var ref : treference); 154 begin 155 with ref do 156 begin 157 { do we have a segment prefix ? } 158 { These are probably not correctly handled under GAS } 159 { should be replaced by coding the segment override } 160 { directly! - DJGPP FAQ } 161 if segment<>NR_NO then 162 owner.writer.AsmWrite(gas_regname(segment)+':'); 163 if assigned(symbol) then 164 owner.writer.AsmWrite(symbol.name); 165 if assigned(relsymbol) then 166 owner.writer.AsmWrite('-'+relsymbol.name); 167 if ref.refaddr=addr_pic then 168 begin 169 { @GOT and @GOTPCREL references are only allowed for symbol alone, 170 indexing, relsymbol or offset cannot be present. } 171 if assigned(relsymbol) or (offset<>0) or (index<>NR_NO) then 172 InternalError(2015011801); 173 {$ifdef x86_64} 174 if (base<>NR_RIP) then 175 InternalError(2015011802); 176 owner.writer.AsmWrite('@GOTPCREL'); 177 {$else x86_64} 178 owner.writer.AsmWrite('@GOT'); 179 {$endif x86_64} 180 end; 181 if offset<0 then 182 owner.writer.AsmWrite(tostr(offset)) 183 else 184 if (offset>0) then 185 begin 186 if assigned(symbol) then 187 owner.writer.AsmWrite('+'+tostr(offset)) 188 else 189 owner.writer.AsmWrite(tostr(offset)); 190 end 191 else if (index=NR_NO) and (base=NR_NO) and (not assigned(symbol)) then 192 owner.writer.AsmWrite('0'); 193 if (index<>NR_NO) and (base=NR_NO) then 194 begin 195 owner.writer.AsmWrite('(,'+gas_regname(index)); 196 if scalefactor<>0 then 197 owner.writer.AsmWrite(','+tostr(scalefactor)); 198 owner.writer.AsmWrite(')'); 199 end 200 else 201 if (index=NR_NO) and (base<>NR_NO) then 202 owner.writer.AsmWrite('('+gas_regname(base)+')') 203 else 204 if (index<>NR_NO) and (base<>NR_NO) then 205 begin 206 owner.writer.AsmWrite('('+gas_regname(base)+','+gas_regname(index)); 207 if scalefactor<>0 then 208 owner.writer.AsmWrite(','+tostr(scalefactor)); 209 owner.writer.AsmWrite(')'); 210 end; 211 end; 212 end; 213 214 215 procedure Tx86InstrWriter.WriteOper(const o:toper); 216 begin 217 case o.typ of 218 top_reg : 219 { Solaris assembler does not accept %st instead of %st(0) } 220 if (owner.asminfo^.id=as_solaris_as) and (o.reg=NR_ST) then 221 owner.writer.AsmWrite(gas_regname(NR_ST0)) 222 else 223 owner.writer.AsmWrite(gas_regname(o.reg)); 224 top_ref : 225 if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got] then 226 WriteReference(o.ref^) 227 else 228 begin 229 owner.writer.AsmWrite('$'); 230 if assigned(o.ref^.symbol) then 231 owner.writer.AsmWrite(o.ref^.symbol.name); 232 if o.ref^.offset>0 then 233 owner.writer.AsmWrite('+'+tostr(o.ref^.offset)) 234 else 235 if o.ref^.offset<0 then 236 owner.writer.AsmWrite(tostr(o.ref^.offset)) 237 else 238 if not(assigned(o.ref^.symbol)) then 239 owner.writer.AsmWrite('0'); 240 end; 241 top_const : 242 owner.writer.AsmWrite('$'+tostr(o.val)); 243 else 244 internalerror(10001); 245 end; 246 end; 247 248 249 procedure Tx86InstrWriter.WriteOper_jmp(const o:toper); 250 begin 251 case o.typ of 252 top_reg : 253 owner.writer.AsmWrite('*'+gas_regname(o.reg)); 254 top_ref : 255 begin 256 if o.ref^.refaddr in [addr_no,addr_pic_no_got] then 257 begin 258 owner.writer.AsmWrite('*'); 259 WriteReference(o.ref^); 260 end 261 else 262 begin 263 owner.writer.AsmWrite(o.ref^.symbol.name); 264 if o.ref^.refaddr=addr_pic then 265 owner.writer.AsmWrite('@PLT'); 266 if o.ref^.offset>0 then 267 owner.writer.AsmWrite('+'+tostr(o.ref^.offset)) 268 else 269 if o.ref^.offset<0 then 270 owner.writer.AsmWrite(tostr(o.ref^.offset)); 271 end; 272 end; 273 top_const : 274 owner.writer.AsmWrite(tostr(o.val)); 275 else 276 internalerror(10001); 277 end; 278 end; 279 280 281 procedure Tx86InstrWriter.WriteInstruction(hp: tai); 282 var 283 op : tasmop; 284 calljmp : boolean; 285 i : integer; 286 begin 287 if hp.typ <> ait_instruction then 288 exit; 289 taicpu(hp).SetOperandOrder(op_att); 290 op:=taicpu(hp).opcode; 291 calljmp:=is_calljmp(op); 292 293 { see fNoInterUnitMovQ declaration comment } 294 if fNoInterUnitMovQ then 295 begin 296 if ((op=A_MOVQ) or 297 (op=A_VMOVQ)) and 298 (((taicpu(hp).oper[0]^.typ=top_reg) and 299 (getregtype(taicpu(hp).oper[0]^.reg)=R_INTREGISTER)) or 300 ((taicpu(hp).oper[1]^.typ=top_reg) and 301 (getregtype(taicpu(hp).oper[1]^.reg)=R_INTREGISTER))) then 302 begin 303 if op=A_MOVQ then 304 op:=A_MOVD 305 else 306 op:=A_VMOVD; 307 taicpu(hp).opcode:=op; 308 end; 309 end; 310 owner.writer.AsmWrite(#9); 311 { movsd should not be translated to movsl when there 312 are (xmm) arguments } 313 if (op=A_MOVSD) and (taicpu(hp).ops>0) then 314 owner.writer.AsmWrite('movsd') 315 { the same applies to cmpsd as well } 316 else if (op=A_CMPSD) and (taicpu(hp).ops>0) then 317 owner.writer.AsmWrite('cmpsd') 318 else 319 owner.writer.AsmWrite(gas_op2str[op]); 320 owner.writer.AsmWrite(cond2str[taicpu(hp).condition]); 321 { suffix needed ? fnstsw,fldcw don't support suffixes 322 with binutils 2.9.5 under linux } 323 { if (Taicpu(hp).oper[0]^.typ=top_reg) and 324 (Taicpu(hp).oper[0]^.reg.enum>lastreg) then 325 internalerror(200301081);} 326 327 if (not calljmp) and 328 (gas_needsuffix[op]<>AttSufNONE) and 329 (op<>A_FNSTSW) and 330 (op<>A_FSTSW) and 331 (op<>A_FNSTCW) and 332 (op<>A_FSTCW) and 333 (op<>A_FLDCW) and 334 (not fskipPopcountSuffix or 335 (op<>A_POPCNT)) and 336 ((owner.asminfo^.id<>as_solaris_as) or (op<>A_Jcc) and (op<>A_SETcc)) and 337 not( 338 (taicpu(hp).ops<>0) and 339 (taicpu(hp).oper[0]^.typ=top_reg) and 340 (getregtype(taicpu(hp).oper[0]^.reg)=R_FPUREGISTER) 341 ) then 342 begin 343 owner.writer.AsmWrite(gas_opsize2str[taicpu(hp).opsize]); 344 end; 345 346 { process operands } 347 if taicpu(hp).ops<>0 then 348 begin 349 if calljmp then 350 begin 351 owner.writer.AsmWrite(#9); 352 WriteOper_jmp(taicpu(hp).oper[0]^); 353 end 354 else 355 begin 356 for i:=0 to taicpu(hp).ops-1 do 357 begin 358 if i=0 then 359 owner.writer.AsmWrite(#9) 360 else 361 owner.writer.AsmWrite(','); 362 WriteOper(taicpu(hp).oper[i]^); 363 end; 364 end; 365 end; 366 owner.writer.AsmLn; 367 end; 368 369 370 {***************************************************************************** 371 Initialize 372 *****************************************************************************} 373 374 const 375 {$ifdef x86_64} 376 as_x86_64_as_info : tasminfo = 377 ( 378 id : as_gas; 379 idtxt : 'AS'; 380 asmbin : 'as'; 381 asmcmd : '--64 -o $OBJ $BIGOBJ $EXTRAOPT $ASM'; 382 supported_targets : [system_x86_64_linux,system_x86_64_freebsd, 383 system_x86_64_win64,system_x86_64_embedded, 384 system_x86_64_openbsd,system_x86_64_netbsd, 385 system_x86_64_dragonfly,system_x86_64_aros, 386 system_x86_64_android,system_x86_64_haiku]; 387 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 388 labelprefix : '.L'; 389 comment : '# '; 390 dollarsign: '$'; 391 ); 392 393 as_x86_64_yasm_info : tasminfo = 394 ( 395 id : as_yasm; 396 idtxt : 'YASM'; 397 asmbin : 'yasm'; 398 asmcmd : '-a x86 -p gas -f $FORMAT -o $OBJ $EXTRAOPT $ASM'; 399 supported_targets : [system_x86_64_linux,system_x86_64_freebsd,system_x86_64_win64,system_x86_64_embedded]; 400 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 401 labelprefix : '.L'; 402 comment : '# '; 403 dollarsign: '$'; 404 ); 405 406 as_x86_64_gas_info : tasminfo = 407 ( 408 id : as_ggas; 409 idtxt : 'GAS'; 410 asmbin : 'gas'; 411 asmcmd : '--64 -o $OBJ $EXTRAOPT $ASM'; 412 supported_targets : [system_x86_64_solaris]; 413 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 414 labelprefix : '.L'; 415 comment : '# '; 416 dollarsign: '$'; 417 ); 418 419 420 as_x86_64_solaris_info : tasminfo = 421 ( 422 id : as_solaris_as; 423 idtxt : 'AS-SOL'; 424 asmbin : 'as'; 425 asmcmd : ' -m64 -o $OBJ $EXTRAOPT $ASM'; 426 supported_targets : [system_x86_64_solaris]; 427 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 428 labelprefix : '.L'; 429 comment : '# '; 430 dollarsign: '$'; 431 ); 432 433 434 435 as_x86_64_gas_darwin_info : tasminfo = 436 ( 437 id : as_darwin; 438 idtxt : 'AS-DARWIN'; 439 asmbin : 'as'; 440 asmcmd : '-o $OBJ $EXTRAOPT $ASM -arch x86_64'; 441 supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim]; 442 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 443 labelprefix : 'L'; 444 comment : '# '; 445 dollarsign: '$'; 446 ); 447 448 as_x86_64_clang_darwin_info : tasminfo = 449 ( 450 id : as_clang_asdarwin; 451 idtxt : 'CLANG'; 452 asmbin : 'clang'; 453 asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $EXTRAOPT -x assembler $ASM'; 454 supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim]; 455 flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_no_stabs,af_llvm]; 456 labelprefix : 'L'; 457 comment : '# '; 458 dollarsign: '$'; 459 ); 460 461 {$else x86_64} 462 as_i386_as_info : tasminfo = 463 ( 464 id : as_gas; 465 idtxt : 'AS'; 466 asmbin : 'as'; 467 asmcmd : '--32 -o $OBJ $BIGOBJ $EXTRAOPT $ASM'; 468 supported_targets : [system_i386_GO32V2,system_i386_linux,system_i386_Win32,system_i386_freebsd,system_i386_solaris,system_i386_beos, 469 system_i386_netbsd,system_i386_Netware,system_i386_wdosx,system_i386_openbsd, 470 system_i386_netwlibc,system_i386_wince,system_i386_embedded,system_i386_symbian,system_i386_haiku,system_x86_6432_linux, 471 system_i386_nativent,system_i386_android,system_i386_aros]; 472 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 473 labelprefix : '.L'; 474 comment : '# '; 475 dollarsign: '$'; 476 ); 477 478 as_i386_yasm_info : tasminfo = 479 ( 480 id : as_yasm; 481 idtxt : 'YASM'; 482 asmbin : 'yasm'; 483 asmcmd : '-a x86 -p gas -f $FORMAT -o $OBJ $EXTRAOPT $ASM'; 484 supported_targets : [system_i386_GO32V2,system_i386_linux,system_i386_Win32,system_i386_freebsd,system_i386_solaris,system_i386_beos, 485 system_i386_netbsd,system_i386_Netware,system_i386_wdosx,system_i386_openbsd, 486 system_i386_netwlibc,system_i386_wince,system_i386_embedded,system_i386_symbian,system_i386_haiku,system_x86_6432_linux, 487 system_i386_nativent]; 488 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 489 labelprefix : '.L'; 490 comment : '# '; 491 dollarsign: '$'; 492 ); 493 494 495 as_i386_as_aout_info : tasminfo = 496 ( 497 id : as_i386_as_aout; 498 idtxt : 'AS_AOUT'; 499 asmbin : 'as'; 500 asmcmd : '-o $OBJ $EXTRAOPT $ASM'; 501 supported_targets : [system_i386_linux,system_i386_OS2,system_i386_freebsd,system_i386_netbsd,system_i386_openbsd,system_i386_EMX,system_i386_embedded]; 502 flags : [af_needar,af_stabs_use_function_absolute_addresses]; 503 labelprefix : 'L'; 504 comment : '# '; 505 dollarsign: '$'; 506 ); 507 508 509 as_i386_gas_darwin_info : tasminfo = 510 ( 511 id : as_darwin; 512 idtxt : 'AS-DARWIN'; 513 asmbin : 'as'; 514 asmcmd : '-o $OBJ $EXTRAOPT $ASM -arch i386'; 515 supported_targets : [system_i386_darwin,system_i386_iphonesim]; 516 flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses]; 517 labelprefix : 'L'; 518 comment : '# '; 519 dollarsign: '$'; 520 ); 521 522 as_i386_clang_darwin_info : tasminfo = 523 ( 524 id : as_clang_asdarwin; 525 idtxt : 'CLANG'; 526 asmbin : 'clang'; 527 asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $EXTRAOPT -x assembler $ASM'; 528 supported_targets : [system_i386_darwin,system_i386_iphonesim]; 529 flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_no_stabs,af_llvm]; 530 labelprefix : 'L'; 531 comment : '# '; 532 dollarsign: '$'; 533 ); 534 535 as_i386_gas_info : tasminfo = 536 ( 537 id : as_ggas; 538 idtxt : 'GAS'; 539 asmbin : 'gas'; 540 asmcmd : '--32 -o $OBJ $EXTRAOPT $ASM'; 541 supported_targets : [system_i386_GO32V2,system_i386_linux,system_i386_Win32,system_i386_freebsd,system_i386_solaris,system_i386_beos, 542 system_i386_netbsd,system_i386_Netware,system_i386_wdosx,system_i386_openbsd, 543 system_i386_netwlibc,system_i386_wince,system_i386_embedded,system_i386_symbian,system_i386_haiku, 544 system_x86_6432_linux,system_i386_android]; 545 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 546 labelprefix : '.L'; 547 comment : '# '; 548 dollarsign: '$'; 549 ); 550 551 as_i386_solaris_info : tasminfo = 552 ( 553 id : as_solaris_as; 554 idtxt : 'AS-SOL'; 555 asmbin : 'as'; 556 asmcmd : ' -o $OBJ $EXTRAOPT $ASM'; 557 supported_targets : [system_i386_solaris]; 558 flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; 559 labelprefix : '.L'; 560 comment : '# '; 561 dollarsign: '$'; 562 ); 563 564 565 {$endif x86_64} 566 567 initialization 568 {$ifdef x86_64} 569 RegisterAssembler(as_x86_64_as_info,Tx86ATTAssembler); 570 RegisterAssembler(as_x86_64_yasm_info,Tx86ATTAssembler); 571 RegisterAssembler(as_x86_64_gas_info,Tx86ATTAssembler); 572 RegisterAssembler(as_x86_64_gas_darwin_info,Tx86AppleGNUAssembler); 573 RegisterAssembler(as_x86_64_clang_darwin_info,Tx86AppleGNUAssembler); 574 RegisterAssembler(as_x86_64_solaris_info,Tx86ATTAssembler); 575 {$else x86_64} 576 RegisterAssembler(as_i386_as_info,Tx86ATTAssembler); 577 RegisterAssembler(as_i386_gas_info,Tx86ATTAssembler); 578 RegisterAssembler(as_i386_yasm_info,Tx86ATTAssembler); 579 RegisterAssembler(as_i386_gas_darwin_info,Tx86AppleGNUAssembler); 580 RegisterAssembler(as_i386_clang_darwin_info,Tx86AppleGNUAssembler); 581 RegisterAssembler(as_i386_as_aout_info,Tx86AoutGNUAssembler); 582 RegisterAssembler(as_i386_solaris_info,Tx86ATTAssembler); 583 {$endif x86_64} 584 end. 585