ag386nsm.pas 34 KB

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