3 Copyright (c) 1998-2000 by Florian Klaempfl
5 This unit implements an asmoutput class for Intel syntax with Intel i386+
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 ****************************************************************************
33 pi386intasmlist=^ti386intasmlist;
34 ti386intasmlist = object(tasmlist)
35 procedure WriteTree(p:paasmoutput);virtual;
36 procedure WriteAsmList;virtual;
37 procedure WriteExternals;
44 globtype,globals,systems,cobjects,
45 files,verbose,cpubase,cpuasm
55 extstr : array[EXT_NEAR..EXT_ABS] of String[8] =
56 ('NEAR','FAR','PROC','BYTE','WORD','DWORD',
57 'CODEPTR','DATAPTR','FWORD','PWORD','QWORD','TBYTE','ABS');
60 function single2str(d : single) : string;
66 { nasm expects a lowercase e }
73 single2str:=lower(hs);
76 function double2str(d : double) : string;
82 { nasm expects a lowercase e }
89 double2str:=lower(hs);
92 function extended2str(e : extended) : string;
98 { nasm expects a lowercase e }
105 extended2str:=lower(hs);
109 function comp2str(d : bestreal) : string;
121 dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
122 comp2str:=double2str(dd^);
125 function getreferencestring(var ref : treference) : string;
130 if ref.is_immediate then
132 getreferencestring:=tostr(ref.offset);
139 inc(offset,offsetfixup);
141 if ref.segment<>R_NO then
142 s:=int_reg2str[segment]+':['
145 if assigned(symbol) then
156 s:=s+int_reg2str[base];
158 if (index<>R_NO) then
164 s:=s+int_reg2str[index];
165 if scalefactor<>0 then
166 s:=s+'*'+tostr(scalefactor);
170 else if (offset>0) then
171 s:=s+'+'+tostr(offset);
174 getreferencestring:=s;
178 function getopstr(const o:toper;s : topsize; opcode: tasmop;dest : boolean) : string;
184 getopstr:=int_reg2str[o.reg];
186 getopstr:=tostr(o.val);
189 if assigned(o.sym) then
190 hs:='offset '+o.sym^.name
194 hs:=hs+'+'+tostr(o.symofs)
197 hs:=hs+tostr(o.symofs)
199 if not(assigned(o.sym)) then
205 hs:=getreferencestring(o.ref^);
206 if ((opcode <> A_LGS) and (opcode <> A_LSS) and
207 (opcode <> A_LFS) and (opcode <> A_LDS) and
208 (opcode <> A_LES)) then
211 S_B : hs:='byte ptr '+hs;
212 S_W : hs:='word ptr '+hs;
213 S_L : hs:='dword ptr '+hs;
214 S_IS : hs:='word ptr '+hs;
215 S_IL : hs:='dword ptr '+hs;
216 S_IQ : hs:='qword ptr '+hs;
217 S_FS : hs:='dword ptr '+hs;
218 S_FL : hs:='qword ptr '+hs;
219 S_FX : hs:='tbyte ptr '+hs;
237 internalerror(10001);
241 function getopstr_jmp(const o:toper) : string;
247 getopstr_jmp:=int_reg2str[o.reg];
249 getopstr_jmp:=tostr(o.val);
254 hs:=hs+'+'+tostr(o.symofs)
257 hs:=hs+tostr(o.symofs);
261 getopstr_jmp:=getreferencestring(o.ref^);
263 internalerror(10001);
268 {****************************************************************************
270 ****************************************************************************}
276 ait_const2str:array[ait_const_32bit..ait_const_8bit] of string[8]=
277 (#9'DD'#9,#9'DW'#9,#9'DB'#9);
279 Function PadTabs(const p:string;addch:char):string;
298 procedure ti386intasmlist.WriteTree(p:paasmoutput);
300 allocstr : array[boolean] of string[10]=(' released',' allocated');
314 if not assigned(p) then
317 while assigned(hp) do
321 AsmWrite(target_asm.comment);
322 AsmWritePChar(pai_asm_comment(hp)^.str);
328 if LastSec<>sec_none then
329 AsmWriteLn('_'+target_asm.secnames[LastSec]+#9#9'ENDS');
330 if pai_section(hp)^.sec<>sec_none then
333 AsmWriteLn('_'+target_asm.secnames[pai_section(hp)^.sec]+#9#9+
334 'SEGMENT'#9'PARA PUBLIC USE32 '''+
335 target_asm.secnames[pai_section(hp)^.sec]+'''');
337 LastSec:=pai_section(hp)^.sec;
340 { CAUSES PROBLEMS WITH THE SEGMENT DEFINITION }
341 { SEGMENT DEFINITION SHOULD MATCH TYPE OF ALIGN }
343 AsmWriteLn(#9'ALIGN '+tostr(pai_align(hp)^.aligntype));
345 ait_datablock : begin
346 if pai_datablock(hp)^.is_global then
347 AsmWriteLn(#9'PUBLIC'#9+pai_datablock(hp)^.sym^.name);
348 AsmWriteLn(PadTabs(pai_datablock(hp)^.sym^.name,#0)+'DB'#9+tostr(pai_datablock(hp)^.size)+' DUP(?)');
352 ait_const_16bit : begin
353 AsmWrite(ait_const2str[hp^.typ]+tostr(pai_const(hp)^.value));
357 found:=(not (Pai(hp^.next)=nil)) and (Pai(hp^.next)^.typ=consttyp);
361 s:=','+tostr(pai_const(hp)^.value);
365 until (not found) or (l>line_length);
368 ait_const_symbol : begin
369 AsmWriteLn(#9#9'DD'#9'offset '+pai_const_symbol(hp)^.sym^.name);
370 if pai_const_symbol(hp)^.offset>0 then
371 AsmWrite('+'+tostr(pai_const_symbol(hp)^.offset))
372 else if pai_const_symbol(hp)^.offset<0 then
373 AsmWrite(tostr(pai_const_symbol(hp)^.offset));
376 ait_const_rva : begin
377 AsmWriteLn(#9#9'RVA'#9+pai_const_symbol(hp)^.sym^.name);
379 ait_real_32bit : AsmWriteLn(#9#9'DD'#9+single2str(pai_real_32bit(hp)^.value));
380 ait_real_64bit : AsmWriteLn(#9#9'DQ'#9+double2str(pai_real_64bit(hp)^.value));
381 ait_real_80bit : AsmWriteLn(#9#9'DT'#9+extended2str(pai_real_80bit(hp)^.value));
382 ait_comp_64bit : AsmWriteLn(#9#9'DQ'#9+comp2str(pai_real_80bit(hp)^.value));
385 lines := pai_string(hp)^.len div line_length;
386 { separate lines in different parts }
387 if pai_string(hp)^.len > 0 then
389 for j := 0 to lines-1 do
391 AsmWrite(#9#9'DB'#9);
393 for i:=counter to counter+line_length do
395 { it is an ascii character. }
396 if (ord(pai_string(hp)^.str[i])>31) and
397 (ord(pai_string(hp)^.str[i])<128) and
398 (pai_string(hp)^.str[i]<>'"') then
406 AsmWrite(pai_string(hp)^.str[i]);
408 end { if > 31 and < 128 and ord('"') }
416 AsmWrite(tostr(ord(pai_string(hp)^.str[i])));
418 end; { end for i:=0 to... }
419 if quoted then AsmWrite('"');
420 AsmWrite(target_os.newline);
421 counter := counter+line_length;
422 end; { end for j:=0 ... }
423 { do last line of lines }
424 AsmWrite(#9#9'DB'#9);
426 for i:=counter to pai_string(hp)^.len-1 do
428 { it is an ascii character. }
429 if (ord(pai_string(hp)^.str[i])>31) and
430 (ord(pai_string(hp)^.str[i])<128) and
431 (pai_string(hp)^.str[i]<>'"') then
439 AsmWrite(pai_string(hp)^.str[i]);
441 end { if > 31 and < 128 and " }
449 AsmWrite(tostr(ord(pai_string(hp)^.str[i])));
451 end; { end for i:=0 to... }
458 if pai_label(hp)^.l^.is_used then
460 AsmWrite(pai_label(hp)^.l^.name);
461 if assigned(hp^.next) and not(pai(hp^.next)^.typ in
462 [ait_const_32bit,ait_const_16bit,ait_const_8bit,
463 ait_const_symbol,ait_const_rva,
464 ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
469 AsmWritePChar(pai_direct(hp)^.str);
473 if pai_symbol(hp)^.is_global then
474 AsmWriteLn(#9'PUBLIC'#9+pai_symbol(hp)^.sym^.name);
475 AsmWrite(pai_symbol(hp)^.sym^.name);
476 if assigned(hp^.next) and not(pai(hp^.next)^.typ in
477 [ait_const_32bit,ait_const_16bit,ait_const_8bit,
478 ait_const_symbol,ait_const_rva,
479 ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
482 ait_symbol_end : begin
484 ait_instruction : begin
485 { Must be done with args in ATT order }
486 paicpu(hp)^.CheckNonCommutativeOpcodes;
487 { We need intel order, no At&t }
488 paicpu(hp)^.SwapOperands;
493 { We need to explicitely set
494 word prefix to get selectors
495 to be pushed in 2 bytes PM }
496 if (paicpu(hp)^.opsize=S_W) and
497 ((paicpu(hp)^.opcode=A_PUSH) or
498 (paicpu(hp)^.opcode=A_POP)) and
499 (paicpu(hp)^.oper[0].typ=top_reg) and
500 ((paicpu(hp)^.oper[0].reg>=firstsreg) and
501 (paicpu(hp)^.oper[0].reg<=lastsreg)) then
502 AsmWriteln(#9#9'DB'#9'066h');
503 { added prefix instructions, must be on same line as opcode }
504 if (paicpu(hp)^.ops = 0) and
505 ((paicpu(hp)^.opcode = A_REP) or
506 (paicpu(hp)^.opcode = A_LOCK) or
507 (paicpu(hp)^.opcode = A_REPE) or
508 (paicpu(hp)^.opcode = A_REPNZ) or
509 (paicpu(hp)^.opcode = A_REPZ) or
510 (paicpu(hp)^.opcode = A_REPNE)) then
512 prefix:=int_op2str[paicpu(hp)^.opcode]+#9;
514 { this is theorically impossible... }
521 { nasm prefers prefix on a line alone }
522 AsmWriteln(#9#9+prefix);
527 if paicpu(hp)^.ops<>0 then
529 if is_calljmp(paicpu(hp)^.opcode) then
530 s:=#9+getopstr_jmp(paicpu(hp)^.oper[0])
533 for i:=0to paicpu(hp)^.ops-1 do
539 s:=s+sep+getopstr(paicpu(hp)^.oper[i],paicpu(hp)^.opsize,paicpu(hp)^.opcode,(i=2));
543 AsmWriteLn(#9#9+prefix+int_op2str[paicpu(hp)^.opcode]+cond2str[paicpu(hp)^.condition]+suffix+s);
549 ait_stab_function_name : ;
552 { only reset buffer if nothing has changed }
553 if AsmSize=AsmStartSize then
557 if LastSec<>sec_none then
558 AsmWriteLn('_'+target_asm.secnames[LastSec]+#9#9'ENDS');
563 AsmCreate(pai_cut(hp)^.place);
565 { avoid empty files }
566 while assigned(hp^.next) and (pai(hp^.next)^.typ in [ait_cut,ait_section,ait_comment]) do
568 if pai(hp^.next)^.typ=ait_section then
570 lastsec:=pai_section(hp^.next)^.sec;
574 AsmWriteLn(#9'.386p');
575 { I was told that this isn't necesarry because }
576 { the labels generated by FPC are unique (FK) }
577 { AsmWriteLn(#9'LOCALS '+target_asm.labelprefix); }
578 if lastsec<>sec_none then
579 AsmWriteLn('_'+target_asm.secnames[lastsec]+#9#9+
580 'SEGMENT'#9'PARA PUBLIC USE32 '''+
581 target_asm.secnames[lastsec]+'''');
582 AsmStartSize:=AsmSize;
586 internalerror(10000);
593 currentasmlist : PAsmList;
595 procedure writeexternal(p:pnamedindexobject);{$ifndef FPC}far;{$endif}
597 if pasmsymbol(p)^.deftyp=AS_EXTERNAL then
598 currentasmlist^.AsmWriteln(#9'EXTRN'#9+p^.name);
601 procedure ti386intasmlist.WriteExternals;
603 currentasmlist:=@self;
604 AsmSymbolList^.foreach({$ifndef VER70}@{$endif}writeexternal);
608 procedure ti386intasmlist.WriteAsmList;
611 if assigned(current_module^.mainsource) then
612 comment(v_info,'Start writing intel-styled assembler output for '+current_module^.mainsource^);
615 AsmWriteLn(#9'.386p');
616 AsmWriteLn(#9'LOCALS '+target_asm.labelprefix);
617 AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
618 AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
621 countlabelref:=false;
625 { INTEL ASM doesn't support stabs
626 WriteTree(debuglist);}
628 WriteTree(codesegment);
629 WriteTree(datasegment);
632 WriteTree(resourcestringlist);
633 WriteTree(bsssegment);
640 if assigned(current_module^.mainsource) then
641 comment(v_info,'Done writing intel-styled assembler output for '+current_module^.mainsource^);
648 Revision 1.1 2002/02/19 08:21:25 sasu
651 Revision 1.1.2.1 2000/08/20 17:37:11 peter
652 * smartlinking fixed for linux
654 Revision 1.1 2000/07/13 06:29:43 michael
657 Revision 1.62 2000/05/12 21:26:22 pierre
658 * fix the FDIV FDIVR FSUB FSUBR and popping equivalent
659 simply by swapping from reverse to normal and vice-versa
660 when passing from one syntax to the other !
662 Revision 1.61 2000/05/09 21:44:27 pierre
663 * add .byte 066h to force correct pushw %es
664 * handle push es as a pushl %es
666 Revision 1.60 2000/04/06 07:05:57 pierre
669 Revision 1.59 2000/02/09 13:22:43 peter
672 Revision 1.58 2000/01/07 01:14:18 peter
673 * updated copyright to 2000
675 Revision 1.57 1999/12/19 17:36:25 florian
676 * generation of LOCALS @@ removed
678 Revision 1.56 1999/11/06 14:34:16 peter
679 * truncated log to 20 revs
681 Revision 1.55 1999/11/02 15:06:56 peter
682 * import library fixes for win32
683 * alignment works again
685 Revision 1.54 1999/09/10 15:41:18 peter
688 Revision 1.53 1999/09/02 18:47:42 daniel
689 * Could not compile with TP, some arrays moved to heap
690 * NOAG386BIN default for TP
691 * AG386* files were not compatible with TP, fixed.
693 Revision 1.52 1999/08/25 11:59:36 jonas
694 * changed pai386, paippc and paiapha (same for tai*) to paicpu (taicpu)
696 Revision 1.51 1999/08/04 00:22:36 florian
697 * renamed i386asm and i386base to cpuasm and cpubase
699 Revision 1.50 1999/07/22 09:37:31 florian
700 + resourcestring implemented
701 + start of longstring support