agx86int.pas 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements an asmoutput class for Intel syntax with Intel i386+
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. {
  18. This unit implements an asmoutput class for Intel syntax with Intel i386+
  19. }
  20. unit agx86int;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. cpubase,
  25. aasmbase,aasmtai,aasmcpu,assemble,cgutils;
  26. type
  27. Tx86IntelAssembler = class(TExternalAssembler)
  28. private
  29. procedure WriteReference(var ref : treference);
  30. procedure WriteOper(const o:toper;s : topsize; opcode: tasmop;dest : boolean);
  31. procedure WriteOper_jmp(const o:toper;s : topsize);
  32. public
  33. procedure WriteTree(p:TAAsmoutput);override;
  34. procedure WriteAsmList;override;
  35. Function DoAssemble:boolean;override;
  36. procedure WriteExternals;
  37. end;
  38. implementation
  39. uses
  40. cutils,globtype,globals,systems,cclasses,
  41. verbose,finput,fmodule,script,cpuinfo,
  42. itx86int,
  43. cgbase
  44. ;
  45. const
  46. line_length = 70;
  47. secnames : array[TAsmSectionType] of string[4] = ('',
  48. 'CODE','DATA','DATA','BSS','',
  49. '','','','','','','',
  50. '','','','','','','',
  51. ''
  52. );
  53. secnamesml64 : array[TAsmSectionType] of string[7] = ('',
  54. '_TEXT','_DATE','_DATA','_BSS','',
  55. '','','','','',
  56. 'idata$2','idata$4','idata$5','idata$6','idata$7','edata',
  57. '','','',''
  58. );
  59. function single2str(d : single) : string;
  60. var
  61. hs : string;
  62. p : byte;
  63. begin
  64. str(d,hs);
  65. { nasm expects a lowercase e }
  66. p:=pos('E',hs);
  67. if p>0 then
  68. hs[p]:='e';
  69. p:=pos('+',hs);
  70. if p>0 then
  71. delete(hs,p,1);
  72. single2str:=lower(hs);
  73. end;
  74. function double2str(d : double) : string;
  75. var
  76. hs : string;
  77. p : byte;
  78. begin
  79. str(d,hs);
  80. { nasm expects a lowercase e }
  81. p:=pos('E',hs);
  82. if p>0 then
  83. hs[p]:='e';
  84. p:=pos('+',hs);
  85. if p>0 then
  86. delete(hs,p,1);
  87. double2str:=lower(hs);
  88. end;
  89. function extended2str(e : extended) : string;
  90. var
  91. hs : string;
  92. p : byte;
  93. begin
  94. str(e,hs);
  95. { nasm expects a lowercase e }
  96. p:=pos('E',hs);
  97. if p>0 then
  98. hs[p]:='e';
  99. p:=pos('+',hs);
  100. if p>0 then
  101. delete(hs,p,1);
  102. extended2str:=lower(hs);
  103. end;
  104. function comp2str(d : bestreal) : string;
  105. type
  106. pdouble = ^double;
  107. var
  108. c : comp;
  109. dd : pdouble;
  110. begin
  111. {$ifdef FPC}
  112. c:=comp(d);
  113. {$else}
  114. c:=d;
  115. {$endif}
  116. dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
  117. comp2str:=double2str(dd^);
  118. end;
  119. function fixline(s:string):string;
  120. {
  121. return s with all leading and ending spaces and tabs removed
  122. }
  123. var
  124. i,j,k : longint;
  125. begin
  126. i:=length(s);
  127. while (i>0) and (s[i] in [#9,' ']) do
  128. dec(i);
  129. j:=1;
  130. while (j<i) and (s[j] in [#9,' ']) do
  131. inc(j);
  132. for k:=j to i do
  133. if s[k] in [#0..#31,#127..#255] then
  134. s[k]:='.';
  135. fixline:=Copy(s,j,i-j+1);
  136. end;
  137. {****************************************************************************
  138. tx86IntelAssembler
  139. ****************************************************************************}
  140. procedure tx86IntelAssembler.WriteReference(var ref : treference);
  141. var
  142. first : boolean;
  143. begin
  144. with ref do
  145. begin
  146. first:=true;
  147. if segment<>NR_NO then
  148. AsmWrite(masm_regname(segment)+':[')
  149. else
  150. AsmWrite('[');
  151. if assigned(symbol) then
  152. begin
  153. if (target_asm.id = as_i386_tasm) then
  154. AsmWrite('dword ptr ');
  155. AsmWrite(symbol.name);
  156. first:=false;
  157. end;
  158. if (base<>NR_NO) then
  159. begin
  160. if not(first) then
  161. AsmWrite('+')
  162. else
  163. first:=false;
  164. AsmWrite(masm_regname(base));
  165. end;
  166. if (index<>NR_NO) then
  167. begin
  168. if not(first) then
  169. AsmWrite('+')
  170. else
  171. first:=false;
  172. AsmWrite(masm_regname(index));
  173. if scalefactor<>0 then
  174. AsmWrite('*'+tostr(scalefactor));
  175. end;
  176. if offset<0 then
  177. begin
  178. AsmWrite(tostr(offset));
  179. first:=false;
  180. end
  181. else if (offset>0) then
  182. begin
  183. AsmWrite('+'+tostr(offset));
  184. first:=false;
  185. end;
  186. if first then
  187. AsmWrite('0');
  188. AsmWrite(']');
  189. end;
  190. end;
  191. procedure tx86IntelAssembler.WriteOper(const o:toper;s : topsize; opcode: tasmop;dest : boolean);
  192. begin
  193. case o.typ of
  194. top_reg :
  195. AsmWrite(masm_regname(o.reg));
  196. top_const :
  197. AsmWrite(tostr(longint(o.val)));
  198. top_ref :
  199. begin
  200. if o.ref^.refaddr=addr_no then
  201. begin
  202. if ((opcode <> A_LGS) and (opcode <> A_LSS) and
  203. (opcode <> A_LFS) and (opcode <> A_LDS) and
  204. (opcode <> A_LES)) then
  205. Begin
  206. case s of
  207. S_B : AsmWrite('byte ptr ');
  208. S_W : AsmWrite('word ptr ');
  209. S_L : AsmWrite('dword ptr ');
  210. S_Q : AsmWrite('qword ptr ');
  211. S_IS : AsmWrite('word ptr ');
  212. S_IL : AsmWrite('dword ptr ');
  213. S_IQ : AsmWrite('qword ptr ');
  214. S_FS : AsmWrite('dword ptr ');
  215. S_FL : AsmWrite('qword ptr ');
  216. S_T,
  217. S_FX : AsmWrite('tbyte ptr ');
  218. S_BW : if dest then
  219. AsmWrite('word ptr ')
  220. else
  221. AsmWrite('byte ptr ');
  222. S_BL : if dest then
  223. AsmWrite('dword ptr ')
  224. else
  225. AsmWrite('byte ptr ');
  226. S_WL : if dest then
  227. AsmWrite('dword ptr ')
  228. else
  229. AsmWrite('word ptr ');
  230. {$ifdef x86_64}
  231. S_BQ : if dest then
  232. AsmWrite('qword ptr ')
  233. else
  234. AsmWrite('byte ptr ');
  235. S_WQ : if dest then
  236. AsmWrite('qword ptr ')
  237. else
  238. AsmWrite('word ptr ');
  239. S_LQ : if dest then
  240. AsmWrite('qword ptr ')
  241. else
  242. AsmWrite('dword ptr ');
  243. S_XMM: AsmWrite('xmmword ptr ');
  244. {$endif x86_64}
  245. end;
  246. end;
  247. WriteReference(o.ref^);
  248. end
  249. else
  250. begin
  251. AsmWrite('offset ');
  252. if assigned(o.ref^.symbol) then
  253. AsmWrite(o.ref^.symbol.name);
  254. if o.ref^.offset>0 then
  255. AsmWrite('+'+tostr(o.ref^.offset))
  256. else
  257. if o.ref^.offset<0 then
  258. AsmWrite(tostr(o.ref^.offset))
  259. else
  260. if not(assigned(o.ref^.symbol)) then
  261. AsmWrite('0');
  262. end;
  263. end;
  264. else
  265. internalerror(2005060510);
  266. end;
  267. end;
  268. procedure tx86IntelAssembler.WriteOper_jmp(const o:toper;s : topsize);
  269. begin
  270. case o.typ of
  271. top_reg :
  272. AsmWrite(masm_regname(o.reg));
  273. top_const :
  274. AsmWrite(tostr(longint(o.val)));
  275. top_ref :
  276. { what about lcall or ljmp ??? }
  277. begin
  278. if o.ref^.refaddr=addr_no then
  279. begin
  280. if (target_asm.id <> as_i386_tasm) then
  281. begin
  282. if s=S_FAR then
  283. AsmWrite('far ptr ')
  284. else
  285. {$ifdef x86_64}
  286. AsmWrite('qword ptr ');
  287. {$else x86_64}
  288. AsmWrite('dword ptr ');
  289. {$endif x86_64}
  290. end;
  291. WriteReference(o.ref^);
  292. end
  293. else
  294. begin
  295. AsmWrite(o.ref^.symbol.name);
  296. if o.ref^.offset>0 then
  297. AsmWrite('+'+tostr(o.ref^.offset))
  298. else
  299. if o.ref^.offset<0 then
  300. AsmWrite(tostr(o.ref^.offset));
  301. end;
  302. end;
  303. else
  304. internalerror(2005060511);
  305. end;
  306. end;
  307. var
  308. LasTSectype : TAsmSectionType;
  309. lastfileinfo : tfileposinfo;
  310. infile,
  311. lastinfile : tinputfile;
  312. const
  313. ait_const2str : array[ait_const_128bit..ait_const_indirect_symbol] of string[20]=(
  314. #9''#9,#9'DQ'#9,#9'DD'#9,#9'DW'#9,#9'DB'#9,
  315. #9'FIXMESLEB',#9'FIXEMEULEB',
  316. #9'DD RVA'#9,#9'FIXMEINDIRECT'#9
  317. );
  318. Function PadTabs(const p:string;addch:char):string;
  319. var
  320. s : string;
  321. i : longint;
  322. begin
  323. i:=length(p);
  324. if addch<>#0 then
  325. begin
  326. inc(i);
  327. s:=p+addch;
  328. end
  329. else
  330. s:=p;
  331. if i<8 then
  332. PadTabs:=s+#9#9
  333. else
  334. PadTabs:=s+#9;
  335. end;
  336. procedure tx86IntelAssembler.WriteTree(p:TAAsmoutput);
  337. const
  338. regallocstr : array[tregalloctype] of string[10]=(' allocated',' released',' sync',' resized');
  339. tempallocstr : array[boolean] of string[10]=(' released',' allocated');
  340. var
  341. s,
  342. prefix,
  343. suffix : string;
  344. hp : tai;
  345. hp1 : tailineinfo;
  346. counter,
  347. lines,
  348. InlineLevel : longint;
  349. i,j,l : longint;
  350. consttyp : taitype;
  351. do_line,DoNotSplitLine,
  352. quoted : boolean;
  353. begin
  354. if not assigned(p) then
  355. exit;
  356. { lineinfo is only needed for al_procedures (PFV) }
  357. do_line:=((cs_asm_source in aktglobalswitches) or
  358. (cs_lineinfo in aktmoduleswitches))
  359. and (p=asmlist[al_procedures]);
  360. InlineLevel:=0;
  361. DoNotSplitLine:=false;
  362. hp:=tai(p.first);
  363. while assigned(hp) do
  364. begin
  365. if do_line and not(hp.typ in SkipLineInfo) and
  366. not DoNotSplitLine then
  367. begin
  368. hp1:=hp as tailineinfo;
  369. { load infile }
  370. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  371. begin
  372. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  373. if assigned(infile) then
  374. begin
  375. { open only if needed !! }
  376. if (cs_asm_source in aktglobalswitches) then
  377. infile.open;
  378. end;
  379. { avoid unnecessary reopens of the same file !! }
  380. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  381. { be sure to change line !! }
  382. lastfileinfo.line:=-1;
  383. end;
  384. { write source }
  385. if (cs_asm_source in aktglobalswitches) and
  386. assigned(infile) then
  387. begin
  388. if (infile<>lastinfile) then
  389. begin
  390. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  391. if assigned(lastinfile) then
  392. lastinfile.close;
  393. end;
  394. if (hp1.fileinfo.line<>lastfileinfo.line) and
  395. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  396. begin
  397. if (hp1.fileinfo.line<>0) and
  398. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  399. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  400. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  401. { set it to a negative value !
  402. to make that is has been read already !! PM }
  403. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  404. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  405. end;
  406. end;
  407. lastfileinfo:=hp1.fileinfo;
  408. lastinfile:=infile;
  409. end;
  410. DoNotSplitLine:=false;
  411. case hp.typ of
  412. ait_comment :
  413. Begin
  414. AsmWrite(target_asm.comment);
  415. AsmWritePChar(tai_comment(hp).str);
  416. AsmLn;
  417. End;
  418. ait_regalloc :
  419. begin
  420. if (cs_asm_regalloc in aktglobalswitches) then
  421. AsmWriteLn(target_asm.comment+'Register '+masm_regname(tai_regalloc(hp).reg)+
  422. regallocstr[tai_regalloc(hp).ratype]);
  423. end;
  424. ait_tempalloc :
  425. begin
  426. if (cs_asm_tempalloc in aktglobalswitches) then
  427. begin
  428. {$ifdef EXTDEBUG}
  429. if assigned(tai_tempalloc(hp).problem) then
  430. AsmWriteLn(target_asm.comment+tai_tempalloc(hp).problem^+' ('+tostr(tai_tempalloc(hp).temppos)+','+
  431. tostr(tai_tempalloc(hp).tempsize)+')')
  432. else
  433. {$endif EXTDEBUG}
  434. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  435. tostr(tai_tempalloc(hp).tempsize)+tempallocstr[tai_tempalloc(hp).allocation]);
  436. end;
  437. end;
  438. ait_section :
  439. begin
  440. if tai_section(hp).sectype<>sec_none then
  441. begin
  442. if target_asm.id=as_x86_64_masm then
  443. begin
  444. if LasTSecType<>sec_none then
  445. AsmWriteLn(secnamesml64[LasTSecType]+#9#9'ENDS');
  446. AsmLn;
  447. AsmWriteLn(secnamesml64[tai_section(hp).sectype]+#9+'SEGMENT')
  448. end
  449. else
  450. begin
  451. if LasTSecType<>sec_none then
  452. AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  453. AsmLn;
  454. AsmWriteLn('_'+secnames[tai_section(hp).sectype]+#9#9+
  455. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  456. secnames[tai_section(hp).sectype]+'''');
  457. end;
  458. end;
  459. LasTSecType:=tai_section(hp).sectype;
  460. end;
  461. ait_align :
  462. begin
  463. { CAUSES PROBLEMS WITH THE SEGMENT DEFINITION }
  464. { SEGMENT DEFINITION SHOULD MATCH TYPE OF ALIGN }
  465. { HERE UNDER TASM! }
  466. if tai_align(hp).aligntype>1 then
  467. AsmWriteLn(#9'ALIGN '+tostr(tai_align(hp).aligntype));
  468. end;
  469. ait_datablock :
  470. begin
  471. if tai_datablock(hp).is_global then
  472. AsmWriteLn(#9'PUBLIC'#9+tai_datablock(hp).sym.name);
  473. AsmWriteLn(PadTabs(tai_datablock(hp).sym.name,#0)+'DB'#9+tostr(tai_datablock(hp).size)+' DUP(?)');
  474. end;
  475. ait_const_uleb128bit,
  476. ait_const_sleb128bit,
  477. ait_const_128bit,
  478. ait_const_64bit,
  479. ait_const_32bit,
  480. ait_const_16bit,
  481. ait_const_8bit,
  482. ait_const_rva_symbol,
  483. ait_const_indirect_symbol :
  484. begin
  485. AsmWrite(ait_const2str[hp.typ]);
  486. consttyp:=hp.typ;
  487. l:=0;
  488. repeat
  489. if assigned(tai_const(hp).sym) then
  490. begin
  491. if assigned(tai_const(hp).endsym) then
  492. s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
  493. else
  494. s:=tai_const(hp).sym.name;
  495. if tai_const(hp).value<>0 then
  496. s:=s+tostr_with_plus(tai_const(hp).value);
  497. end
  498. else
  499. s:=tostr(tai_const(hp).value);
  500. AsmWrite(s);
  501. if (l>line_length) or
  502. (hp.next=nil) or
  503. (tai(hp.next).typ<>consttyp) then
  504. break;
  505. hp:=tai(hp.next);
  506. AsmWrite(',');
  507. until false;
  508. AsmLn;
  509. end;
  510. ait_real_32bit :
  511. AsmWriteLn(#9#9'DD'#9+single2str(tai_real_32bit(hp).value));
  512. ait_real_64bit :
  513. AsmWriteLn(#9#9'DQ'#9+double2str(tai_real_64bit(hp).value));
  514. ait_real_80bit :
  515. AsmWriteLn(#9#9'DT'#9+extended2str(tai_real_80bit(hp).value));
  516. ait_comp_64bit :
  517. AsmWriteLn(#9#9'DQ'#9+comp2str(tai_real_80bit(hp).value));
  518. ait_string :
  519. begin
  520. counter := 0;
  521. lines := tai_string(hp).len div line_length;
  522. { separate lines in different parts }
  523. if tai_string(hp).len > 0 then
  524. Begin
  525. for j := 0 to lines-1 do
  526. begin
  527. AsmWrite(#9#9'DB'#9);
  528. quoted:=false;
  529. for i:=counter to counter+line_length-1 do
  530. begin
  531. { it is an ascii character. }
  532. if (ord(tai_string(hp).str[i])>31) and
  533. (ord(tai_string(hp).str[i])<128) and
  534. (tai_string(hp).str[i]<>'"') then
  535. begin
  536. if not(quoted) then
  537. begin
  538. if i>counter then
  539. AsmWrite(',');
  540. AsmWrite('"');
  541. end;
  542. AsmWrite(tai_string(hp).str[i]);
  543. quoted:=true;
  544. end { if > 31 and < 128 and ord('"') }
  545. else
  546. begin
  547. if quoted then
  548. AsmWrite('"');
  549. if i>counter then
  550. AsmWrite(',');
  551. quoted:=false;
  552. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  553. end;
  554. end; { end for i:=0 to... }
  555. if quoted then AsmWrite('"');
  556. AsmWrite(target_info.newline);
  557. counter := counter+line_length;
  558. end; { end for j:=0 ... }
  559. { do last line of lines }
  560. if counter<tai_string(hp).len then
  561. AsmWrite(#9#9'DB'#9);
  562. quoted:=false;
  563. for i:=counter to tai_string(hp).len-1 do
  564. begin
  565. { it is an ascii character. }
  566. if (ord(tai_string(hp).str[i])>31) and
  567. (ord(tai_string(hp).str[i])<128) and
  568. (tai_string(hp).str[i]<>'"') then
  569. begin
  570. if not(quoted) then
  571. begin
  572. if i>counter then
  573. AsmWrite(',');
  574. AsmWrite('"');
  575. end;
  576. AsmWrite(tai_string(hp).str[i]);
  577. quoted:=true;
  578. end { if > 31 and < 128 and " }
  579. else
  580. begin
  581. if quoted then
  582. AsmWrite('"');
  583. if i>counter then
  584. AsmWrite(',');
  585. quoted:=false;
  586. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  587. end;
  588. end; { end for i:=0 to... }
  589. if quoted then
  590. AsmWrite('"');
  591. end;
  592. AsmLn;
  593. end;
  594. ait_label :
  595. begin
  596. if tai_label(hp).l.is_used then
  597. begin
  598. AsmWrite(tai_label(hp).l.name);
  599. if assigned(hp.next) and not(tai(hp.next).typ in
  600. [ait_const_32bit,ait_const_16bit,ait_const_8bit,
  601. ait_const_rva_symbol,
  602. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  603. AsmWriteLn(':')
  604. else
  605. DoNotSplitLine:=true;
  606. end;
  607. end;
  608. ait_symbol :
  609. begin
  610. if tai_symbol(hp).is_global then
  611. AsmWriteLn(#9'PUBLIC'#9+tai_symbol(hp).sym.name);
  612. AsmWrite(tai_symbol(hp).sym.name);
  613. if assigned(hp.next) and not(tai(hp.next).typ in
  614. [ait_const_32bit,ait_const_16bit,ait_const_8bit,
  615. ait_const_rva_symbol,
  616. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  617. AsmWriteLn(':')
  618. end;
  619. ait_symbol_end :
  620. begin
  621. end;
  622. ait_instruction :
  623. begin
  624. taicpu(hp).CheckNonCommutativeOpcodes;
  625. taicpu(hp).SetOperandOrder(op_intel);
  626. { Reset }
  627. suffix:='';
  628. prefix:= '';
  629. { We need to explicitely set
  630. word prefix to get selectors
  631. to be pushed in 2 bytes PM }
  632. if (taicpu(hp).opsize=S_W) and
  633. (
  634. (
  635. (taicpu(hp).opcode=A_PUSH) or
  636. (taicpu(hp).opcode=A_POP)
  637. ) and
  638. (taicpu(hp).oper[0]^.typ=top_reg) and
  639. is_segment_reg(taicpu(hp).oper[0]^.reg)
  640. ) then
  641. AsmWriteln(#9#9'DB'#9'066h');
  642. { added prefix instructions, must be on same line as opcode }
  643. if (taicpu(hp).ops = 0) and
  644. ((taicpu(hp).opcode = A_REP) or
  645. (taicpu(hp).opcode = A_LOCK) or
  646. (taicpu(hp).opcode = A_REPE) or
  647. (taicpu(hp).opcode = A_REPNZ) or
  648. (taicpu(hp).opcode = A_REPZ) or
  649. (taicpu(hp).opcode = A_REPNE)) then
  650. Begin
  651. prefix:=std_op2str[taicpu(hp).opcode]+#9;
  652. hp:=tai(hp.next);
  653. { this is theorically impossible... }
  654. if hp=nil then
  655. begin
  656. AsmWriteLn(#9#9+prefix);
  657. break;
  658. end;
  659. { nasm prefers prefix on a line alone
  660. AsmWriteln(#9#9+prefix); but not masm PM
  661. prefix:=''; }
  662. if target_asm.id in [as_i386_nasmcoff,as_i386_nasmwin32,as_i386_nasmwdosx,
  663. as_i386_nasmelf,as_i386_nasmobj,as_i386_nasmbeos] then
  664. begin
  665. AsmWriteln(prefix);
  666. prefix:='';
  667. end;
  668. end
  669. else
  670. prefix:= '';
  671. if (target_asm.id = as_i386_wasm) and
  672. (taicpu(hp).opsize=S_W) and
  673. (taicpu(hp).opcode=A_PUSH) and
  674. (taicpu(hp).oper[0]^.typ=top_const) then
  675. begin
  676. AsmWriteln(#9#9'DB 66h,68h ; pushw imm16');
  677. AsmWrite(#9#9'DW');
  678. end
  679. else if (target_asm.id=as_x86_64_masm) and
  680. (taicpu(hp).opcode=A_MOVQ) then
  681. AsmWrite(#9#9'mov')
  682. else
  683. AsmWrite(#9#9+prefix+std_op2str[taicpu(hp).opcode]+cond2str[taicpu(hp).condition]+suffix);
  684. if taicpu(hp).ops<>0 then
  685. begin
  686. if is_calljmp(taicpu(hp).opcode) then
  687. begin
  688. AsmWrite(#9);
  689. WriteOper_jmp(taicpu(hp).oper[0]^,taicpu(hp).opsize);
  690. end
  691. else
  692. begin
  693. for i:=0to taicpu(hp).ops-1 do
  694. begin
  695. if i=0 then
  696. AsmWrite(#9)
  697. else
  698. AsmWrite(',');
  699. WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,taicpu(hp).opcode,(i=2));
  700. end;
  701. end;
  702. end;
  703. AsmLn;
  704. end;
  705. ait_stab,
  706. ait_force_line,
  707. ait_function_name : ;
  708. ait_cutobject :
  709. begin
  710. { only reset buffer if nothing has changed }
  711. if AsmSize=AsmStartSize then
  712. AsmClear
  713. else
  714. begin
  715. if LasTSecType<>sec_none then
  716. AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  717. AsmLn;
  718. AsmWriteLn(#9'END');
  719. AsmClose;
  720. DoAssemble;
  721. AsmCreate(tai_cutobject(hp).place);
  722. end;
  723. { avoid empty files }
  724. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  725. begin
  726. if tai(hp.next).typ=ait_section then
  727. lasTSecType:=tai_section(hp.next).sectype;
  728. hp:=tai(hp.next);
  729. end;
  730. AsmWriteLn(#9'.386p');
  731. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  732. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  733. { I was told that this isn't necesarry because }
  734. { the labels generated by FPC are unique (FK) }
  735. { AsmWriteLn(#9'LOCALS '+target_asm.labelprefix); }
  736. if lasTSectype<>sec_none then
  737. AsmWriteLn('_'+secnames[lasTSectype]+#9#9+
  738. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  739. secnames[lasTSectype]+'''');
  740. AsmStartSize:=AsmSize;
  741. end;
  742. ait_marker :
  743. begin
  744. if tai_marker(hp).kind=InlineStart then
  745. inc(InlineLevel)
  746. else if tai_marker(hp).kind=InlineEnd then
  747. dec(InlineLevel);
  748. end;
  749. ait_directive :
  750. begin
  751. case tai_directive(hp).directive of
  752. asd_nasm_import :
  753. AsmWrite('import ');
  754. asd_extern :
  755. AsmWrite('EXTRN ');
  756. else
  757. internalerror(200509192);
  758. end;
  759. if assigned(tai_directive(hp).name) then
  760. AsmWrite(tai_directive(hp).name^);
  761. AsmLn;
  762. end;
  763. else
  764. internalerror(10000);
  765. end;
  766. hp:=tai(hp.next);
  767. end;
  768. end;
  769. var
  770. currentasmlist : TExternalAssembler;
  771. procedure writeexternal(p:tnamedindexitem;arg:pointer);
  772. begin
  773. if tasmsymbol(p).defbind=AB_EXTERNAL then
  774. begin
  775. case target_asm.id of
  776. as_i386_masm,as_i386_wasm:
  777. currentasmlist.AsmWriteln(#9'EXTRN'#9+p.name
  778. +': NEAR');
  779. as_x86_64_masm:
  780. currentasmlist.AsmWriteln(#9'EXTRN'#9+p.name
  781. +': PROC');
  782. else
  783. currentasmlist.AsmWriteln(#9'EXTRN'#9+p.name);
  784. end;
  785. end;
  786. end;
  787. procedure tx86IntelAssembler.WriteExternals;
  788. begin
  789. currentasmlist:=self;
  790. objectlibrary.symbolsearch.foreach_static(@writeexternal,nil);
  791. end;
  792. function tx86intelassembler.DoAssemble : boolean;
  793. var f : file;
  794. begin
  795. DoAssemble:=Inherited DoAssemble;
  796. { masm does not seem to recognize specific extensions and uses .obj allways PM }
  797. if (target_asm.id in [as_i386_masm,as_i386_wasm]) then
  798. begin
  799. if not(cs_asm_extern in aktglobalswitches) then
  800. begin
  801. if Not FileExists(objfile) and
  802. FileExists(ForceExtension(objfile,'.obj')) then
  803. begin
  804. Assign(F,ForceExtension(objfile,'.obj'));
  805. Rename(F,objfile);
  806. end;
  807. end
  808. else
  809. AsmRes.AddAsmCommand('mv',ForceExtension(objfile,'.obj')+' '+objfile,objfile);
  810. end;
  811. end;
  812. procedure tx86IntelAssembler.WriteAsmList;
  813. var
  814. hal : tasmlist;
  815. begin
  816. {$ifdef EXTDEBUG}
  817. if assigned(current_module.mainsource) then
  818. comment(v_info,'Start writing intel-styled assembler output for '+current_module.mainsource^);
  819. {$endif}
  820. LasTSecType:=sec_none;
  821. if target_asm.id<>as_x86_64_masm then
  822. begin
  823. AsmWriteLn(#9'.386p');
  824. { masm 6.11 does not seem to like LOCALS PM }
  825. if (target_asm.id = as_i386_tasm) then
  826. begin
  827. AsmWriteLn(#9'LOCALS '+target_asm.labelprefix);
  828. end;
  829. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  830. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  831. AsmLn;
  832. end;
  833. WriteExternals;
  834. for hal:=low(Tasmlist) to high(Tasmlist) do
  835. begin
  836. AsmWriteLn(target_asm.comment+'Begin asmlist '+TasmlistStr[hal]);
  837. writetree(asmlist[hal]);
  838. AsmWriteLn(target_asm.comment+'End asmlist '+TasmlistStr[hal]);
  839. end;
  840. AsmWriteLn(#9'END');
  841. AsmLn;
  842. {$ifdef EXTDEBUG}
  843. if assigned(current_module.mainsource) then
  844. comment(v_info,'Done writing intel-styled assembler output for '+current_module.mainsource^);
  845. {$endif EXTDEBUG}
  846. end;
  847. {*****************************************************************************
  848. Initialize
  849. *****************************************************************************}
  850. const
  851. as_i386_tasm_info : tasminfo =
  852. (
  853. id : as_i386_tasm;
  854. idtxt : 'TASM';
  855. asmbin : 'tasm';
  856. asmcmd : '/m2 /ml $ASM $OBJ';
  857. supported_target : system_any; { what should I write here ?? }
  858. flags : [af_allowdirect,af_needar,af_labelprefix_only_inside_procedure];
  859. labelprefix : '@@';
  860. comment : '; ';
  861. );
  862. as_i386_masm_info : tasminfo =
  863. (
  864. id : as_i386_masm;
  865. idtxt : 'MASM';
  866. asmbin : 'masm';
  867. asmcmd : '/c /Cp $ASM /Fo$OBJ';
  868. supported_target : system_any; { what should I write here ?? }
  869. flags : [af_allowdirect,af_needar];
  870. labelprefix : '@@';
  871. comment : '; ';
  872. );
  873. as_i386_wasm_info : tasminfo =
  874. (
  875. id : as_i386_wasm;
  876. idtxt : 'WASM';
  877. asmbin : 'wasm';
  878. asmcmd : '$ASM -6s -fp6 -ms -zq -Fo=$OBJ';
  879. supported_target : system_any; { what should I write here ?? }
  880. flags : [af_allowdirect,af_needar];
  881. labelprefix : '@@';
  882. comment : '; ';
  883. );
  884. as_x86_64_masm_info : tasminfo =
  885. (
  886. id : as_x86_64_masm;
  887. idtxt : 'MASM';
  888. asmbin : 'ml64';
  889. asmcmd : '/c /Cp $ASM /Fo$OBJ';
  890. supported_target : system_any; { what should I write here ?? }
  891. flags : [af_allowdirect,af_needar];
  892. labelprefix : '@@';
  893. comment : '; ';
  894. );
  895. initialization
  896. {$ifdef x86_64}
  897. RegisterAssembler(as_x86_64_masm_info,tx86IntelAssembler);
  898. {$endif x86_64}
  899. {$ifdef i386}
  900. RegisterAssembler(as_i386_tasm_info,tx86IntelAssembler);
  901. RegisterAssembler(as_i386_masm_info,tx86IntelAssembler);
  902. RegisterAssembler(as_i386_wasm_info,tx86IntelAssembler);
  903. {$endif i386}
  904. end.