ag386nsm.pas 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements an asmoutput class for the Nasm assembler with
  5. Intel syntax for the i386+
  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. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit ag386nsm;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. cpubase,
  24. aasmbase,aasmtai,aasmcpu,assemble;
  25. type
  26. T386NasmAssembler = class(texternalassembler)
  27. private
  28. procedure WriteReference(var ref : treference);
  29. procedure WriteOper(const o:toper;s : topsize; opcode: tasmop;ops:longint;dest : boolean);
  30. procedure WriteOper_jmp(const o:toper; op : tasmop);
  31. public
  32. procedure WriteTree(p:taasmoutput);override;
  33. procedure WriteAsmList;override;
  34. procedure WriteExternals;
  35. end;
  36. implementation
  37. uses
  38. {$ifdef delphi}
  39. sysutils,
  40. {$endif}
  41. cutils,globtype,globals,systems,cclasses,
  42. fmodule,finput,verbose,cpuinfo,cgbase
  43. ;
  44. const
  45. line_length = 64;
  46. nasm_regname_table : array[tregisterindex] of string[7] = (
  47. {r386nasm.inc contains the Nasm name of each register.}
  48. {$i r386nasm.inc}
  49. );
  50. var
  51. lastfileinfo : tfileposinfo;
  52. infile,
  53. lastinfile : tinputfile;
  54. function nasm_regname(r:Tregister):string;
  55. var
  56. p : tregisterindex;
  57. begin
  58. p:=findreg_by_number(r);
  59. if p<>0 then
  60. result:=nasm_regname_table[p]
  61. else
  62. result:=generic_regname(r);
  63. end;
  64. function fixline(s:string):string;
  65. {
  66. return s with all leading and ending spaces and tabs removed
  67. }
  68. var
  69. i,j,k : longint;
  70. begin
  71. i:=length(s);
  72. while (i>0) and (s[i] in [#9,' ']) do
  73. dec(i);
  74. j:=1;
  75. while (j<i) and (s[j] in [#9,' ']) do
  76. inc(j);
  77. for k:=j to i do
  78. if s[k] in [#0..#31,#127..#255] then
  79. s[k]:='.';
  80. fixline:=Copy(s,j,i-j+1);
  81. end;
  82. function single2str(d : single) : string;
  83. var
  84. hs : string;
  85. p : byte;
  86. begin
  87. str(d,hs);
  88. { nasm expects a lowercase e }
  89. p:=pos('E',hs);
  90. if p>0 then
  91. hs[p]:='e';
  92. p:=pos('+',hs);
  93. if p>0 then
  94. delete(hs,p,1);
  95. single2str:=lower(hs);
  96. end;
  97. function double2str(d : double) : string;
  98. var
  99. hs : string;
  100. p : byte;
  101. begin
  102. str(d,hs);
  103. { nasm expects a lowercase e }
  104. p:=pos('E',hs);
  105. if p>0 then
  106. hs[p]:='e';
  107. p:=pos('+',hs);
  108. if p>0 then
  109. delete(hs,p,1);
  110. double2str:=lower(hs);
  111. end;
  112. function extended2str(e : extended) : string;
  113. var
  114. hs : string;
  115. p : byte;
  116. begin
  117. str(e,hs);
  118. { nasm expects a lowercase e }
  119. p:=pos('E',hs);
  120. if p>0 then
  121. hs[p]:='e';
  122. p:=pos('+',hs);
  123. if p>0 then
  124. delete(hs,p,1);
  125. extended2str:=lower(hs);
  126. end;
  127. function comp2str(d : bestreal) : string;
  128. type
  129. pdouble = ^double;
  130. var
  131. c : comp;
  132. dd : pdouble;
  133. begin
  134. {$ifdef FPC}
  135. c:=comp(d);
  136. {$else}
  137. c:=d;
  138. {$endif}
  139. dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
  140. comp2str:=double2str(dd^);
  141. end;
  142. function sizestr(s:topsize;dest:boolean):string;
  143. begin
  144. case s of
  145. S_B : sizestr:='byte ';
  146. S_W : sizestr:='word ';
  147. S_L : sizestr:='dword ';
  148. S_IS : sizestr:='word ';
  149. S_IL : sizestr:='dword ';
  150. S_IQ : sizestr:='qword ';
  151. S_FS : sizestr:='dword ';
  152. S_FL : sizestr:='qword ';
  153. S_FX : sizestr:='tword ';
  154. S_BW : if dest then
  155. sizestr:='word '
  156. else
  157. sizestr:='byte ';
  158. S_BL : if dest then
  159. sizestr:='dword '
  160. else
  161. sizestr:='byte ';
  162. S_WL : if dest then
  163. sizestr:='dword '
  164. else
  165. sizestr:='word ';
  166. else { S_NO }
  167. sizestr:='';
  168. end;
  169. end;
  170. Function PadTabs(const p:string;addch:char):string;
  171. var
  172. s : string;
  173. i : longint;
  174. begin
  175. i:=length(p);
  176. if addch<>#0 then
  177. begin
  178. inc(i);
  179. s:=p+addch;
  180. end
  181. else
  182. s:=p;
  183. if i<8 then
  184. PadTabs:=s+#9#9
  185. else
  186. PadTabs:=s+#9;
  187. end;
  188. {****************************************************************************
  189. T386NasmAssembler
  190. ****************************************************************************}
  191. procedure T386NasmAssembler.WriteReference(var ref : treference);
  192. var
  193. first : boolean;
  194. begin
  195. with ref do
  196. begin
  197. AsmWrite('[');
  198. first:=true;
  199. if (segment<>NR_NO) then
  200. AsmWrite(nasm_regname(segment)+':');
  201. if assigned(symbol) then
  202. begin
  203. AsmWrite(symbol.name);
  204. first:=false;
  205. end;
  206. if (base<>NR_NO) then
  207. begin
  208. if not(first) then
  209. AsmWrite('+')
  210. else
  211. first:=false;
  212. AsmWrite(nasm_regname(base))
  213. end;
  214. if (index<>NR_NO) then
  215. begin
  216. if not(first) then
  217. AsmWrite('+')
  218. else
  219. first:=false;
  220. AsmWrite(nasm_regname(index));
  221. if scalefactor<>0 then
  222. AsmWrite('*'+tostr(scalefactor));
  223. end;
  224. if offset<0 then
  225. begin
  226. AsmWrite(tostr(offset));
  227. first:=false;
  228. end
  229. else if (offset>0) then
  230. begin
  231. AsmWrite('+'+tostr(offset));
  232. first:=false;
  233. end;
  234. if first then
  235. AsmWrite('0');
  236. AsmWrite(']');
  237. end;
  238. end;
  239. procedure T386NasmAssembler.WriteOper(const o:toper;s : topsize; opcode: tasmop;ops:longint;dest : boolean);
  240. begin
  241. case o.typ of
  242. top_reg :
  243. AsmWrite(nasm_regname(o.reg));
  244. top_const :
  245. begin
  246. if (ops=1) and (opcode<>A_RET) then
  247. AsmWrite(sizestr(s,dest));
  248. AsmWrite(tostr(longint(o.val)));
  249. end;
  250. top_symbol :
  251. begin
  252. asmwrite('dword ');
  253. if assigned(o.sym) then
  254. begin
  255. asmwrite(o.sym.name);
  256. if o.symofs=0 then
  257. exit;
  258. end;
  259. if o.symofs>0 then
  260. asmwrite('+');
  261. asmwrite(tostr(o.symofs))
  262. end;
  263. top_ref :
  264. begin
  265. if not ((opcode = A_LEA) or (opcode = A_LGS) or
  266. (opcode = A_LSS) or (opcode = A_LFS) or
  267. (opcode = A_LES) or (opcode = A_LDS) or
  268. (opcode = A_SHR) or (opcode = A_SHL) or
  269. (opcode = A_SAR) or (opcode = A_SAL) or
  270. (opcode = A_OUT) or (opcode = A_IN)) then
  271. AsmWrite(sizestr(s,dest));
  272. WriteReference(o.ref^);
  273. end;
  274. else
  275. internalerror(10001);
  276. end;
  277. end;
  278. procedure T386NasmAssembler.WriteOper_jmp(const o:toper; op : tasmop);
  279. begin
  280. case o.typ of
  281. top_reg :
  282. AsmWrite(nasm_regname(o.reg));
  283. top_ref :
  284. WriteReference(o.ref^);
  285. top_const :
  286. AsmWrite(tostr(longint(o.val)));
  287. top_symbol :
  288. begin
  289. if not(
  290. (op=A_JCXZ) or (op=A_JECXZ) or
  291. (op=A_LOOP) or (op=A_LOOPE) or
  292. (op=A_LOOPNE) or (op=A_LOOPNZ) or
  293. (op=A_LOOPZ)
  294. ) then
  295. AsmWrite('NEAR ');
  296. AsmWrite(o.sym.name);
  297. if o.symofs>0 then
  298. AsmWrite('+'+tostr(o.symofs))
  299. else
  300. if o.symofs<0 then
  301. AsmWrite(tostr(o.symofs));
  302. end;
  303. else
  304. internalerror(10001);
  305. end;
  306. end;
  307. var
  308. LasTSec : TSection;
  309. const
  310. ait_const2str:array[ait_const_32bit..ait_const_8bit] of string[8]=
  311. (#9'DD'#9,#9'DW'#9,#9'DB'#9);
  312. procedure T386NasmAssembler.WriteTree(p:taasmoutput);
  313. const
  314. allocstr : array[boolean] of string[10]=(' released',' allocated');
  315. var
  316. s : string;
  317. hp : tai;
  318. hp1 : tailineinfo;
  319. counter,
  320. lines,
  321. i,j,l : longint;
  322. InlineLevel : longint;
  323. consttyp : taitype;
  324. found,
  325. do_line,
  326. quoted : boolean;
  327. begin
  328. if not assigned(p) then
  329. exit;
  330. InlineLevel:=0;
  331. { lineinfo is only needed for codesegment (PFV) }
  332. do_line:=(cs_asm_source in aktglobalswitches) or
  333. ((cs_lineinfo in aktmoduleswitches)
  334. and (p=codesegment));
  335. hp:=tai(p.first);
  336. while assigned(hp) do
  337. begin
  338. if not(hp.typ in SkipLineInfo) then
  339. begin
  340. hp1:=hp as tailineinfo;
  341. aktfilepos:=hp1.fileinfo;
  342. if do_line then
  343. begin
  344. { load infile }
  345. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  346. begin
  347. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  348. if assigned(infile) then
  349. begin
  350. { open only if needed !! }
  351. if (cs_asm_source in aktglobalswitches) then
  352. infile.open;
  353. end;
  354. { avoid unnecessary reopens of the same file !! }
  355. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  356. { be sure to change line !! }
  357. lastfileinfo.line:=-1;
  358. end;
  359. { write source }
  360. if (cs_asm_source in aktglobalswitches) and
  361. assigned(infile) then
  362. begin
  363. if (infile<>lastinfile) then
  364. begin
  365. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  366. if assigned(lastinfile) then
  367. lastinfile.close;
  368. end;
  369. if (hp1.fileinfo.line<>lastfileinfo.line) and
  370. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  371. begin
  372. if (hp1.fileinfo.line<>0) and
  373. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  374. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  375. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  376. { set it to a negative value !
  377. to make that is has been read already !! PM }
  378. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  379. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  380. end;
  381. end;
  382. lastfileinfo:=hp1.fileinfo;
  383. lastinfile:=infile;
  384. end;
  385. end;
  386. case hp.typ of
  387. ait_comment :
  388. Begin
  389. AsmWrite(target_asm.comment);
  390. AsmWritePChar(tai_comment(hp).str);
  391. AsmLn;
  392. End;
  393. ait_regalloc :
  394. begin
  395. if (cs_asm_regalloc in aktglobalswitches) then
  396. AsmWriteLn(#9#9+target_asm.comment+'Register '+nasm_regname(tai_regalloc(hp).reg)+
  397. allocstr[tai_regalloc(hp).allocation]);
  398. end;
  399. ait_tempalloc :
  400. begin
  401. if (cs_asm_tempalloc in aktglobalswitches) then
  402. begin
  403. {$ifdef EXTDEBUG}
  404. if assigned(tai_tempalloc(hp).problem) then
  405. AsmWriteLn(target_asm.comment+tai_tempalloc(hp).problem^+' ('+tostr(tai_tempalloc(hp).temppos)+','+
  406. tostr(tai_tempalloc(hp).tempsize)+')')
  407. else
  408. {$endif EXTDEBUG}
  409. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  410. tostr(tai_tempalloc(hp).tempsize)+allocstr[tai_tempalloc(hp).allocation]);
  411. end;
  412. end;
  413. ait_section :
  414. begin
  415. if tai_section(hp).sec<>sec_none then
  416. begin
  417. AsmLn;
  418. AsmWriteLn('SECTION '+target_asm.secnames[tai_section(hp).sec]);
  419. end;
  420. LasTSec:=tai_section(hp).sec;
  421. end;
  422. ait_align :
  423. begin
  424. { nasm gives warnings when it finds align in bss as it
  425. wants to store data }
  426. if lastsec<>sec_bss then
  427. AsmWriteLn(#9'ALIGN '+tostr(tai_align(hp).aligntype));
  428. end;
  429. ait_datablock :
  430. begin
  431. if tai_datablock(hp).is_global then
  432. begin
  433. AsmWrite(#9'GLOBAL ');
  434. AsmWriteLn(tai_datablock(hp).sym.name);
  435. end;
  436. AsmWrite(PadTabs(tai_datablock(hp).sym.name,':'));
  437. AsmWriteLn('RESB'#9+tostr(tai_datablock(hp).size));
  438. end;
  439. ait_const_32bit,
  440. ait_const_16bit,
  441. ait_const_8bit :
  442. begin
  443. AsmWrite(ait_const2str[hp.typ]+tostr(tai_const(hp).value));
  444. consttyp:=hp.typ;
  445. l:=0;
  446. repeat
  447. found:=(not (tai(hp.next)=nil)) and (tai(hp.next).typ=consttyp);
  448. if found then
  449. begin
  450. hp:=tai(hp.next);
  451. s:=','+tostr(tai_const(hp).value);
  452. AsmWrite(s);
  453. inc(l,length(s));
  454. end;
  455. until (not found) or (l>line_length);
  456. AsmLn;
  457. end;
  458. ait_const_symbol :
  459. begin
  460. AsmWrite(#9#9'DD'#9);
  461. AsmWrite(tai_const_symbol(hp).sym.name);
  462. if tai_const_symbol(hp).offset>0 then
  463. AsmWrite('+'+tostr(tai_const_symbol(hp).offset))
  464. else if tai_const_symbol(hp).offset<0 then
  465. AsmWrite(tostr(tai_const_symbol(hp).offset));
  466. AsmLn;
  467. end;
  468. ait_const_rva :
  469. begin
  470. AsmWrite(#9#9'RVA'#9);
  471. AsmWriteLn(tai_const_symbol(hp).sym.name);
  472. end;
  473. ait_real_32bit :
  474. AsmWriteLn(#9#9'DD'#9+single2str(tai_real_32bit(hp).value));
  475. ait_real_64bit :
  476. AsmWriteLn(#9#9'DQ'#9+double2str(tai_real_64bit(hp).value));
  477. ait_real_80bit :
  478. AsmWriteLn(#9#9'DT'#9+extended2str(tai_real_80bit(hp).value));
  479. ait_comp_64bit :
  480. AsmWriteLn(#9#9'DQ'#9+comp2str(tai_real_80bit(hp).value));
  481. ait_string :
  482. begin
  483. counter := 0;
  484. lines := tai_string(hp).len div line_length;
  485. { separate lines in different parts }
  486. if tai_string(hp).len > 0 then
  487. Begin
  488. for j := 0 to lines-1 do
  489. begin
  490. AsmWrite(#9#9'DB'#9);
  491. quoted:=false;
  492. for i:=counter to counter+line_length-1 do
  493. begin
  494. { it is an ascii character. }
  495. if (ord(tai_string(hp).str[i])>31) and
  496. (ord(tai_string(hp).str[i])<128) and
  497. (tai_string(hp).str[i]<>'"') then
  498. begin
  499. if not(quoted) then
  500. begin
  501. if i>counter then
  502. AsmWrite(',');
  503. AsmWrite('"');
  504. end;
  505. AsmWrite(tai_string(hp).str[i]);
  506. quoted:=true;
  507. end { if > 31 and < 128 and ord('"') }
  508. else
  509. begin
  510. if quoted then
  511. AsmWrite('"');
  512. if i>counter then
  513. AsmWrite(',');
  514. quoted:=false;
  515. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  516. end;
  517. end; { end for i:=0 to... }
  518. if quoted then AsmWrite('"');
  519. AsmWrite(target_info.newline);
  520. inc(counter,line_length);
  521. end; { end for j:=0 ... }
  522. { do last line of lines }
  523. if counter<tai_string(hp).len then
  524. AsmWrite(#9#9'DB'#9);
  525. quoted:=false;
  526. for i:=counter to tai_string(hp).len-1 do
  527. begin
  528. { it is an ascii character. }
  529. if (ord(tai_string(hp).str[i])>31) and
  530. (ord(tai_string(hp).str[i])<128) and
  531. (tai_string(hp).str[i]<>'"') then
  532. begin
  533. if not(quoted) then
  534. begin
  535. if i>counter then
  536. AsmWrite(',');
  537. AsmWrite('"');
  538. end;
  539. AsmWrite(tai_string(hp).str[i]);
  540. quoted:=true;
  541. end { if > 31 and < 128 and " }
  542. else
  543. begin
  544. if quoted then
  545. AsmWrite('"');
  546. if i>counter then
  547. AsmWrite(',');
  548. quoted:=false;
  549. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  550. end;
  551. end; { end for i:=0 to... }
  552. if quoted then
  553. AsmWrite('"');
  554. end;
  555. AsmLn;
  556. end;
  557. ait_label :
  558. begin
  559. if tai_label(hp).l.is_used then
  560. AsmWriteLn(tai_label(hp).l.name+':');
  561. end;
  562. ait_direct :
  563. begin
  564. AsmWritePChar(tai_direct(hp).str);
  565. AsmLn;
  566. end;
  567. ait_symbol :
  568. begin
  569. if tai_symbol(hp).is_global then
  570. begin
  571. AsmWrite(#9'GLOBAL ');
  572. AsmWriteLn(tai_symbol(hp).sym.name);
  573. end;
  574. AsmWrite(tai_symbol(hp).sym.name);
  575. if assigned(hp.next) and not(tai(hp.next).typ in
  576. [ait_const_32bit,ait_const_16bit,ait_const_8bit,
  577. ait_const_symbol,ait_const_rva,
  578. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  579. AsmWriteLn(':')
  580. end;
  581. ait_symbol_end : ;
  582. ait_instruction :
  583. begin
  584. taicpu(hp).CheckNonCommutativeOpcodes;
  585. { We need intel order, no At&t }
  586. taicpu(hp).SetOperandOrder(op_intel);
  587. s:='';
  588. if ((taicpu(hp).opcode=A_FADDP) or
  589. (taicpu(hp).opcode=A_FMULP))
  590. and (taicpu(hp).ops=0) then
  591. begin
  592. taicpu(hp).allocate_oper(2);
  593. taicpu(hp).oper[0]^.typ:=top_reg;
  594. taicpu(hp).oper[0]^.reg:=NR_ST1;
  595. taicpu(hp).oper[1]^.typ:=top_reg;
  596. taicpu(hp).oper[1]^.reg:=NR_ST;
  597. end;
  598. if taicpu(hp).opcode=A_FWAIT then
  599. AsmWriteln(#9#9'DB'#9'09bh')
  600. else
  601. begin
  602. { We need to explicitely set
  603. word prefix to get selectors
  604. to be pushed in 2 bytes PM }
  605. if (taicpu(hp).opsize=S_W) and
  606. ((taicpu(hp).opcode=A_PUSH) or
  607. (taicpu(hp).opcode=A_POP)) and
  608. (taicpu(hp).oper[0]^.typ=top_reg) and
  609. (is_segment_reg(taicpu(hp).oper[0]^.reg)) then
  610. AsmWriteln(#9#9'DB'#9'066h');
  611. AsmWrite(#9#9+std_op2str[taicpu(hp).opcode]+cond2str[taicpu(hp).condition]);
  612. if taicpu(hp).ops<>0 then
  613. begin
  614. if is_calljmp(taicpu(hp).opcode) then
  615. begin
  616. AsmWrite(#9);
  617. WriteOper_jmp(taicpu(hp).oper[0]^,taicpu(hp).opcode);
  618. end
  619. else
  620. begin
  621. for i:=0 to taicpu(hp).ops-1 do
  622. begin
  623. if i=0 then
  624. AsmWrite(#9)
  625. else
  626. AsmWrite(',');
  627. WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,taicpu(hp).opcode,taicpu(hp).ops,(i=2));
  628. end;
  629. end;
  630. end;
  631. AsmLn;
  632. end;
  633. end;
  634. {$ifdef GDB}
  635. ait_stabn,
  636. ait_stabs,
  637. ait_force_line,
  638. ait_stab_function_name : ;
  639. {$endif GDB}
  640. ait_cut :
  641. begin
  642. { only reset buffer if nothing has changed }
  643. if AsmSize=AsmStartSize then
  644. AsmClear
  645. else
  646. begin
  647. AsmClose;
  648. DoAssemble;
  649. AsmCreate(tai_cut(hp).place);
  650. end;
  651. { avoid empty files }
  652. while assigned(hp.next) and (tai(hp.next).typ in [ait_cut,ait_section,ait_comment]) do
  653. begin
  654. if tai(hp.next).typ=ait_section then
  655. lasTSec:=tai_section(hp.next).sec;
  656. hp:=tai(hp.next);
  657. end;
  658. if lasTSec<>sec_none then
  659. AsmWriteLn('SECTION '+target_asm.secnames[lasTSec]);
  660. AsmStartSize:=AsmSize;
  661. end;
  662. ait_marker :
  663. if tai_marker(hp).kind=InlineStart then
  664. inc(InlineLevel)
  665. else if tai_marker(hp).kind=InlineEnd then
  666. dec(InlineLevel);
  667. else
  668. internalerror(10000);
  669. end;
  670. hp:=tai(hp.next);
  671. end;
  672. end;
  673. var
  674. currentasmlist : TExternalAssembler;
  675. procedure writeexternal(p:tnamedindexitem;arg:pointer);
  676. begin
  677. if tasmsymbol(p).defbind=AB_EXTERNAL then
  678. currentasmlist.AsmWriteln('EXTERN'#9+p.name);
  679. end;
  680. procedure T386NasmAssembler.WriteExternals;
  681. begin
  682. currentasmlist:=self;
  683. objectlibrary.symbolsearch.foreach_static({$ifdef fpcprocvar}@{$endif}writeexternal,nil);
  684. end;
  685. procedure T386NasmAssembler.WriteAsmList;
  686. begin
  687. {$ifdef EXTDEBUG}
  688. if assigned(current_module.mainsource) then
  689. comment(v_info,'Start writing nasm-styled assembler output for '+current_module.mainsource^);
  690. {$endif}
  691. LasTSec:=sec_none;
  692. AsmWriteLn('BITS 32');
  693. AsmLn;
  694. lastfileinfo.line:=-1;
  695. lastfileinfo.fileindex:=0;
  696. lastinfile:=nil;
  697. WriteExternals;
  698. { Nasm doesn't support stabs
  699. WriteTree(debuglist);}
  700. WriteTree(codesegment);
  701. WriteTree(datasegment);
  702. WriteTree(consts);
  703. WriteTree(rttilist);
  704. WriteTree(resourcestringlist);
  705. WriteTree(bsssegment);
  706. Writetree(importssection);
  707. { exports are written by DLLTOOL
  708. if we use it so don't insert it twice (PM) }
  709. if not UseDeffileForExport and assigned(exportssection) then
  710. Writetree(exportssection);
  711. Writetree(resourcesection);
  712. AsmLn;
  713. {$ifdef EXTDEBUG}
  714. if assigned(current_module.mainsource) then
  715. comment(v_info,'Done writing nasm-styled assembler output for '+current_module.mainsource^);
  716. {$endif EXTDEBUG}
  717. end;
  718. {*****************************************************************************
  719. Initialize
  720. *****************************************************************************}
  721. const
  722. as_i386_nasmcoff_info : tasminfo =
  723. (
  724. id : as_i386_nasmcoff;
  725. idtxt : 'NASMCOFF';
  726. asmbin : 'nasm';
  727. asmcmd : '-f coff -o $OBJ $ASM';
  728. supported_target : system_i386_go32v2;
  729. outputbinary: false;
  730. allowdirect : true;
  731. needar : true;
  732. labelprefix_only_inside_procedure: false;
  733. labelprefix : '..@';
  734. comment : '; ';
  735. secnames : ('',
  736. '.text','.data','.bss',
  737. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  738. '.stab','.stabstr','')
  739. );
  740. as_i386_nasmwin32_info : tasminfo =
  741. (
  742. id : as_i386_nasmwin32;
  743. idtxt : 'NASMWIN32';
  744. asmbin : 'nasm';
  745. asmcmd : '-f win32 -o $OBJ $ASM';
  746. supported_target : system_i386_win32;
  747. outputbinary: false;
  748. allowdirect : true;
  749. needar : true;
  750. labelprefix_only_inside_procedure: false;
  751. labelprefix : '..@';
  752. comment : '; ';
  753. secnames : ('',
  754. '.text','.data','.bss',
  755. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  756. '.stab','.stabstr','')
  757. );
  758. as_i386_nasmobj_info : tasminfo =
  759. (
  760. id : as_i386_nasmobj;
  761. idtxt : 'NASMOBJ';
  762. asmbin : 'nasm';
  763. asmcmd : '-f obj -o $OBJ $ASM';
  764. supported_target : system_any; { what should I write here ?? }
  765. outputbinary: false;
  766. allowdirect : true;
  767. needar : true;
  768. labelprefix_only_inside_procedure: false;
  769. labelprefix : '..@';
  770. comment : '; ';
  771. secnames : ('',
  772. '.text','.data','.bss',
  773. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  774. '.stab','.stabstr','')
  775. );
  776. as_i386_nasmwdosx_info : tasminfo =
  777. (
  778. id : as_i386_nasmwdosx;
  779. idtxt : 'NASMWDOSX';
  780. asmbin : 'nasm';
  781. asmcmd : '-f win32 -o $OBJ $ASM';
  782. supported_target : system_i386_wdosx;
  783. outputbinary: false;
  784. allowdirect : true;
  785. needar : true;
  786. labelprefix_only_inside_procedure: false;
  787. labelprefix : '..@';
  788. comment : '; ';
  789. secnames : ('',
  790. '.text','.data','.bss',
  791. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  792. '.stab','.stabstr','')
  793. );
  794. as_i386_nasmelf_info : tasminfo =
  795. (
  796. id : as_i386_nasmelf;
  797. idtxt : 'NASMELF';
  798. asmbin : 'nasm';
  799. asmcmd : '-f elf -o $OBJ $ASM';
  800. supported_target : system_i386_linux;
  801. outputbinary: false;
  802. allowdirect : true;
  803. needar : true;
  804. labelprefix_only_inside_procedure: false;
  805. labelprefix : '..@';
  806. comment : '; ';
  807. secnames : ('',
  808. '.text','.data','.bss',
  809. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  810. '.stab','.stabstr','')
  811. );
  812. as_i386_nasmbeos_info : tasminfo =
  813. (
  814. id : as_i386_nasmbeos;
  815. idtxt : 'NASMELF';
  816. asmbin : 'nasm';
  817. asmcmd : '-f elf -o $OBJ $ASM';
  818. supported_target : system_i386_beos;
  819. outputbinary: false;
  820. allowdirect : true;
  821. needar : true;
  822. labelprefix_only_inside_procedure: false;
  823. labelprefix : '..@';
  824. comment : '; ';
  825. secnames : ('',
  826. '.text','.data','.bss',
  827. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  828. '.stab','.stabstr','')
  829. );
  830. initialization
  831. RegisterAssembler(as_i386_nasmcoff_info,T386NasmAssembler);
  832. RegisterAssembler(as_i386_nasmwin32_info,T386NasmAssembler);
  833. RegisterAssembler(as_i386_nasmwdosx_info,T386NasmAssembler);
  834. RegisterAssembler(as_i386_nasmobj_info,T386NasmAssembler);
  835. RegisterAssembler(as_i386_nasmbeos_info,T386NasmAssembler);
  836. RegisterAssembler(as_i386_nasmelf_info,T386NasmAssembler);
  837. end.
  838. {
  839. $Log$
  840. Revision 1.42 2003-11-29 15:53:06 florian
  841. + nasmelf mode for BeOS
  842. + DQWORD directive in intel assembler mode
  843. Revision 1.41 2003/10/21 15:15:36 peter
  844. * taicpu_abstract.oper[] changed to pointers
  845. Revision 1.40 2003/10/01 20:34:49 peter
  846. * procinfo unit contains tprocinfo
  847. * cginfo renamed to cgbase
  848. * moved cgmessage to verbose
  849. * fixed ppc and sparc compiles
  850. Revision 1.39 2003/09/23 17:56:06 peter
  851. * locals and paras are allocated in the code generation
  852. * tvarsym.localloc contains the location of para/local when
  853. generating code for the current procedure
  854. Revision 1.38 2003/09/03 15:55:01 peter
  855. * NEWRA branch merged
  856. Revision 1.37.2.1 2003/08/31 15:46:26 peter
  857. * more updates for tregister
  858. Revision 1.37 2003/08/09 18:56:54 daniel
  859. * cs_regalloc renamed to cs_regvars to avoid confusion with register
  860. allocator
  861. * Some preventive changes to i386 spillinh code
  862. Revision 1.36 2003/07/06 15:31:21 daniel
  863. * Fixed register allocator. *Lots* of fixes.
  864. Revision 1.35 2003/06/03 13:01:59 daniel
  865. * Register allocator finished
  866. Revision 1.34 2003/05/26 19:37:57 peter
  867. * don't generate align in .bss
  868. Revision 1.33 2003/04/22 10:09:35 daniel
  869. + Implemented the actual register allocator
  870. + Scratch registers unavailable when new register allocator used
  871. + maybe_save/maybe_restore unavailable when new register allocator used
  872. Revision 1.32 2003/03/08 13:59:17 daniel
  873. * Work to handle new register notation in ag386nsm
  874. + Added newra version of Ti386moddivnode
  875. Revision 1.31 2003/03/08 08:59:07 daniel
  876. + $define newra will enable new register allocator
  877. + getregisterint will return imaginary registers with $newra
  878. + -sr switch added, will skip register allocation so you can see
  879. the direct output of the code generator before register allocation
  880. Revision 1.30 2003/01/08 18:43:57 daniel
  881. * Tregister changed into a record
  882. Revision 1.29 2002/12/24 18:10:34 peter
  883. * Long symbol names support
  884. Revision 1.28 2002/11/17 16:31:59 carl
  885. * memory optimization (3-4%) : cleanup of tai fields,
  886. cleanup of tdef and tsym fields.
  887. * make it work for m68k
  888. Revision 1.27 2002/11/15 01:58:56 peter
  889. * merged changes from 1.0.7 up to 04-11
  890. - -V option for generating bug report tracing
  891. - more tracing for option parsing
  892. - errors for cdecl and high()
  893. - win32 import stabs
  894. - win32 records<=8 are returned in eax:edx (turned off by default)
  895. - heaptrc update
  896. - more info for temp management in .s file with EXTDEBUG
  897. Revision 1.26 2002/08/18 20:06:28 peter
  898. * inlining is now also allowed in interface
  899. * renamed write/load to ppuwrite/ppuload
  900. * tnode storing in ppu
  901. * nld,ncon,nbas are already updated for storing in ppu
  902. Revision 1.25 2002/08/12 15:08:41 carl
  903. + stab register indexes for powerpc (moved from gdb to cpubase)
  904. + tprocessor enumeration moved to cpuinfo
  905. + linker in target_info is now a class
  906. * many many updates for m68k (will soon start to compile)
  907. - removed some ifdef or correct them for correct cpu
  908. Revision 1.24 2002/08/11 14:32:29 peter
  909. * renamed current_library to objectlibrary
  910. Revision 1.23 2002/08/11 13:24:16 peter
  911. * saving of asmsymbols in ppu supported
  912. * asmsymbollist global is removed and moved into a new class
  913. tasmlibrarydata that will hold the info of a .a file which
  914. corresponds with a single module. Added librarydata to tmodule
  915. to keep the library info stored for the module. In the future the
  916. objectfiles will also be stored to the tasmlibrarydata class
  917. * all getlabel/newasmsymbol and friends are moved to the new class
  918. Revision 1.22 2002/07/26 21:15:43 florian
  919. * rewrote the system handling
  920. Revision 1.21 2002/07/01 18:46:29 peter
  921. * internal linker
  922. * reorganized aasm layer
  923. Revision 1.20 2002/05/18 13:34:21 peter
  924. * readded missing revisions
  925. Revision 1.19 2002/05/16 19:46:50 carl
  926. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  927. + try to fix temp allocation (still in ifdef)
  928. + generic constructor calls
  929. + start of tassembler / tmodulebase class cleanup
  930. Revision 1.17 2002/05/12 16:53:16 peter
  931. * moved entry and exitcode to ncgutil and cgobj
  932. * foreach gets extra argument for passing local data to the
  933. iterator function
  934. * -CR checks also class typecasts at runtime by changing them
  935. into as
  936. * fixed compiler to cycle with the -CR option
  937. * fixed stabs with elf writer, finally the global variables can
  938. be watched
  939. * removed a lot of routines from cga unit and replaced them by
  940. calls to cgobj
  941. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  942. u32bit then the other is typecasted also to u32bit without giving
  943. a rangecheck warning/error.
  944. * fixed pascal calling method with reversing also the high tree in
  945. the parast, detected by tcalcst3 test
  946. Revision 1.16 2002/04/15 19:12:09 carl
  947. + target_info.size_of_pointer -> pointer_size
  948. + some cleanup of unused types/variables
  949. * move several constants from cpubase to their specific units
  950. (where they are used)
  951. + att_Reg2str -> gas_reg2str
  952. + int_reg2str -> std_reg2str
  953. Revision 1.15 2002/04/14 16:58:41 carl
  954. + att_reg2str -> gas_reg2str
  955. Revision 1.14 2002/04/04 18:27:37 carl
  956. + added wdosx support (patch from Pavel)
  957. Revision 1.13 2002/04/02 17:11:33 peter
  958. * tlocation,treference update
  959. * LOC_CONSTANT added for better constant handling
  960. * secondadd splitted in multiple routines
  961. * location_force_reg added for loading a location to a register
  962. of a specified size
  963. * secondassignment parses now first the right and then the left node
  964. (this is compatible with Kylix). This saves a lot of push/pop especially
  965. with string operations
  966. * adapted some routines to use the new cg methods
  967. }