ag386int.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. {
  2. $Id$
  3. Copyright (c) 1996,97 by Florian Klaempfl
  4. This unit implements an asmoutput class for Intel syntax with Intel i386+
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ag386int;
  19. interface
  20. uses aasm,assemble;
  21. type
  22. pi386intasmlist=^ti386intasmlist;
  23. ti386intasmlist = object(tasmlist)
  24. procedure WriteTree(p:paasmoutput);virtual;
  25. procedure WriteAsmList;virtual;
  26. end;
  27. implementation
  28. uses
  29. dos,globals,systems,cobjects,i386,
  30. strings,files,verbose
  31. {$ifdef GDB}
  32. ,gdb
  33. {$endif GDB}
  34. ;
  35. const
  36. line_length = 70;
  37. extstr : array[EXT_NEAR..EXT_ABS] of String[8] =
  38. ('NEAR','FAR','PROC','BYTE','WORD','DWORD',
  39. 'CODEPTR','DATAPTR','FWORD','PWORD','QWORD','TBYTE','ABS');
  40. function double2str(d : double) : string;
  41. var
  42. hs : string;
  43. p : byte;
  44. begin
  45. str(d,hs);
  46. { nasm expects a lowercase e }
  47. p:=pos('E',hs);
  48. if p>0 then
  49. hs[p]:='e';
  50. p:=pos('+',hs);
  51. if p>0 then
  52. delete(hs,p,1);
  53. double2str:=lower(hs);
  54. end;
  55. function comp2str(d : bestreal) : string;
  56. type
  57. pdouble = ^double;
  58. var
  59. c : comp;
  60. dd : pdouble;
  61. begin
  62. c:=comp(d);
  63. dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
  64. comp2str:=double2str(dd^);
  65. end;
  66. function getreferencestring(const ref : treference) : string;
  67. var
  68. s : string;
  69. first : boolean;
  70. begin
  71. if ref.isintvalue then
  72. s:= tostr(ref.offset)
  73. else
  74. with ref do
  75. begin
  76. first:=true;
  77. if ref.segment<>R_DEFAULT_SEG then
  78. s:=int_reg2str[segment]+':['
  79. else
  80. s:='[';
  81. if assigned(symbol) then
  82. begin
  83. s:=s+symbol^;
  84. first:=false;
  85. end;
  86. if (base<>R_NO) then
  87. begin
  88. if not(first) then
  89. s:=s+'+'
  90. else
  91. first:=false;
  92. s:=s+int_reg2str[base];
  93. end;
  94. if (index<>R_NO) then
  95. begin
  96. if not(first) then
  97. s:=s+'+'
  98. else
  99. first:=false;
  100. s:=s+int_reg2str[index];
  101. if scalefactor<>0 then
  102. s:=s+'*'+tostr(scalefactor);
  103. end;
  104. if offset<0 then
  105. s:=s+tostr(offset)
  106. else if (offset>0) then
  107. s:=s+'+'+tostr(offset);
  108. s:=s+']';
  109. end;
  110. getreferencestring:=s;
  111. end;
  112. function getopstr(t : byte;o : pointer;s : topsize; _operator: tasmop;dest : boolean) : string;
  113. var
  114. hs : string;
  115. begin
  116. case t of
  117. top_reg : getopstr:=int_reg2str[tregister(o)];
  118. top_const,
  119. top_ref : begin
  120. if t=top_const then
  121. hs := tostr(longint(o))
  122. else
  123. hs:=getreferencestring(preference(o)^);
  124. { can possibly give a range check error under tp }
  125. { if using in... }
  126. if ((_operator <> A_LGS) and (_operator <> A_LSS) and
  127. (_operator <> A_LFS) and (_operator <> A_LDS) and
  128. (_operator <> A_LES)) then
  129. Begin
  130. case s of
  131. S_B : hs:='byte ptr '+hs;
  132. S_W : hs:='word ptr '+hs;
  133. S_L : hs:='dword ptr '+hs;
  134. S_IS : hs:='word ptr '+hs;
  135. S_IL : hs:='dword ptr '+hs;
  136. S_IQ : hs:='qword ptr '+hs;
  137. S_FS : hs:='dword ptr '+hs;
  138. S_FL : hs:='qword ptr '+hs;
  139. S_FX : hs:='tbyte ptr '+hs;
  140. S_BW : if dest then
  141. hs:='word ptr '+hs
  142. else
  143. hs:='byte ptr '+hs;
  144. S_BL : if dest then
  145. hs:='dword ptr '+hs
  146. else
  147. hs:='byte ptr '+hs;
  148. S_WL : if dest then
  149. hs:='dword ptr '+hs
  150. else
  151. hs:='word ptr '+hs;
  152. end;
  153. end;
  154. getopstr:=hs;
  155. end;
  156. top_symbol : begin
  157. hs[0]:=chr(strlen(pchar(pcsymbol(o)^.symbol)));
  158. move(pchar(pcsymbol(o)^.symbol)^,hs[1],byte(hs[0]));
  159. hs:='offset '+hs;
  160. if pcsymbol(o)^.offset>0 then
  161. hs:=hs+'+'+tostr(pcsymbol(o)^.offset)
  162. else
  163. if pcsymbol(o)^.offset<0 then
  164. hs:=hs+tostr(pcsymbol(o)^.offset);
  165. getopstr:=hs;
  166. end;
  167. else
  168. internalerror(10001);
  169. end;
  170. end;
  171. function getopstr_jmp(t : byte;o : pointer) : string;
  172. var
  173. hs : string;
  174. begin
  175. case t of
  176. top_reg : getopstr_jmp:=int_reg2str[tregister(o)];
  177. top_ref : getopstr_jmp:=getreferencestring(preference(o)^);
  178. top_const : getopstr_jmp:=tostr(longint(o));
  179. top_symbol : begin
  180. hs[0]:=chr(strlen(pchar(pcsymbol(o)^.symbol)));
  181. move(pchar(pcsymbol(o)^.symbol)^,hs[1],byte(hs[0]));
  182. if pcsymbol(o)^.offset>0 then
  183. hs:=hs+'+'+tostr(pcsymbol(o)^.offset)
  184. else
  185. if pcsymbol(o)^.offset<0 then
  186. hs:=hs+tostr(pcsymbol(o)^.offset);
  187. getopstr_jmp:=hs;
  188. end;
  189. else
  190. internalerror(10001);
  191. end;
  192. end;
  193. {****************************************************************************
  194. TI386INTASMLIST
  195. ****************************************************************************}
  196. var
  197. LastSec : tsection;
  198. const
  199. ait_const2str:array[ait_const_32bit..ait_const_8bit] of string[8]=
  200. (#9'DD'#9,'',#9'DW'#9,#9'DB'#9);
  201. ait_section2masmstr : array[tsection] of string[6]=
  202. ('','CODE','DATA','BSS','');
  203. Function PadTabs(p:pchar;addch:char):string;
  204. var
  205. s : string;
  206. i : longint;
  207. begin
  208. i:=strlen(p);
  209. if addch<>#0 then
  210. begin
  211. inc(i);
  212. s:=StrPas(p)+addch;
  213. end
  214. else
  215. s:=StrPas(p);
  216. if i<8 then
  217. PadTabs:=s+#9#9
  218. else
  219. PadTabs:=s+#9;
  220. end;
  221. procedure ti386intasmlist.WriteTree(p:paasmoutput);
  222. type
  223. twowords=record
  224. word1,word2:word;
  225. end;
  226. var
  227. s,
  228. prefix,
  229. suffix : string;
  230. hp : pai;
  231. counter,
  232. lines,
  233. i,j,l : longint;
  234. consttyp : tait;
  235. found,
  236. quoted : boolean;
  237. begin
  238. if not assigned(p) then
  239. exit;
  240. hp:=pai(p^.first);
  241. while assigned(hp) do
  242. begin
  243. case hp^.typ of
  244. ait_comment : Begin
  245. AsmWrite(target_asm.comment);
  246. AsmWritePChar(pai_asm_comment(hp)^.str);
  247. AsmLn;
  248. End;
  249. ait_section : begin
  250. if LastSec<>sec_none then
  251. AsmWriteLn('_'+ait_section2masmstr[LastSec]+#9#9'ENDS');
  252. if pai_section(hp)^.sec<>sec_none then
  253. begin
  254. AsmLn;
  255. AsmWriteLn('_'+ait_section2masmstr[pai_section(hp)^.sec]+#9#9+
  256. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  257. ait_section2masmstr[pai_section(hp)^.sec]+'''');
  258. end;
  259. LastSec:=pai_section(hp)^.sec;
  260. end;
  261. ait_align : begin
  262. { CAUSES PROBLEMS WITH THE SEGMENT DEFINITION }
  263. { SEGMENT DEFINITION SHOULD MATCH TYPE OF ALIGN }
  264. { HERE UNDER TASM! }
  265. AsmWriteLn(#9'ALIGN '+tostr(pai_align(hp)^.aligntype));
  266. end;
  267. ait_external : AsmWriteLn(#9'EXTRN'#9+StrPas(pai_external(hp)^.name)+
  268. ' :'+extstr[pai_external(hp)^.exttyp]);
  269. ait_datablock : begin
  270. if pai_datablock(hp)^.is_global then
  271. AsmWriteLn(#9'PUBLIC'#9+StrPas(pai_datablock(hp)^.name));
  272. AsmWriteLn(PadTabs(pai_datablock(hp)^.name,#0)+'DB'#9+tostr(pai_datablock(hp)^.size)+' DUP(?)');
  273. end;
  274. ait_const_32bit,
  275. ait_const_8bit,
  276. ait_const_16bit : begin
  277. AsmWrite(ait_const2str[hp^.typ]+tostr(pai_const(hp)^.value));
  278. consttyp:=hp^.typ;
  279. l:=0;
  280. repeat
  281. found:=(not (Pai(hp^.next)=nil)) and (Pai(hp^.next)^.typ=consttyp);
  282. if found then
  283. begin
  284. hp:=Pai(hp^.next);
  285. s:=','+tostr(pai_const(hp)^.value);
  286. AsmWrite(s);
  287. inc(l,length(s));
  288. end;
  289. until (not found) or (l>line_length);
  290. AsmLn;
  291. end;
  292. ait_const_symbol : begin
  293. AsmWrite(#9#9+'DD '#9'offset ');
  294. AsmWritePChar(pchar(pai_const(hp)^.value));
  295. AsmLn;
  296. end;
  297. ait_real_32bit : AsmWriteLn(#9#9'DD'#9+double2str(pai_single(hp)^.value));
  298. ait_real_64bit : AsmWriteLn(#9#9'DQ'#9+double2str(pai_double(hp)^.value));
  299. ait_real_extended : AsmWriteLn(#9#9'DT'#9+double2str(pai_extended(hp)^.value));
  300. ait_comp : AsmWriteLn(#9#9'DQ'#9+comp2str(pai_extended(hp)^.value));
  301. ait_string : begin
  302. counter := 0;
  303. lines := pai_string(hp)^.len div line_length;
  304. { separate lines in different parts }
  305. if pai_string(hp)^.len > 0 then
  306. Begin
  307. for j := 0 to lines-1 do
  308. begin
  309. AsmWrite(#9#9'DB'#9);
  310. quoted:=false;
  311. for i:=counter to counter+line_length do
  312. begin
  313. { it is an ascii character. }
  314. if (ord(pai_string(hp)^.str[i])>31) and
  315. (ord(pai_string(hp)^.str[i])<128) and
  316. (pai_string(hp)^.str[i]<>'"') then
  317. begin
  318. if not(quoted) then
  319. begin
  320. if i>counter then
  321. AsmWrite(',');
  322. AsmWrite('"');
  323. end;
  324. AsmWrite(pai_string(hp)^.str[i]);
  325. quoted:=true;
  326. end { if > 31 and < 128 and ord('"') }
  327. else
  328. begin
  329. if quoted then
  330. AsmWrite('"');
  331. if i>counter then
  332. AsmWrite(',');
  333. quoted:=false;
  334. AsmWrite(tostr(ord(pai_string(hp)^.str[i])));
  335. end;
  336. end; { end for i:=0 to... }
  337. if quoted then AsmWrite('"');
  338. AsmWrite(target_os.newline);
  339. counter := counter+line_length;
  340. end; { end for j:=0 ... }
  341. { do last line of lines }
  342. AsmWrite(#9#9'DB'#9);
  343. quoted:=false;
  344. for i:=counter to pai_string(hp)^.len-1 do
  345. begin
  346. { it is an ascii character. }
  347. if (ord(pai_string(hp)^.str[i])>31) and
  348. (ord(pai_string(hp)^.str[i])<128) and
  349. (pai_string(hp)^.str[i]<>'"') then
  350. begin
  351. if not(quoted) then
  352. begin
  353. if i>counter then
  354. AsmWrite(',');
  355. AsmWrite('"');
  356. end;
  357. AsmWrite(pai_string(hp)^.str[i]);
  358. quoted:=true;
  359. end { if > 31 and < 128 and " }
  360. else
  361. begin
  362. if quoted then
  363. AsmWrite('"');
  364. if i>counter then
  365. AsmWrite(',');
  366. quoted:=false;
  367. AsmWrite(tostr(ord(pai_string(hp)^.str[i])));
  368. end;
  369. end; { end for i:=0 to... }
  370. if quoted then
  371. AsmWrite('"');
  372. end;
  373. AsmLn;
  374. end;
  375. ait_label : begin
  376. if pai_label(hp)^.l^.is_used then
  377. begin
  378. AsmWrite(lab2str(pai_label(hp)^.l));
  379. if (assigned(hp^.next) and not(pai(hp^.next)^.typ in
  380. [ait_const_32bit,ait_const_16bit,ait_const_8bit,ait_const_symbol,
  381. ait_real_32bit,ait_real_64bit,ait_real_extended,ait_string])) then
  382. AsmWriteLn(':');
  383. end;
  384. end;
  385. ait_direct : begin
  386. AsmWritePChar(pai_direct(hp)^.str);
  387. AsmLn;
  388. end;
  389. ait_labeled_instruction : AsmWriteLn(#9#9+int_op2str[pai_labeled(hp)^._operator]+#9+lab2str(pai_labeled(hp)^.lab));
  390. ait_symbol : begin
  391. if pai_symbol(hp)^.is_global then
  392. AsmWriteLn(#9'PUBLIC'#9+StrPas(pai_symbol(hp)^.name));
  393. AsmWritePChar(pai_symbol(hp)^.name);
  394. if assigned(hp^.next) and not(pai(hp^.next)^.typ in
  395. [ait_const_32bit,ait_const_16bit,ait_const_8bit,ait_const_symbol,
  396. ait_real_64bit,ait_real_extended,ait_string]) then
  397. AsmWriteLn(':')
  398. end;
  399. ait_instruction : begin
  400. suffix:='';
  401. prefix:= '';
  402. { added prefix instructions, must be on same line as opcode }
  403. if (pai386(hp)^.op1t = top_none) and
  404. ((pai386(hp)^._operator = A_REP) or
  405. (pai386(hp)^._operator = A_LOCK) or
  406. (pai386(hp)^._operator = A_REPE) or
  407. (pai386(hp)^._operator = A_REPNE)) then
  408. Begin
  409. prefix:=int_op2str[pai386(hp)^._operator]+#9;
  410. hp:=Pai(hp^.next);
  411. { this is theorically impossible... }
  412. if hp=nil then
  413. begin
  414. s:=#9#9+prefix;
  415. AsmWriteLn(s);
  416. break;
  417. end;
  418. end
  419. else
  420. prefix:= '';
  421. if pai386(hp)^.op1t<>top_none then
  422. begin
  423. if pai386(hp)^._operator in [A_CALL] then
  424. begin
  425. { with tasm call near ptr [edi+12] does not
  426. work but call near [edi+12] works ?? (PM)
  427. It works with call dword ptr [], but you
  428. need /m2 (2 passes) with tasm (PFV)
  429. }
  430. { if pai386(hp)^.op1t=top_ref then
  431. s:='near '+getopstr_jmp(pai386(hp)^.op1t,pai386(hp)^.op1)
  432. else
  433. s:='near ptr '+getopstr_jmp(pai386(hp)^.op1t,pai386(hp)^.op1);}
  434. s:='dword ptr '+getopstr_jmp(pai386(hp)^.op1t,pai386(hp)^.op1);
  435. end
  436. else
  437. begin
  438. s:=getopstr(pai386(hp)^.op1t,pai386(hp)^.op1,pai386(hp)^.size,pai386(hp)^._operator,false);
  439. if pai386(hp)^.op3t<>top_none then
  440. begin
  441. if pai386(hp)^.op2t<>top_none then
  442. s:=getopstr(pai386(hp)^.op2t,pointer(longint(twowords(pai386(hp)^.op2).word1)),
  443. pai386(hp)^.size,pai386(hp)^._operator,true)+','+s;
  444. s:=getopstr(pai386(hp)^.op3t,pointer(longint(twowords(pai386(hp)^.op2).word2)),
  445. pai386(hp)^.size,pai386(hp)^._operator,false)+','+s;
  446. end
  447. else
  448. if pai386(hp)^.op2t<>top_none then
  449. s:=getopstr(pai386(hp)^.op2t,pai386(hp)^.op2,pai386(hp)^.size,
  450. pai386(hp)^._operator,true)+','+s;
  451. end;
  452. s:=#9+s;
  453. end
  454. else
  455. begin
  456. { check if string instruction }
  457. { long form, otherwise may give range check errors }
  458. { in turbo pascal... }
  459. if ((pai386(hp)^._operator = A_CMPS) or
  460. (pai386(hp)^._operator = A_INS) or
  461. (pai386(hp)^._operator = A_OUTS) or
  462. (pai386(hp)^._operator = A_SCAS) or
  463. (pai386(hp)^._operator = A_STOS) or
  464. (pai386(hp)^._operator = A_MOVS) or
  465. (pai386(hp)^._operator = A_LODS) or
  466. (pai386(hp)^._operator = A_XLAT)) then
  467. Begin
  468. case pai386(hp)^.size of
  469. S_B: suffix:='b';
  470. S_W: suffix:='w';
  471. S_L: suffix:='d';
  472. else
  473. Message(assem_f_invalid_suffix_intel);
  474. end;
  475. end;
  476. s:='';
  477. end;
  478. AsmWriteLn(#9#9+prefix+int_op2str[pai386(hp)^._operator]+suffix+s);
  479. end;
  480. {$ifdef GDB}
  481. ait_stabn,
  482. ait_stabs,
  483. ait_stab_function_name : ;
  484. {$endif GDB}
  485. else
  486. internalerror(10000);
  487. end;
  488. hp:=pai(hp^.next);
  489. end;
  490. end;
  491. procedure ti386intasmlist.WriteAsmList;
  492. begin
  493. {$ifdef EXTDEBUG}
  494. if assigned(current_module^.mainsource) then
  495. comment(v_info,'Start writing intel-styled assembler output for '+current_module^.mainsource^);
  496. {$endif}
  497. LastSec:=sec_none;
  498. AsmWriteLn(#9'.386p');
  499. AsmWriteLn(#9'LOCALS '+target_asm.labelprefix);
  500. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  501. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  502. AsmLn;
  503. WriteTree(externals);
  504. { INTEL ASM doesn't support stabs
  505. WriteTree(debuglist);}
  506. WriteTree(codesegment);
  507. WriteTree(datasegment);
  508. WriteTree(consts);
  509. WriteTree(rttilist);
  510. WriteTree(bsssegment);
  511. AsmWriteLn(#9'END');
  512. AsmLn;
  513. {$ifdef EXTDEBUG}
  514. if assigned(current_module^.mainsource) then
  515. comment(v_info,'Done writing intel-styled assembler output for '+current_module^.mainsource^);
  516. {$endif EXTDEBUG}
  517. end;
  518. end.
  519. {
  520. $Log$
  521. Revision 1.10 1998-05-25 17:11:36 pierre
  522. * firstpasscount bug fixed
  523. now all is already set correctly the first time
  524. under EXTDEBUG try -gp to skip all other firstpasses
  525. it works !!
  526. * small bug fixes
  527. - for smallsets with -dTESTSMALLSET
  528. - some warnings removed (by correcting code !)
  529. Revision 1.9 1998/05/23 01:20:55 peter
  530. + aktasmmode, aktoptprocessor, aktoutputformat
  531. + smartlink per module $SMARTLINK-/+ (like MMX) and moved to aktswitches
  532. + $LIBNAME to set the library name where the unit will be put in
  533. * splitted cgi386 a bit (codeseg to large for bp7)
  534. * nasm, tasm works again. nasm moved to ag386nsm.pas
  535. Revision 1.8 1998/05/06 18:36:53 peter
  536. * tai_section extended with code,data,bss sections and enumerated type
  537. * ident 'compiled by FPC' moved to pmodules
  538. * small fix for smartlink
  539. Revision 1.7 1998/05/06 08:38:32 pierre
  540. * better position info with UseTokenInfo
  541. UseTokenInfo greatly simplified
  542. + added check for changed tree after first time firstpass
  543. (if we could remove all the cases were it happen
  544. we could skip all firstpass if firstpasscount > 1)
  545. Only with ExtDebug
  546. Revision 1.6 1998/05/04 17:54:24 peter
  547. + smartlinking works (only case jumptable left todo)
  548. * redesign of systems.pas to support assemblers and linkers
  549. + Unitname is now also in the PPU-file, increased version to 14
  550. Revision 1.5 1998/05/01 07:43:52 florian
  551. + basics for rtti implemented
  552. + switch $m (generate rtti for published sections)
  553. Revision 1.4 1998/04/29 10:33:41 pierre
  554. + added some code for ansistring (not complete nor working yet)
  555. * corrected operator overloading
  556. * corrected nasm output
  557. + started inline procedures
  558. + added starstarn : use ** for exponentiation (^ gave problems)
  559. + started UseTokenInfo cond to get accurate positions
  560. Revision 1.3 1998/04/08 16:58:01 pierre
  561. * several bugfixes
  562. ADD ADC and AND are also sign extended
  563. nasm output OK (program still crashes at end
  564. and creates wrong assembler files !!)
  565. procsym types sym in tdef removed !!
  566. Revision 1.2 1998/04/08 11:34:17 peter
  567. * nasm works (linux only tested)
  568. }