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