ag386int.pas 24 KB

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