agx86int.pas 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  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,aasmdata,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:TAsmList);override;
  34. procedure WriteAsmList;override;
  35. Function DoAssemble:boolean;override;
  36. procedure WriteExternals;
  37. end;
  38. implementation
  39. uses
  40. SysUtils,
  41. cutils,globtype,globals,systems,cclasses,
  42. verbose,script,cpuinfo,
  43. itx86int,
  44. cgbase
  45. {$ifdef EXTDEBUG}
  46. ,fmodule
  47. {$endif EXTDEBUG}
  48. ;
  49. const
  50. line_length = 70;
  51. wasm_cpu_name : array[tcputype] of string = (
  52. {$if defined(x86_64)}
  53. 'IA64', // cpu_none,
  54. '686', // cpu_athlon64,
  55. '686', // cpu_core_i,
  56. '686', // cpu_core_avx,
  57. '686' // cpu_core_avx2
  58. {$elseif defined(i386)}
  59. 'IA64', // cpu_none,
  60. '386', // cpu_386,
  61. '486', // cpu_486,
  62. '586', // cpu_Pentium,
  63. '686', // cpu_Pentium2,
  64. '686', // cpu_Pentium3,
  65. '686', // cpu_Pentium4,
  66. '686', // cpu_PentiumM,
  67. '686', // cpu_core_i,
  68. '686', // cpu_core_avx,
  69. '686' // cpu_core_avx2
  70. {$elseif defined(i8086)}
  71. 'IA64', // cpu_none
  72. '8086', // cpu_8086
  73. '186', // cpu_186
  74. '286', // cpu_286
  75. '386', // cpu_386
  76. '486', // cpu_486
  77. '586', // cpu_Pentium
  78. '686', // cpu_Pentium2
  79. '686', // cpu_Pentium3
  80. '686', // cpu_Pentium4
  81. '686' // cpu_PentiumM
  82. {$endif}
  83. );
  84. secnames : array[TAsmSectiontype] of string[4] = ('','',
  85. 'CODE','DATA','DATA','DATA','BSS','TLS',
  86. '','','','','','',
  87. '','','','',
  88. '',
  89. '',
  90. '',
  91. '',
  92. '',
  93. '','','','','','',
  94. '',
  95. '',
  96. '',
  97. '',
  98. '',
  99. '',
  100. '',
  101. '',
  102. '',
  103. '',
  104. '',
  105. '',
  106. '',
  107. '',
  108. '',
  109. '',
  110. '',
  111. '',
  112. '',
  113. '',
  114. '',
  115. '',
  116. '',
  117. '',
  118. '',
  119. '',
  120. '',
  121. '',
  122. '',
  123. '',
  124. '',
  125. '',
  126. '',
  127. '',
  128. '',
  129. '',
  130. '',
  131. '',
  132. '',
  133. ''
  134. );
  135. secnamesml64 : array[TAsmSectiontype] of string[7] = ('','',
  136. '_TEXT','_DATA','_DATA','_DATA','_BSS','_TLS',
  137. '','','','',
  138. 'idata$2','idata$4','idata$5','idata$6','idata$7','edata',
  139. '',
  140. '',
  141. '',
  142. '',
  143. '',
  144. '','','','','','',
  145. '',
  146. '',
  147. '',
  148. '',
  149. '',
  150. '',
  151. '',
  152. '',
  153. '',
  154. '',
  155. '',
  156. '',
  157. '',
  158. '',
  159. '',
  160. '',
  161. '',
  162. '',
  163. '',
  164. '',
  165. '',
  166. '',
  167. '',
  168. '',
  169. '',
  170. '',
  171. '',
  172. '',
  173. '',
  174. '',
  175. '',
  176. '',
  177. '',
  178. '',
  179. '',
  180. '',
  181. '',
  182. '',
  183. '',
  184. ''
  185. );
  186. function single2str(d : single) : string;
  187. var
  188. hs : string;
  189. p : byte;
  190. begin
  191. str(d,hs);
  192. { nasm expects a lowercase e }
  193. p:=pos('E',hs);
  194. if p>0 then
  195. hs[p]:='e';
  196. p:=pos('+',hs);
  197. if p>0 then
  198. delete(hs,p,1);
  199. single2str:=lower(hs);
  200. end;
  201. function double2str(d : double) : string;
  202. var
  203. hs : string;
  204. p : byte;
  205. begin
  206. str(d,hs);
  207. { nasm expects a lowercase e }
  208. p:=pos('E',hs);
  209. if p>0 then
  210. hs[p]:='e';
  211. p:=pos('+',hs);
  212. if p>0 then
  213. delete(hs,p,1);
  214. double2str:=lower(hs);
  215. end;
  216. function extended2str(e : extended) : string;
  217. var
  218. hs : string;
  219. p : byte;
  220. begin
  221. str(e,hs);
  222. { nasm expects a lowercase e }
  223. p:=pos('E',hs);
  224. if p>0 then
  225. hs[p]:='e';
  226. p:=pos('+',hs);
  227. if p>0 then
  228. delete(hs,p,1);
  229. extended2str:=lower(hs);
  230. end;
  231. function comp2str(d : bestreal) : string;
  232. type
  233. pdouble = ^double;
  234. var
  235. c : comp;
  236. dd : pdouble;
  237. begin
  238. c:=comp(d);
  239. dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
  240. comp2str:=double2str(dd^);
  241. end;
  242. { MASM supports aligns up to 8192 }
  243. function alignstr(b : integer) : string;
  244. begin
  245. case b of
  246. 1: result:='BYTE';
  247. 2: result:='WORD';
  248. 4: result:='DWORD';
  249. 0,
  250. 16: result:='PARA';
  251. 256: result:='PAGE';
  252. else
  253. result:='ALIGN('+tostr(b)+')';
  254. end;
  255. end;
  256. {****************************************************************************
  257. tx86IntelAssembler
  258. ****************************************************************************}
  259. procedure tx86IntelAssembler.WriteReference(var ref : treference);
  260. var
  261. first : boolean;
  262. begin
  263. with ref do
  264. begin
  265. first:=true;
  266. if segment<>NR_NO then
  267. writer.AsmWrite(masm_regname(segment)+':[')
  268. else
  269. writer.AsmWrite('[');
  270. if assigned(symbol) then
  271. begin
  272. if (asminfo^.id = as_i386_tasm) then
  273. writer.AsmWrite('dword ptr ');
  274. writer.AsmWrite(symbol.name);
  275. first:=false;
  276. end;
  277. if (base<>NR_NO) then
  278. begin
  279. if not(first) then
  280. writer.AsmWrite('+')
  281. else
  282. first:=false;
  283. {$ifdef x86_64}
  284. { ml64 needs [$+foo] instead of [rip+foo] }
  285. if (base=NR_RIP) and (asminfo^.id=as_x86_64_masm) then
  286. writer.AsmWrite('$')
  287. else
  288. {$endif x86_64}
  289. writer.AsmWrite(masm_regname(base));
  290. end;
  291. if (index<>NR_NO) then
  292. begin
  293. if not(first) then
  294. writer.AsmWrite('+')
  295. else
  296. first:=false;
  297. writer.AsmWrite(masm_regname(index));
  298. if scalefactor<>0 then
  299. writer.AsmWrite('*'+tostr(scalefactor));
  300. end;
  301. if offset<0 then
  302. begin
  303. writer.AsmWrite(tostr(offset));
  304. first:=false;
  305. end
  306. else if (offset>0) then
  307. begin
  308. writer.AsmWrite('+'+tostr(offset));
  309. first:=false;
  310. end;
  311. if first then
  312. writer.AsmWrite('0');
  313. writer.AsmWrite(']');
  314. end;
  315. end;
  316. procedure tx86IntelAssembler.WriteOper(const o:toper;s : topsize; opcode: tasmop;dest : boolean);
  317. begin
  318. case o.typ of
  319. top_reg :
  320. writer.AsmWrite(masm_regname(o.reg));
  321. top_const :
  322. writer.AsmWrite(tostr(o.val));
  323. top_ref :
  324. begin
  325. if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got] then
  326. begin
  327. if ((opcode <> A_LGS) and (opcode <> A_LSS) and
  328. (opcode <> A_LFS)
  329. {$ifndef x86_64}
  330. and (opcode <> A_LDS) and (opcode <> A_LES)
  331. {$endif x86_64}
  332. ) then
  333. Begin
  334. case s of
  335. S_B : writer.AsmWrite('byte ptr ');
  336. S_W : writer.AsmWrite('word ptr ');
  337. S_L : writer.AsmWrite('dword ptr ');
  338. S_Q : writer.AsmWrite('qword ptr ');
  339. S_IS : writer.AsmWrite('word ptr ');
  340. S_IL : writer.AsmWrite('dword ptr ');
  341. S_IQ : writer.AsmWrite('qword ptr ');
  342. S_FS : writer.AsmWrite('dword ptr ');
  343. S_FL : writer.AsmWrite('qword ptr ');
  344. S_T,
  345. S_FX : writer.AsmWrite('tbyte ptr ');
  346. S_BW : if dest then
  347. writer.AsmWrite('word ptr ')
  348. else
  349. writer.AsmWrite('byte ptr ');
  350. S_BL : if dest then
  351. writer.AsmWrite('dword ptr ')
  352. else
  353. writer.AsmWrite('byte ptr ');
  354. S_WL : if dest then
  355. writer.AsmWrite('dword ptr ')
  356. else
  357. writer.AsmWrite('word ptr ');
  358. S_XMM: writer.AsmWrite('xmmword ptr ');
  359. S_YMM: writer.AsmWrite('ymmword ptr ');
  360. {$ifdef x86_64}
  361. S_BQ : if dest then
  362. writer.AsmWrite('qword ptr ')
  363. else
  364. writer.AsmWrite('byte ptr ');
  365. S_WQ : if dest then
  366. writer.AsmWrite('qword ptr ')
  367. else
  368. writer.AsmWrite('word ptr ');
  369. S_LQ : if dest then
  370. writer.AsmWrite('qword ptr ')
  371. else
  372. writer.AsmWrite('dword ptr ');
  373. {$endif x86_64}
  374. end;
  375. end;
  376. WriteReference(o.ref^);
  377. end
  378. else
  379. begin
  380. writer.AsmWrite('offset ');
  381. if assigned(o.ref^.symbol) then
  382. writer.AsmWrite(o.ref^.symbol.name);
  383. if o.ref^.offset>0 then
  384. writer.AsmWrite('+'+tostr(o.ref^.offset))
  385. else
  386. if o.ref^.offset<0 then
  387. writer.AsmWrite(tostr(o.ref^.offset))
  388. else
  389. if not(assigned(o.ref^.symbol)) then
  390. writer.AsmWrite('0');
  391. end;
  392. end;
  393. else
  394. internalerror(2005060510);
  395. end;
  396. end;
  397. procedure tx86IntelAssembler.WriteOper_jmp(const o:toper;s : topsize);
  398. begin
  399. case o.typ of
  400. top_reg :
  401. writer.AsmWrite(masm_regname(o.reg));
  402. top_const :
  403. writer.AsmWrite(tostr(o.val));
  404. top_ref :
  405. { what about lcall or ljmp ??? }
  406. begin
  407. if o.ref^.refaddr=addr_no then
  408. begin
  409. if (asminfo^.id <> as_i386_tasm) then
  410. begin
  411. if s=S_FAR then
  412. writer.AsmWrite('far ptr ')
  413. else
  414. {$ifdef x86_64}
  415. writer.AsmWrite('qword ptr ');
  416. {$else x86_64}
  417. writer.AsmWrite('dword ptr ');
  418. {$endif x86_64}
  419. end;
  420. WriteReference(o.ref^);
  421. end
  422. else
  423. begin
  424. writer.AsmWrite(o.ref^.symbol.name);
  425. if o.ref^.offset>0 then
  426. writer.AsmWrite('+'+tostr(o.ref^.offset))
  427. else
  428. if o.ref^.offset<0 then
  429. writer.AsmWrite(tostr(o.ref^.offset));
  430. end;
  431. end;
  432. else
  433. internalerror(2005060511);
  434. end;
  435. end;
  436. const
  437. ait_const2str : array[aitconst_128bit..aitconst_secrel32_symbol] of string[20]=(
  438. #9''#9,#9'DQ'#9,#9'DD'#9,#9'DW'#9,#9'DB'#9,
  439. #9'FIXMESLEB',#9'FIXEMEULEB',
  440. #9'DD RVA'#9,#9'DD SECREL32'#9
  441. );
  442. Function PadTabs(const p:string;addch:char):string;
  443. var
  444. s : string;
  445. i : longint;
  446. begin
  447. i:=length(p);
  448. if addch<>#0 then
  449. begin
  450. inc(i);
  451. s:=p+addch;
  452. end
  453. else
  454. s:=p;
  455. if i<8 then
  456. PadTabs:=s+#9#9
  457. else
  458. PadTabs:=s+#9;
  459. end;
  460. procedure tx86IntelAssembler.WriteTree(p:TAsmList);
  461. var
  462. s,
  463. prefix,
  464. suffix : string;
  465. hp : tai;
  466. cpu: tcputype;
  467. counter,
  468. lines,
  469. InlineLevel : longint;
  470. i,j,l : longint;
  471. consttype : taiconst_type;
  472. do_line,DoNotSplitLine,
  473. quoted : boolean;
  474. fixed_opcode: TAsmOp;
  475. begin
  476. if not assigned(p) then
  477. exit;
  478. { lineinfo is only needed for al_procedures (PFV) }
  479. do_line:=((cs_asm_source in current_settings.globalswitches) or
  480. (cs_lineinfo in current_settings.moduleswitches))
  481. and (p=current_asmdata.asmlists[al_procedures]);
  482. InlineLevel:=0;
  483. DoNotSplitLine:=false;
  484. hp:=tai(p.first);
  485. while assigned(hp) do
  486. begin
  487. prefetch(pointer(hp.next)^);
  488. if not(hp.typ in SkipLineInfo) then
  489. begin
  490. current_filepos:=tailineinfo(hp).fileinfo;
  491. { no line info for inlined code }
  492. if do_line and (inlinelevel=0) and not DoNotSplitLine then
  493. WriteSourceLine(hp as tailineinfo);
  494. end;
  495. DoNotSplitLine:=false;
  496. case hp.typ of
  497. ait_comment :
  498. Begin
  499. writer.AsmWrite(asminfo^.comment);
  500. writer.AsmWritePChar(tai_comment(hp).str);
  501. writer.AsmLn;
  502. End;
  503. ait_regalloc :
  504. begin
  505. if (cs_asm_regalloc in current_settings.globalswitches) then
  506. writer.AsmWriteLn(asminfo^.comment+'Register '+masm_regname(tai_regalloc(hp).reg)+
  507. regallocstr[tai_regalloc(hp).ratype]);
  508. end;
  509. ait_tempalloc :
  510. begin
  511. if (cs_asm_tempalloc in current_settings.globalswitches) then
  512. WriteTempalloc(tai_tempalloc(hp));
  513. end;
  514. ait_section :
  515. begin
  516. if tai_section(hp).sectype<>sec_none then
  517. begin
  518. if asminfo^.id=as_x86_64_masm then
  519. begin
  520. if LasTSecType<>sec_none then
  521. writer.AsmWriteLn(secnamesml64[LasTSecType]+#9#9'ENDS');
  522. writer.AsmLn;
  523. writer.AsmWriteLn(secnamesml64[tai_section(hp).sectype]+#9+'SEGMENT')
  524. end
  525. else
  526. begin
  527. if LasTSecType<>sec_none then
  528. writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  529. writer.AsmLn;
  530. writer.AsmWriteLn('_'+secnames[tai_section(hp).sectype]+#9#9+
  531. 'SEGMENT'#9+alignstr(tai_section(hp).secalign)+' PUBLIC USE32 '''+
  532. secnames[tai_section(hp).sectype]+'''');
  533. end;
  534. end;
  535. LasTSecType:=tai_section(hp).sectype;
  536. end;
  537. ait_align :
  538. begin
  539. { CAUSES PROBLEMS WITH THE SEGMENT DEFINITION }
  540. { SEGMENT DEFINITION SHOULD MATCH TYPE OF ALIGN }
  541. { HERE UNDER TASM! }
  542. if tai_align_abstract(hp).aligntype>1 then
  543. writer.AsmWriteLn(#9'ALIGN '+tostr(tai_align_abstract(hp).aligntype));
  544. end;
  545. ait_datablock :
  546. begin
  547. if tai_datablock(hp).is_global then
  548. writer.AsmWriteLn(#9'PUBLIC'#9+tai_datablock(hp).sym.name);
  549. writer.AsmWriteLn(PadTabs(tai_datablock(hp).sym.name,#0)+'DB'#9+tostr(tai_datablock(hp).size)+' DUP(?)');
  550. end;
  551. ait_const:
  552. begin
  553. consttype:=tai_const(hp).consttype;
  554. case consttype of
  555. aitconst_uleb128bit,
  556. aitconst_sleb128bit,
  557. aitconst_128bit,
  558. aitconst_64bit,
  559. aitconst_32bit,
  560. aitconst_16bit,
  561. aitconst_8bit,
  562. aitconst_rva_symbol,
  563. aitconst_secrel32_symbol :
  564. begin
  565. writer.AsmWrite(ait_const2str[consttype]);
  566. l:=0;
  567. repeat
  568. if assigned(tai_const(hp).sym) then
  569. begin
  570. if assigned(tai_const(hp).endsym) then
  571. s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
  572. else
  573. s:=tai_const(hp).sym.name;
  574. if tai_const(hp).value<>0 then
  575. s:=s+tostr_with_plus(tai_const(hp).value);
  576. end
  577. else
  578. s:=tostr(tai_const(hp).value);
  579. writer.AsmWrite(s);
  580. inc(l,length(s));
  581. if (l>line_length) or
  582. (hp.next=nil) or
  583. (tai(hp.next).typ<>ait_const) or
  584. (tai_const(hp.next).consttype<>consttype) then
  585. break;
  586. hp:=tai(hp.next);
  587. writer.AsmWrite(',');
  588. until false;
  589. { Substract section start for secrel32 type }
  590. if consttype=aitconst_secrel32_symbol then
  591. writer.AsmWrite(' - $$');
  592. writer.AsmLn;
  593. end;
  594. else
  595. internalerror(200704253);
  596. end;
  597. end;
  598. ait_realconst:
  599. begin
  600. case tai_realconst(hp).realtyp of
  601. aitrealconst_s32bit:
  602. writer.AsmWriteLn(#9#9'DD'#9+single2str(tai_realconst(hp).value.s32val));
  603. aitrealconst_s64bit:
  604. writer.AsmWriteLn(#9#9'DQ'#9+double2str(tai_realconst(hp).value.s64val));
  605. aitrealconst_s80bit:
  606. writer.AsmWriteLn(#9#9'DT'#9+extended2str(tai_realconst(hp).value.s80val));
  607. aitrealconst_s64comp:
  608. writer.AsmWriteLn(#9#9'DQ'#9+extended2str(tai_realconst(hp).value.s64compval));
  609. else
  610. internalerror(2014050604);
  611. end;
  612. end;
  613. ait_string :
  614. begin
  615. counter := 0;
  616. lines := tai_string(hp).len div line_length;
  617. { separate lines in different parts }
  618. if tai_string(hp).len > 0 then
  619. Begin
  620. for j := 0 to lines-1 do
  621. begin
  622. writer.AsmWrite(#9#9'DB'#9);
  623. quoted:=false;
  624. for i:=counter to counter+line_length-1 do
  625. begin
  626. { it is an ascii character. }
  627. if (ord(tai_string(hp).str[i])>31) and
  628. (ord(tai_string(hp).str[i])<128) and
  629. (tai_string(hp).str[i]<>'"') then
  630. begin
  631. if not(quoted) then
  632. begin
  633. if i>counter then
  634. writer.AsmWrite(',');
  635. writer.AsmWrite('"');
  636. end;
  637. writer.AsmWrite(tai_string(hp).str[i]);
  638. quoted:=true;
  639. end { if > 31 and < 128 and ord('"') }
  640. else
  641. begin
  642. if quoted then
  643. writer.AsmWrite('"');
  644. if i>counter then
  645. writer.AsmWrite(',');
  646. quoted:=false;
  647. writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
  648. end;
  649. end; { end for i:=0 to... }
  650. if quoted then writer.AsmWrite('"');
  651. writer.AsmWrite(target_info.newline);
  652. counter := counter+line_length;
  653. end; { end for j:=0 ... }
  654. { do last line of lines }
  655. if counter<tai_string(hp).len then
  656. writer.AsmWrite(#9#9'DB'#9);
  657. quoted:=false;
  658. for i:=counter to tai_string(hp).len-1 do
  659. begin
  660. { it is an ascii character. }
  661. if (ord(tai_string(hp).str[i])>31) and
  662. (ord(tai_string(hp).str[i])<128) and
  663. (tai_string(hp).str[i]<>'"') then
  664. begin
  665. if not(quoted) then
  666. begin
  667. if i>counter then
  668. writer.AsmWrite(',');
  669. writer.AsmWrite('"');
  670. end;
  671. writer.AsmWrite(tai_string(hp).str[i]);
  672. quoted:=true;
  673. end { if > 31 and < 128 and " }
  674. else
  675. begin
  676. if quoted then
  677. writer.AsmWrite('"');
  678. if i>counter then
  679. writer.AsmWrite(',');
  680. quoted:=false;
  681. writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
  682. end;
  683. end; { end for i:=0 to... }
  684. if quoted then
  685. writer.AsmWrite('"');
  686. end;
  687. writer.AsmLn;
  688. end;
  689. ait_label :
  690. begin
  691. if tai_label(hp).labsym.is_used then
  692. begin
  693. writer.AsmWrite(tai_label(hp).labsym.name);
  694. if assigned(hp.next) and not(tai(hp.next).typ in
  695. [ait_const,ait_realconst,ait_string]) then
  696. writer.AsmWriteLn(':')
  697. else
  698. DoNotSplitLine:=true;
  699. end;
  700. end;
  701. ait_symbol :
  702. begin
  703. if tai_symbol(hp).has_value then
  704. internalerror(2009090802);
  705. if tai_symbol(hp).is_global then
  706. writer.AsmWriteLn(#9'PUBLIC'#9+tai_symbol(hp).sym.name);
  707. writer.AsmWrite(tai_symbol(hp).sym.name);
  708. if assigned(hp.next) and not(tai(hp.next).typ in
  709. [ait_const,ait_realconst,ait_string]) then
  710. writer.AsmWriteLn(':')
  711. end;
  712. ait_symbol_end :
  713. begin
  714. end;
  715. ait_instruction :
  716. begin
  717. fixed_opcode:=taicpu(hp).FixNonCommutativeOpcodes;
  718. taicpu(hp).SetOperandOrder(op_intel);
  719. { Reset }
  720. suffix:='';
  721. prefix:= '';
  722. { We need to explicitely set
  723. word prefix to get selectors
  724. to be pushed in 2 bytes PM }
  725. if (taicpu(hp).opsize=S_W) and
  726. (
  727. (
  728. (fixed_opcode=A_PUSH) or
  729. (fixed_opcode=A_POP)
  730. ) and
  731. (taicpu(hp).oper[0]^.typ=top_reg) and
  732. is_segment_reg(taicpu(hp).oper[0]^.reg)
  733. ) then
  734. writer.AsmWriteln(#9#9'DB'#9'066h');
  735. { added prefix instructions, must be on same line as opcode }
  736. if (taicpu(hp).ops = 0) and
  737. ((fixed_opcode = A_REP) or
  738. (fixed_opcode = A_LOCK) or
  739. (fixed_opcode = A_REPE) or
  740. (fixed_opcode = A_REPNZ) or
  741. (fixed_opcode = A_REPZ) or
  742. (fixed_opcode = A_REPNE)) then
  743. Begin
  744. prefix:=std_op2str[fixed_opcode]+#9;
  745. { there can be a stab inbetween when the opcode was on
  746. a different line in the source code }
  747. repeat
  748. hp:=tai(hp.next);
  749. until (hp=nil) or (hp.typ=ait_instruction);
  750. { next instruction ... }
  751. fixed_opcode:=taicpu(hp).FixNonCommutativeOpcodes;
  752. taicpu(hp).SetOperandOrder(op_intel);
  753. { this is theorically impossible... }
  754. if hp=nil then
  755. begin
  756. writer.AsmWriteLn(#9#9+prefix);
  757. break;
  758. end;
  759. { nasm prefers prefix on a line alone
  760. writer.AsmWriteln(#9#9+prefix); but not masm PM
  761. prefix:=''; }
  762. if asminfo^.id in [as_i386_nasmcoff,as_i386_nasmwin32,as_i386_nasmwdosx,
  763. as_i386_nasmelf,as_i386_nasmobj,as_i386_nasmbeos,as_i386_nasmhaiku] then
  764. begin
  765. writer.AsmWriteln(prefix);
  766. prefix:='';
  767. end;
  768. end
  769. else
  770. prefix:= '';
  771. if (asminfo^.id = as_i386_wasm) and
  772. (taicpu(hp).opsize=S_W) and
  773. (fixed_opcode=A_PUSH) and
  774. (taicpu(hp).oper[0]^.typ=top_const) then
  775. begin
  776. writer.AsmWriteln(#9#9'DB 66h,68h ; pushw imm16');
  777. writer.AsmWrite(#9#9'DW');
  778. end
  779. else if (asminfo^.id=as_x86_64_masm) and
  780. (fixed_opcode=A_MOVQ) then
  781. writer.AsmWrite(#9#9'mov')
  782. else
  783. writer.AsmWrite(#9#9+prefix+std_op2str[fixed_opcode]+cond2str[taicpu(hp).condition]+suffix);
  784. if taicpu(hp).ops<>0 then
  785. begin
  786. if is_calljmp(fixed_opcode) then
  787. begin
  788. writer.AsmWrite(#9);
  789. WriteOper_jmp(taicpu(hp).oper[0]^,taicpu(hp).opsize);
  790. end
  791. else
  792. begin
  793. for i:=0to taicpu(hp).ops-1 do
  794. begin
  795. if i=0 then
  796. writer.AsmWrite(#9)
  797. else
  798. writer.AsmWrite(',');
  799. WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,fixed_opcode,(i=2));
  800. end;
  801. end;
  802. end;
  803. writer.AsmLn;
  804. end;
  805. ait_stab,
  806. ait_force_line,
  807. ait_function_name : ;
  808. ait_cutobject :
  809. begin
  810. { only reset buffer if nothing has changed }
  811. if not writer.ClearIfEmpty then
  812. begin
  813. if LasTSecType<>sec_none then
  814. writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  815. writer.AsmLn;
  816. writer.AsmWriteLn(#9'END');
  817. writer.AsmClose;
  818. DoAssemble;
  819. writer.AsmCreate(tai_cutobject(hp).place);
  820. end;
  821. { avoid empty files }
  822. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  823. begin
  824. if tai(hp.next).typ=ait_section then
  825. lasTSecType:=tai_section(hp.next).sectype;
  826. hp:=tai(hp.next);
  827. end;
  828. if (asminfo^.id = as_i386_wasm) then
  829. begin
  830. writer.AsmWriteLn(#9'.686p');
  831. writer.AsmWriteLn(#9'.mmx');
  832. end
  833. else
  834. writer.AsmWriteLn(#9'.386p');
  835. {$ifdef i8086}
  836. writer.AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  837. writer.AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  838. {$endif i8086}
  839. { I was told that this isn't necesarry because }
  840. { the labels generated by FPC are unique (FK) }
  841. { writer.AsmWriteLn(#9'LOCALS '+asminfo^.labelprefix); }
  842. { TODO: PARA is incorrect, must use actual section align }
  843. if lasTSectype<>sec_none then
  844. writer.AsmWriteLn('_'+secnames[lasTSectype]+#9#9+
  845. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  846. secnames[lasTSectype]+'''');
  847. writer.MarkEmpty;
  848. end;
  849. ait_marker :
  850. begin
  851. if tai_marker(hp).kind=mark_NoLineInfoStart then
  852. inc(InlineLevel)
  853. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  854. dec(InlineLevel);
  855. end;
  856. ait_directive :
  857. begin
  858. case tai_directive(hp).directive of
  859. asd_nasm_import :
  860. begin
  861. writer.AsmWrite('import ');
  862. writer.AsmWrite(tai_directive(hp).name);
  863. writer.AsmLn;
  864. end;
  865. asd_extern :
  866. begin
  867. writer.AsmWrite('EXTRN ');
  868. writer.AsmWrite(tai_directive(hp).name);
  869. writer.AsmLn;
  870. end;
  871. asd_cpu :
  872. begin
  873. if (asminfo^.id = as_i386_wasm) then
  874. begin
  875. writer.AsmWrite('.');
  876. for cpu:=low(tcputype) to high(tcputype) do
  877. begin
  878. if tai_directive(hp).name=CPUTypeStr[CPU] then
  879. begin
  880. writer.AsmWriteLn(wasm_cpu_name[cpu]);
  881. break;
  882. end;
  883. end;
  884. end
  885. else
  886. begin
  887. { TODO: implement this properly for TASM/MASM/WASM (.686p, etc.) }
  888. writer.AsmWrite(asminfo^.comment+' CPU ');
  889. writer.AsmWrite(tai_directive(hp).name);
  890. writer.AsmLn;
  891. end;
  892. end
  893. else
  894. internalerror(200509192);
  895. end;
  896. end;
  897. ait_seh_directive :
  898. { Ignore for now };
  899. else
  900. internalerror(10000);
  901. end;
  902. hp:=tai(hp.next);
  903. end;
  904. end;
  905. procedure tx86intelassembler.WriteExternals;
  906. var
  907. sym : TAsmSymbol;
  908. i : longint;
  909. begin
  910. for i:=0 to current_asmdata.AsmSymbolDict.Count-1 do
  911. begin
  912. sym:=TAsmSymbol(current_asmdata.AsmSymbolDict[i]);
  913. if sym.bind=AB_EXTERNAL then
  914. begin
  915. case asminfo^.id of
  916. as_i386_masm,
  917. as_i386_wasm :
  918. writer.AsmWriteln(#9'EXTRN'#9+sym.name+': NEAR');
  919. as_x86_64_masm :
  920. writer.AsmWriteln(#9'EXTRN'#9+sym.name+': PROC');
  921. else
  922. writer.AsmWriteln(#9'EXTRN'#9+sym.name);
  923. end;
  924. end;
  925. end;
  926. end;
  927. function tx86intelassembler.DoAssemble : boolean;
  928. var
  929. masmobjfn : string;
  930. begin
  931. DoAssemble:=Inherited DoAssemble;
  932. { masm does not seem to recognize specific extensions and uses .obj allways PM }
  933. if (asminfo^.id in [as_i386_masm,as_i386_wasm]) then
  934. begin
  935. masmobjfn:=ChangeFileExt(objfilename,'.obj');
  936. if not(cs_asm_extern in current_settings.globalswitches) then
  937. begin
  938. if Not FileExists(objfilename) and
  939. FileExists(masmobjfn) then
  940. RenameFile(masmobjfn,objfilename);
  941. end
  942. else
  943. AsmRes.AddAsmCommand('mv',masmobjfn+' '+objfilename,objfilename);
  944. end;
  945. end;
  946. procedure tx86IntelAssembler.WriteAsmList;
  947. var
  948. hal : tasmlisttype;
  949. begin
  950. {$ifdef EXTDEBUG}
  951. if current_module.mainsource<>'' then
  952. comment(v_info,'Start writing intel-styled assembler output for '+current_module.mainsource);
  953. {$endif}
  954. if asminfo^.id<>as_x86_64_masm then
  955. begin
  956. if (asminfo^.id = as_i386_wasm) then
  957. begin
  958. writer.AsmWriteLn(#9'.686p');
  959. writer.AsmWriteLn(#9'.mmx');
  960. end
  961. else
  962. writer.AsmWriteLn(#9'.386p');
  963. { masm 6.11 does not seem to like LOCALS PM }
  964. if (asminfo^.id = as_i386_tasm) then
  965. begin
  966. writer.AsmWriteLn(#9'LOCALS '+asminfo^.labelprefix);
  967. end;
  968. {$ifdef i8086}
  969. writer.AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  970. writer.AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  971. {$endif i8086}
  972. writer.AsmLn;
  973. end;
  974. WriteExternals;
  975. for hal:=low(TasmlistType) to high(TasmlistType) do
  976. begin
  977. writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmListTypeStr[hal]);
  978. writetree(current_asmdata.asmlists[hal]);
  979. writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmListTypeStr[hal]);
  980. end;
  981. { better do this at end of WriteTree, but then there comes a trouble with
  982. al_const which does not have leading ait_section and thus goes out of segment }
  983. if LastSecType <> sec_none then
  984. begin
  985. if asminfo^.id=as_x86_64_masm then
  986. writer.AsmWriteLn(secnamesml64[LasTSecType]+#9#9'ENDS')
  987. else
  988. writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  989. end;
  990. LastSecType := sec_none;
  991. writer.AsmWriteLn(#9'END');
  992. writer.AsmLn;
  993. {$ifdef EXTDEBUG}
  994. if current_module.mainsource<>'' then
  995. comment(v_info,'Done writing intel-styled assembler output for '+current_module.mainsource);
  996. {$endif EXTDEBUG}
  997. end;
  998. {*****************************************************************************
  999. Initialize
  1000. *****************************************************************************}
  1001. const
  1002. {$ifdef i386}
  1003. as_i386_tasm_info : tasminfo =
  1004. (
  1005. id : as_i386_tasm;
  1006. idtxt : 'TASM';
  1007. asmbin : 'tasm';
  1008. asmcmd : '/m2 /ml $EXTRAOPT $ASM $OBJ';
  1009. supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
  1010. flags : [af_needar,af_labelprefix_only_inside_procedure];
  1011. labelprefix : '@@';
  1012. comment : '; ';
  1013. dollarsign: '$';
  1014. );
  1015. as_i386_masm_info : tasminfo =
  1016. (
  1017. id : as_i386_masm;
  1018. idtxt : 'MASM';
  1019. asmbin : 'masm';
  1020. asmcmd : '/c /Cp $EXTRAOPT $ASM /Fo$OBJ';
  1021. supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
  1022. flags : [af_needar];
  1023. labelprefix : '@@';
  1024. comment : '; ';
  1025. dollarsign: '$';
  1026. );
  1027. as_i386_wasm_info : tasminfo =
  1028. (
  1029. id : as_i386_wasm;
  1030. idtxt : 'WASM';
  1031. asmbin : 'wasm';
  1032. asmcmd : '$ASM $EXTRAOPT -6s -fp6 -ms -zq -Fo=$OBJ';
  1033. supported_targets : [system_i386_watcom];
  1034. flags : [af_needar];
  1035. labelprefix : '@@';
  1036. comment : '; ';
  1037. dollarsign: '$';
  1038. );
  1039. {$endif i386}
  1040. {$ifdef x86_64}
  1041. as_x86_64_masm_info : tasminfo =
  1042. (
  1043. id : as_x86_64_masm;
  1044. idtxt : 'MASM';
  1045. asmbin : 'ml64';
  1046. asmcmd : '/c /Cp $EXTRAOPT $ASM /Fo$OBJ';
  1047. supported_targets : [system_x86_64_win64];
  1048. flags : [af_needar];
  1049. labelprefix : '@@';
  1050. comment : '; ';
  1051. dollarsign: '$';
  1052. );
  1053. {$endif x86_64}
  1054. initialization
  1055. {$ifdef x86_64}
  1056. RegisterAssembler(as_x86_64_masm_info,tx86IntelAssembler);
  1057. {$endif x86_64}
  1058. {$ifdef i386}
  1059. RegisterAssembler(as_i386_tasm_info,tx86IntelAssembler);
  1060. RegisterAssembler(as_i386_masm_info,tx86IntelAssembler);
  1061. RegisterAssembler(as_i386_wasm_info,tx86IntelAssembler);
  1062. {$endif i386}
  1063. end.