agppcmpw.pas 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368
  1. {
  2. $Id$
  3. Copyright (c) 2002 by Florian Klaempfl
  4. This unit implements an asmoutput class for PowerPC with MPW syntax
  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. {
  19. This unit implements an asmoutput class for PowerPC with MPW syntax
  20. }
  21. unit agppcmpw;
  22. {$i fpcdefs.inc}
  23. interface
  24. uses
  25. aasmtai,
  26. globals,aasmbase,aasmcpu,assemble,
  27. cpubase;
  28. type
  29. TPPCMPWAssembler = class(TExternalAssembler)
  30. procedure WriteTree(p:TAAsmoutput);override;
  31. procedure WriteAsmList;override;
  32. Function DoAssemble:boolean;override;
  33. procedure WriteExternals;
  34. {$ifdef GDB}
  35. procedure WriteFileLineInfo(var fileinfo : tfileposinfo);
  36. procedure WriteFileEndInfo;
  37. {$endif}
  38. procedure WriteAsmFileHeader;
  39. private
  40. procedure WriteInstruction(hp : tai);
  41. procedure WriteProcedureHeader(var hp:tai);
  42. procedure WriteDataExportHeader(var s:string; isGlobal, isConst:boolean);
  43. end;
  44. implementation
  45. uses
  46. {$ifdef delphi}
  47. sysutils,
  48. {$endif}
  49. cutils,globtype,systems,cclasses,
  50. verbose,finput,fmodule,script,cpuinfo,
  51. cgbase,
  52. itcpugas
  53. ;
  54. const
  55. line_length = 70;
  56. {Whether internal procedure references should be xxx[PR]: }
  57. use_PR = false;
  58. const_storage_class = '[RW]';
  59. secnames : array[TAsmSectionType] of string[10] = ('',
  60. 'csect','csect [TC]','csect [TC]', {TODO: Perhaps use other section types.}
  61. '','','','','','','','','','','','',''
  62. );
  63. {$ifdef GDB}
  64. var
  65. n_line : byte; { different types of source lines }
  66. linecount,
  67. includecount : longint;
  68. funcname : pchar;
  69. stabslastfileinfo : tfileposinfo;
  70. isInFunction: Boolean;
  71. firstLineInFunction: longint;
  72. {$endif}
  73. function ReplaceForbiddenChars(var s: string):Boolean;
  74. {Returns wheater a replacement has occured.}
  75. var
  76. i:Integer;
  77. {The dollar sign is not allowed in MPW PPCAsm}
  78. begin
  79. ReplaceForbiddenChars:=false;
  80. for i:=1 to Length(s) do
  81. if s[i]='$' then
  82. begin
  83. s[i]:='s';
  84. ReplaceForbiddenChars:=true;
  85. end;
  86. end;
  87. {*** From here is copyed from agppcgas.pp, except where marked with CHANGED.
  88. Perhaps put in a third common file. ***}
  89. function getreferencestring(var ref : treference) : string;
  90. var
  91. s : string;
  92. begin
  93. with ref do
  94. begin
  95. if (refaddr <> addr_no) then
  96. InternalError(2002110301)
  97. else if ((offset < -32768) or (offset > 32767)) then
  98. InternalError(19991);
  99. if assigned(symbol) then
  100. begin
  101. s:= symbol.name;
  102. ReplaceForbiddenChars(s);
  103. {if symbol.typ = AT_FUNCTION then
  104. ;}
  105. s:= s+'[TC]' {ref to TOC entry }
  106. end
  107. else
  108. s:= '';
  109. if offset<0 then
  110. s:=s+tostr(offset)
  111. else
  112. if (offset>0) then
  113. begin
  114. if assigned(symbol) then
  115. s:=s+'+'+tostr(offset)
  116. else
  117. s:=s+tostr(offset);
  118. end;
  119. if (index=NR_NO) and (base<>NR_NO) then
  120. begin
  121. if offset=0 then
  122. if not assigned(symbol) then
  123. s:=s+'0';
  124. s:=s+'('+gas_regname(base)+')';
  125. end
  126. else if (index<>NR_NO) and (base<>NR_NO) and (offset=0) then
  127. begin
  128. if (offset=0) then
  129. s:=s+gas_regname(base)+','+gas_regname(index)
  130. else
  131. internalerror(19992);
  132. end
  133. else if (base=NR_NO) and (offset=0) then
  134. begin
  135. {Temporary fix for inline asm, where a local var is referenced.}
  136. //if assigned(symbol) then
  137. // s:= s+'(rtoc)';
  138. end;
  139. end;
  140. getreferencestring:=s;
  141. end;
  142. function getopstr_jmp(const o:toper) : string;
  143. var
  144. hs : string;
  145. begin
  146. case o.typ of
  147. top_reg :
  148. getopstr_jmp:=gas_regname(o.reg);
  149. { no top_ref jumping for powerpc }
  150. top_const :
  151. getopstr_jmp:=tostr(o.val);
  152. top_ref :
  153. begin
  154. if o.ref^.refaddr=addr_full then
  155. begin
  156. hs:=o.ref^.symbol.name;
  157. ReplaceForbiddenChars(hs);
  158. case o.ref^.symbol.typ of
  159. AT_FUNCTION:
  160. begin
  161. if hs[1] <> '@' then {if not local label}
  162. if use_PR then
  163. hs:= '.'+hs+'[PR]'
  164. else
  165. hs:= '.'+hs
  166. end
  167. else
  168. ;
  169. end;
  170. if o.ref^.offset>0 then
  171. hs:=hs+'+'+tostr(o.ref^.offset)
  172. else
  173. if o.ref^.offset<0 then
  174. hs:=hs+tostr(o.ref^.offset);
  175. getopstr_jmp:=hs;
  176. end
  177. else
  178. internalerror(200402263);
  179. end;
  180. top_none:
  181. getopstr_jmp:='';
  182. else
  183. internalerror(2002070603);
  184. end;
  185. end;
  186. function getopstr(const o:toper) : string;
  187. var
  188. hs : string;
  189. begin
  190. case o.typ of
  191. top_reg:
  192. getopstr:=gas_regname(o.reg);
  193. top_const:
  194. getopstr:=tostr(longint(o.val));
  195. top_ref:
  196. if o.ref^.refaddr=addr_no then
  197. getopstr:=getreferencestring(o.ref^)
  198. else
  199. begin
  200. hs:=o.ref^.symbol.name;
  201. ReplaceForbiddenChars(hs);
  202. if o.ref^.offset>0 then
  203. hs:=hs+'+'+tostr(o.ref^.offset)
  204. else
  205. if o.ref^.offset<0 then
  206. hs:=hs+tostr(o.ref^.offset);
  207. getopstr:=hs;
  208. end;
  209. else
  210. internalerror(2002070604);
  211. end;
  212. end;
  213. function branchmode(o: tasmop): string[4];
  214. var tempstr: string[4];
  215. begin
  216. tempstr := '';
  217. case o of
  218. A_BCCTR,A_BCCTRL: tempstr := 'ctr';
  219. A_BCLR,A_BCLRL: tempstr := 'lr';
  220. end;
  221. case o of
  222. A_BL,A_BLA,A_BCL,A_BCLA,A_BCCTRL,A_BCLRL: tempstr := tempstr+'l';
  223. end;
  224. case o of
  225. A_BA,A_BLA,A_BCA,A_BCLA: tempstr:=tempstr+'a';
  226. end;
  227. branchmode := tempstr;
  228. end;
  229. function cond2str(op: tasmop; c: tasmcond): string;
  230. { note: no checking is performed whether the given combination of }
  231. { conditions is valid }
  232. var
  233. tempstr: string;
  234. begin
  235. tempstr:=#9;
  236. case c.simple of
  237. false:
  238. begin
  239. cond2str := tempstr+gas_op2str[op];
  240. case c.dirhint of
  241. DH_None:;
  242. DH_Minus:
  243. cond2str:=cond2str+'-';
  244. DH_Plus:
  245. cond2str:=cond2str+'+';
  246. else
  247. internalerror(2003112901);
  248. end;
  249. cond2str:=cond2str+#9+tostr(c.bo)+','+tostr(c.bi)+',';
  250. end;
  251. true:
  252. if (op >= A_B) and (op <= A_BCLRL) then
  253. case c.cond of
  254. { unconditional branch }
  255. C_NONE:
  256. cond2str := tempstr+gas_op2str[op];
  257. { bdnzt etc }
  258. else
  259. begin
  260. tempstr := tempstr+'b'+asmcondflag2str[c.cond]+
  261. branchmode(op);
  262. case c.dirhint of
  263. DH_None:
  264. tempstr:=tempstr+#9;
  265. DH_Minus:
  266. tempstr:=tempstr+('-'+#9);
  267. DH_Plus:
  268. tempstr:=tempstr+('+'+#9);
  269. else
  270. internalerror(2003112901);
  271. end;
  272. case c.cond of
  273. C_LT..C_NU:
  274. cond2str := tempstr+gas_regname(newreg(R_SPECIALREGISTER,c.cr,R_SUBWHOLE));
  275. C_T,C_F,C_DNZT,C_DNZF,C_DZT,C_DZF:
  276. cond2str := tempstr+tostr(c.crbit);
  277. else
  278. cond2str := tempstr;
  279. end;
  280. end;
  281. end
  282. { we have a trap instruction }
  283. else
  284. begin
  285. internalerror(2002070601);
  286. { not yet implemented !!!!!!!!!!!!!!!!!!!!! }
  287. { case tempstr := 'tw';}
  288. end;
  289. end;
  290. end;
  291. procedure TPPCMPWAssembler.WriteInstruction(hp : tai);
  292. var op: TAsmOp;
  293. s: string;
  294. i: byte;
  295. sep: string[3];
  296. begin
  297. op:=taicpu(hp).opcode;
  298. if is_calljmp(op) then
  299. begin
  300. { direct BO/BI in op[0] and op[1] not supported, put them in condition! }
  301. case op of
  302. A_B,A_BA:
  303. s:=#9+gas_op2str[op]+#9;
  304. A_BCTR,A_BCTRL,A_BLR,A_BLRL:
  305. s:=#9+gas_op2str[op];
  306. A_BL,A_BLA:
  307. s:=#9+gas_op2str[op]+#9;
  308. else
  309. begin
  310. s:=cond2str(op,taicpu(hp).condition);
  311. if (s[length(s)] <> #9) and
  312. (taicpu(hp).ops>0) then
  313. s := s + ',';
  314. end;
  315. end;
  316. if (taicpu(hp).ops>0) and (taicpu(hp).oper[0]^.typ<>top_none) then
  317. begin
  318. { first write the current contents of s, because the symbol }
  319. { may be 255 characters }
  320. asmwrite(s);
  321. s:=getopstr_jmp(taicpu(hp).oper[0]^);
  322. end;
  323. end
  324. else
  325. { process operands }
  326. begin
  327. s:=#9+gas_op2str[op];
  328. if taicpu(hp).ops<>0 then
  329. begin
  330. sep:=#9;
  331. for i:=0 to taicpu(hp).ops-1 do
  332. begin
  333. s:=s+sep+getopstr(taicpu(hp).oper[i]^);
  334. sep:=',';
  335. end;
  336. end;
  337. end;
  338. AsmWriteLn(s);
  339. end;
  340. {*** Until here is copyed from agppcgas.pp. ***}
  341. function single2str(d : single) : string;
  342. var
  343. hs : string;
  344. p : byte;
  345. begin
  346. str(d,hs);
  347. { nasm expects a lowercase e }
  348. p:=pos('E',hs);
  349. if p>0 then
  350. hs[p]:='e';
  351. p:=pos('+',hs);
  352. if p>0 then
  353. delete(hs,p,1);
  354. single2str:=lower(hs);
  355. end;
  356. function double2str(d : double) : string;
  357. var
  358. hs : string;
  359. p : byte;
  360. begin
  361. str(d,hs);
  362. { nasm expects a lowercase e }
  363. p:=pos('E',hs);
  364. if p>0 then
  365. hs[p]:='e';
  366. p:=pos('+',hs);
  367. if p>0 then
  368. delete(hs,p,1);
  369. double2str:=lower(hs);
  370. end;
  371. function fixline(s:string):string;
  372. {
  373. return s with all leading and ending spaces and tabs removed
  374. }
  375. var
  376. i,j,k : longint;
  377. begin
  378. i:=length(s);
  379. while (i>0) and (s[i] in [#9,' ']) do
  380. dec(i);
  381. j:=1;
  382. while (j<i) and (s[j] in [#9,' ']) do
  383. inc(j);
  384. for k:=j to i do
  385. if s[k] in [#0..#31,#127..#255] then
  386. s[k]:='.';
  387. fixline:=Copy(s,j,i-j+1);
  388. end;
  389. {****************************************************************************
  390. PowerPC MPW Assembler
  391. ****************************************************************************}
  392. procedure TPPCMPWAssembler.WriteProcedureHeader(var hp:tai);
  393. {Returns the current hp where the caller should continue from}
  394. {For multiple entry procedures, only the last is exported as xxx[PR]
  395. (if use_PR is set) }
  396. procedure WriteExportHeader(hp:tai);
  397. var
  398. s: string;
  399. replaced: boolean;
  400. begin
  401. s:= tai_symbol(hp).sym.name;
  402. replaced:= ReplaceForbiddenChars(s);
  403. if not use_PR then
  404. begin
  405. AsmWrite(#9'export'#9'.');
  406. AsmWrite(s);
  407. if replaced then
  408. begin
  409. AsmWrite(' => ''.');
  410. AsmWrite(tai_symbol(hp).sym.name);
  411. AsmWrite('''');
  412. end;
  413. AsmLn;
  414. end;
  415. AsmWrite(#9'export'#9);
  416. AsmWrite(s);
  417. AsmWrite('[DS]');
  418. if replaced then
  419. begin
  420. AsmWrite(' => ''');
  421. AsmWrite(tai_symbol(hp).sym.name);
  422. AsmWrite('[DS]''');
  423. end;
  424. AsmLn;
  425. {Entry in transition vector: }
  426. AsmWrite(#9'csect'#9); AsmWrite(s); AsmWriteLn('[DS]');
  427. AsmWrite(#9'dc.l'#9'.'); AsmWriteLn(s);
  428. AsmWriteln(#9'dc.l'#9'TOC[tc0]');
  429. {Entry in TOC: }
  430. AsmWriteLn(#9'toc');
  431. AsmWrite(#9'tc'#9);
  432. AsmWrite(s); AsmWrite('[TC],');
  433. AsmWrite(s); AsmWriteln('[DS]');
  434. end;
  435. function GetAdjacentTaiSymbol(var hp:tai):Boolean;
  436. begin
  437. GetAdjacentTaiSymbol:= false;
  438. while assigned(hp.next) do
  439. case tai(hp.next).typ of
  440. ait_symbol:
  441. begin
  442. hp:=tai(hp.next);
  443. GetAdjacentTaiSymbol:= true;
  444. Break;
  445. end;
  446. ait_stab_function_name:
  447. hp:=tai(hp.next);
  448. else
  449. begin
  450. //AsmWriteln(' ;#*#*# ' + tostr(Ord(tai(hp.next).typ)));
  451. Break;
  452. end;
  453. end;
  454. end;
  455. var
  456. first,last: tai;
  457. s: string;
  458. replaced: boolean;
  459. begin
  460. s:= tai_symbol(hp).sym.name;
  461. {Write all headers}
  462. first:= hp;
  463. repeat
  464. WriteExportHeader(hp);
  465. last:= hp;
  466. until not GetAdjacentTaiSymbol(hp);
  467. {Start the section of the body of the proc: }
  468. s:= tai_symbol(last).sym.name;
  469. replaced:= ReplaceForbiddenChars(s);
  470. if use_PR then
  471. begin
  472. AsmWrite(#9'export'#9'.'); AsmWrite(s); AsmWrite('[PR]');
  473. if replaced then
  474. begin
  475. AsmWrite(' => ''.');
  476. AsmWrite(tai_symbol(last).sym.name);
  477. AsmWrite('[PR]''');
  478. end;
  479. AsmLn;
  480. end;
  481. {Starts the section: }
  482. AsmWrite(#9'csect'#9'.');
  483. AsmWrite(s);
  484. AsmWriteLn('[PR]');
  485. {Info for the debugger: }
  486. AsmWrite(#9'function'#9'.');
  487. AsmWrite(s);
  488. AsmWriteLn('[PR]');
  489. {$ifdef GDB}
  490. if ((cs_debuginfo in aktmoduleswitches) or
  491. (cs_gdb_lineinfo in aktglobalswitches)) then
  492. begin
  493. //info for debuggers:
  494. firstLineInFunction:= stabslastfileinfo.line;
  495. AsmWriteLn(#9'beginf ' + tostr(firstLineInFunction));
  496. isInFunction:= true;
  497. end;
  498. {$endif}
  499. {Write all labels: }
  500. hp:= first;
  501. repeat
  502. s:= tai_symbol(hp).sym.name;
  503. ReplaceForbiddenChars(s);
  504. AsmWrite('.'); AsmWrite(s); AsmWriteLn(':');
  505. until not GetAdjacentTaiSymbol(hp);
  506. end;
  507. procedure TPPCMPWAssembler.WriteDataExportHeader(var s:string; isGlobal, isConst:boolean);
  508. // Returns in s the changed string
  509. var
  510. sym: string;
  511. replaced: boolean;
  512. begin
  513. sym:= s;
  514. replaced:= ReplaceForbiddenChars(s);
  515. if isGlobal then
  516. begin
  517. AsmWrite(#9'export'#9);
  518. AsmWrite(s);
  519. if isConst then
  520. AsmWrite(const_storage_class)
  521. else
  522. AsmWrite('[RW]');
  523. if replaced then
  524. begin
  525. AsmWrite(' => ''');
  526. AsmWrite(sym);
  527. AsmWrite('''');
  528. end;
  529. AsmLn;
  530. end;
  531. if not macos_direct_globals then
  532. begin
  533. AsmWriteLn(#9'toc');
  534. AsmWrite(#9'tc'#9);
  535. AsmWrite(s);
  536. AsmWrite('[TC], ');
  537. AsmWrite(s);
  538. if isConst then
  539. AsmWrite(const_storage_class)
  540. else
  541. AsmWrite('[RW]');
  542. AsmLn;
  543. AsmWrite(#9'csect'#9);
  544. AsmWrite(s);
  545. if isConst then
  546. AsmWrite(const_storage_class)
  547. else
  548. AsmWrite('[RW]');
  549. end
  550. else
  551. begin
  552. AsmWrite(#9'csect'#9);
  553. AsmWrite(s);
  554. AsmWrite('[TC]');
  555. end;
  556. AsmLn;
  557. end;
  558. var
  559. LasTSec : TAsmSectionType;
  560. lastfileinfo : tfileposinfo;
  561. infile,
  562. lastinfile : tinputfile;
  563. const
  564. ait_const2str:array[ait_const_32bit..ait_const_8bit] of string[8]=
  565. (#9'dc.l'#9,#9'dc.w'#9,#9'dc.b'#9);
  566. Function PadTabs(const p:string;addch:char):string;
  567. var
  568. s : string;
  569. i : longint;
  570. begin
  571. i:=length(p);
  572. if addch<>#0 then
  573. begin
  574. inc(i);
  575. s:=p+addch;
  576. end
  577. else
  578. s:=p;
  579. if i<8 then
  580. PadTabs:=s+#9#9
  581. else
  582. PadTabs:=s+#9;
  583. end;
  584. {$ifdef GDB}
  585. procedure TPPCMPWAssembler.WriteFileLineInfo(var fileinfo : tfileposinfo);
  586. var
  587. curr_n : byte;
  588. begin
  589. if not ((cs_debuginfo in aktmoduleswitches) or
  590. (cs_gdb_lineinfo in aktglobalswitches)) then
  591. exit;
  592. { file changed ? (must be before line info) }
  593. if (fileinfo.fileindex<>0) and
  594. (stabslastfileinfo.fileindex<>fileinfo.fileindex) then
  595. begin
  596. infile:=current_module.sourcefiles.get_file(fileinfo.fileindex);
  597. if assigned(infile) then
  598. begin
  599. (*
  600. if includecount=0 then
  601. curr_n:=n_sourcefile
  602. else
  603. curr_n:=n_includefile;
  604. if (infile.path^<>'') then
  605. begin
  606. AsmWriteLn(#9'.stabs "'+lower(BsToSlash(FixPath(infile.path^,false)))+'",'+
  607. tostr(curr_n)+',0,0,'+target_asm.labelprefix+'text'+ToStr(IncludeCount));
  608. end;
  609. AsmWriteLn(#9'.stabs "'+lower(FixFileName(infile.name^))+'",'+
  610. tostr(curr_n)+',0,0,'+target_asm.labelprefix+'text'+ToStr(IncludeCount));
  611. *)
  612. AsmWriteLn(#9'file '''+lower(FixFileName(infile.name^))+'''');
  613. (*
  614. AsmWriteLn(target_asm.labelprefix+'text'+ToStr(IncludeCount)+':');
  615. *)
  616. inc(includecount);
  617. { force new line info }
  618. stabslastfileinfo.line:=-1;
  619. end;
  620. end;
  621. { line changed ? }
  622. if (stabslastfileinfo.line<>fileinfo.line) and (fileinfo.line<>0) then
  623. begin
  624. (*
  625. if (n_line=n_textline) and assigned(funcname) and
  626. (target_info.use_function_relative_addresses) then
  627. begin
  628. AsmWriteLn(target_asm.labelprefix+'l'+tostr(linecount)+':');
  629. AsmWrite(#9'.stabn '+tostr(n_line)+',0,'+tostr(fileinfo.line)+','+
  630. target_asm.labelprefix+'l'+tostr(linecount)+' - ');
  631. AsmWritePChar(FuncName);
  632. AsmLn;
  633. inc(linecount);
  634. end
  635. else
  636. AsmWriteLn(#9'.stabd'#9+tostr(n_line)+',0,'+tostr(fileinfo.line));
  637. *)
  638. if isInFunction then
  639. AsmWriteln(#9'line '+ tostr(fileinfo.line - firstLineInFunction - 1));
  640. end;
  641. stabslastfileinfo:=fileinfo;
  642. end;
  643. procedure TPPCMPWAssembler.WriteFileEndInfo;
  644. begin
  645. if not ((cs_debuginfo in aktmoduleswitches) or
  646. (cs_gdb_lineinfo in aktglobalswitches)) then
  647. exit;
  648. AsmLn;
  649. (*
  650. AsmWriteLn(ait_section2str(sec_code));
  651. AsmWriteLn(#9'.stabs "",'+tostr(n_sourcefile)+',0,0,'+target_asm.labelprefix+'etext');
  652. AsmWriteLn(target_asm.labelprefix+'etext:');
  653. *)
  654. end;
  655. {$endif}
  656. procedure TPPCMPWAssembler.WriteTree(p:TAAsmoutput);
  657. var
  658. s,
  659. prefix,
  660. suffix : string;
  661. hp : tai;
  662. hp1 : tailineinfo;
  663. counter,
  664. lines,
  665. InlineLevel : longint;
  666. i,j,l : longint;
  667. consttyp : taitype;
  668. found,
  669. do_line,DoNotSplitLine,
  670. quoted : boolean;
  671. sep : char;
  672. replaced : boolean;
  673. begin
  674. if not assigned(p) then
  675. exit;
  676. InlineLevel:=0;
  677. { lineinfo is only needed for codesegment (PFV) }
  678. do_line:=((cs_asm_source in aktglobalswitches) or
  679. (cs_lineinfo in aktmoduleswitches))
  680. and (p=codesegment);
  681. DoNotSplitLine:=false;
  682. hp:=tai(p.first);
  683. while assigned(hp) do
  684. begin
  685. if not(hp.typ in SkipLineInfo) and
  686. not DoNotSplitLine then
  687. begin
  688. hp1 := hp as tailineinfo;
  689. {$ifdef GDB}
  690. { write debug info }
  691. if (cs_debuginfo in aktmoduleswitches) or
  692. (cs_gdb_lineinfo in aktglobalswitches) then
  693. WriteFileLineInfo(hp1.fileinfo);
  694. {$endif GDB}
  695. if do_line then
  696. begin
  697. { load infile }
  698. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  699. begin
  700. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  701. if assigned(infile) then
  702. begin
  703. { open only if needed !! }
  704. if (cs_asm_source in aktglobalswitches) then
  705. infile.open;
  706. end;
  707. { avoid unnecessary reopens of the same file !! }
  708. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  709. { be sure to change line !! }
  710. lastfileinfo.line:=-1;
  711. end;
  712. { write source }
  713. if (cs_asm_source in aktglobalswitches) and
  714. assigned(infile) then
  715. begin
  716. if (infile<>lastinfile) then
  717. begin
  718. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  719. if assigned(lastinfile) then
  720. lastinfile.close;
  721. end;
  722. if (hp1.fileinfo.line<>lastfileinfo.line) and
  723. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  724. begin
  725. if (hp1.fileinfo.line<>0) and
  726. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  727. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  728. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  729. { set it to a negative value !
  730. to make that is has been read already !! PM }
  731. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  732. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  733. end;
  734. end;
  735. lastfileinfo:=hp1.fileinfo;
  736. lastinfile:=infile;
  737. end;
  738. end;
  739. DoNotSplitLine:=false;
  740. case hp.typ of
  741. ait_comment:
  742. begin
  743. AsmWrite(target_asm.comment);
  744. AsmWritePChar(tai_comment(hp).str);
  745. AsmLn;
  746. end;
  747. ait_regalloc,
  748. ait_tempalloc:
  749. ;
  750. ait_section:
  751. begin
  752. {if LasTSec<>sec_none then
  753. AsmWriteLn('_'+target_asm.secnames[LasTSec]+#9#9'ENDS');}
  754. if tai_section(hp).sectype<>sec_none then
  755. begin
  756. AsmLn;
  757. AsmWriteLn(#9+secnames[tai_section(hp).sectype]);
  758. {$ifdef GDB}
  759. lastfileinfo.line:=-1;
  760. {$endif GDB}
  761. end;
  762. LasTSec:=tai_section(hp).sectype;
  763. end;
  764. ait_align:
  765. begin
  766. case tai_align(hp).aligntype of
  767. 1:AsmWriteLn(#9'align 0');
  768. 2:AsmWriteLn(#9'align 1');
  769. 4:AsmWriteLn(#9'align 2');
  770. otherwise internalerror(2002110302);
  771. end;
  772. end;
  773. ait_datablock:
  774. begin
  775. s:= tai_datablock(hp).sym.name;
  776. WriteDataExportHeader(s, tai_datablock(hp).is_global, false);
  777. if not macos_direct_globals then
  778. begin
  779. AsmWriteLn(#9'ds.b '+tostr(tai_datablock(hp).size));
  780. end
  781. else
  782. begin
  783. AsmWriteLn(PadTabs(s+':',#0)+'ds.b '+tostr(tai_datablock(hp).size));
  784. {TODO: ? PadTabs(s,#0) }
  785. end;
  786. end;
  787. ait_const_uleb128bit,
  788. ait_const_sleb128bit,
  789. ait_const_128bit,
  790. ait_const_64bit,
  791. ait_const_32bit,
  792. ait_const_16bit,
  793. ait_const_8bit,
  794. ait_const_rva_symbol,
  795. ait_const_indirect_symbol :
  796. begin
  797. AsmWrite(ait_const2str[hp.typ]);
  798. consttyp:=hp.typ;
  799. l:=0;
  800. repeat
  801. if assigned(tai_const(hp).sym) then
  802. begin
  803. if use_PR then
  804. AsmWrite('.');
  805. if assigned(tai_const(hp).endsym) then
  806. s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
  807. else
  808. s:=tai_const(hp).sym.name;
  809. ReplaceForbiddenChars(s);
  810. if tai_const(hp).value<>0 then
  811. InternalError(2002110101);
  812. if use_PR then
  813. AsmWriteLn('[PR]')
  814. else
  815. AsmWriteLn('[DS]');
  816. end
  817. else
  818. s:=tostr(tai_const(hp).value);
  819. AsmWrite(s);
  820. if (l>line_length) or
  821. (hp.next=nil) or
  822. (tai(hp.next).typ<>consttyp) then
  823. break;
  824. hp:=tai(hp.next);
  825. AsmWrite(',');
  826. until false;
  827. AsmLn;
  828. end;
  829. ait_real_32bit:
  830. AsmWriteLn(#9'dc.l'#9'"'+single2str(tai_real_32bit(hp).value)+'"');
  831. ait_real_64bit:
  832. AsmWriteLn(#9'dc.d'#9'"'+double2str(tai_real_64bit(hp).value)+'"');
  833. ait_string:
  834. begin
  835. {NOTE When a single quote char is encountered, it is
  836. replaced with a numeric ascii value. It could also
  837. have been replaced with the escape seq of double quotes.
  838. Backslash seems to be used as an escape char, although
  839. this is not mentioned in the PPCAsm documentation.}
  840. counter := 0;
  841. lines := tai_string(hp).len div line_length;
  842. { separate lines in different parts }
  843. if tai_string(hp).len > 0 then
  844. begin
  845. for j := 0 to lines-1 do
  846. begin
  847. AsmWrite(#9'dc.b'#9);
  848. quoted:=false;
  849. for i:=counter to counter+line_length-1 do
  850. begin
  851. { it is an ascii character. }
  852. if (ord(tai_string(hp).str[i])>31) and
  853. (ord(tai_string(hp).str[i])<128) and
  854. (tai_string(hp).str[i]<>'''') and
  855. (tai_string(hp).str[i]<>'\') then
  856. begin
  857. if not(quoted) then
  858. begin
  859. if i>counter then
  860. AsmWrite(',');
  861. AsmWrite('''');
  862. end;
  863. AsmWrite(tai_string(hp).str[i]);
  864. quoted:=true;
  865. end { if > 31 and < 128 and ord('"') }
  866. else
  867. begin
  868. if quoted then
  869. AsmWrite('''');
  870. if i>counter then
  871. AsmWrite(',');
  872. quoted:=false;
  873. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  874. end;
  875. end; { end for i:=0 to... }
  876. if quoted then AsmWrite('''');
  877. AsmLn;
  878. counter := counter+line_length;
  879. end; { end for j:=0 ... }
  880. { do last line of lines }
  881. if counter < tai_string(hp).len then
  882. AsmWrite(#9'dc.b'#9);
  883. quoted:=false;
  884. for i:=counter to tai_string(hp).len-1 do
  885. begin
  886. { it is an ascii character. }
  887. if (ord(tai_string(hp).str[i])>31) and
  888. (ord(tai_string(hp).str[i])<128) and
  889. (tai_string(hp).str[i]<>'''') and
  890. (tai_string(hp).str[i]<>'\') then
  891. begin
  892. if not(quoted) then
  893. begin
  894. if i>counter then
  895. AsmWrite(',');
  896. AsmWrite('''');
  897. end;
  898. AsmWrite(tai_string(hp).str[i]);
  899. quoted:=true;
  900. end { if > 31 and < 128 and " }
  901. else
  902. begin
  903. if quoted then
  904. AsmWrite('''');
  905. if i>counter then
  906. AsmWrite(',');
  907. quoted:=false;
  908. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  909. end;
  910. end; { end for i:=0 to... }
  911. if quoted then
  912. AsmWrite('''');
  913. end;
  914. AsmLn;
  915. end;
  916. ait_label:
  917. begin
  918. if tai_label(hp).l.is_used then
  919. begin
  920. s:= tai_label(hp).l.name;
  921. ReplaceForbiddenChars(s);
  922. if s[1] = '@' then
  923. //Local labels:
  924. AsmWriteLn(s+':')
  925. else
  926. begin
  927. //Procedure entry points:
  928. if not macos_direct_globals then
  929. begin
  930. AsmWriteLn(#9'toc');
  931. AsmWrite(#9'tc'#9); AsmWrite(s);
  932. AsmWrite('[TC], '); AsmWrite(s);
  933. AsmWriteLn(const_storage_class);
  934. AsmWrite(#9'csect'#9); AsmWrite(s);
  935. AsmWriteLn(const_storage_class);
  936. end
  937. else
  938. begin
  939. AsmWrite(#9'csect'#9); AsmWrite(s);
  940. AsmWriteLn('[TC]');
  941. AsmWriteLn(PadTabs(s+':',#0));
  942. end;
  943. end;
  944. end;
  945. end;
  946. ait_direct:
  947. begin
  948. AsmWritePChar(tai_direct(hp).str);
  949. AsmLn;
  950. end;
  951. ait_symbol:
  952. begin
  953. if tai_symbol(hp).sym.typ=AT_FUNCTION then
  954. WriteProcedureHeader(hp)
  955. else if tai_symbol(hp).sym.typ=AT_DATA then
  956. begin
  957. s:= tai_symbol(hp).sym.name;
  958. WriteDataExportHeader(s, tai_symbol(hp).is_global, true);
  959. if macos_direct_globals then
  960. begin
  961. AsmWrite(s);
  962. AsmWriteLn(':');
  963. end;
  964. end
  965. else
  966. InternalError(2003071301);
  967. end;
  968. ait_symbol_end:
  969. {$ifdef GDB}
  970. if isInFunction then
  971. if ((cs_debuginfo in aktmoduleswitches) or
  972. (cs_gdb_lineinfo in aktglobalswitches)) then
  973. begin
  974. //info for debuggers:
  975. AsmWriteLn(#9'endf ' + tostr(stabslastfileinfo.line));
  976. isInFunction:= false;
  977. end
  978. {$endif GDB}
  979. ;
  980. ait_instruction:
  981. WriteInstruction(hp);
  982. {$ifdef GDB}
  983. ait_stabn: ;
  984. ait_stabs: ;
  985. ait_force_line :
  986. stabslastfileinfo.line:=0;
  987. ait_stab_function_name: ;
  988. {$endif GDB}
  989. ait_cutobject :
  990. begin
  991. { only reset buffer if nothing has changed }
  992. if AsmSize=AsmStartSize then
  993. AsmClear
  994. else
  995. begin
  996. {
  997. if LasTSec<>sec_none then
  998. AsmWriteLn('_'+target_asm.secnames[LasTSec]+#9#9'ends');
  999. AsmLn;
  1000. }
  1001. AsmWriteLn(#9'end');
  1002. AsmClose;
  1003. DoAssemble;
  1004. AsmCreate(tai_cutobject(hp).place);
  1005. end;
  1006. { avoid empty files }
  1007. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  1008. begin
  1009. if tai(hp.next).typ=ait_section then
  1010. begin
  1011. lasTSec:=tai_section(hp.next).sectype;
  1012. end;
  1013. hp:=tai(hp.next);
  1014. end;
  1015. WriteAsmFileHeader;
  1016. if lasTSec<>sec_none then
  1017. AsmWriteLn(#9+secnames[lasTSec]);
  1018. { AsmWriteLn('_'+target_asm.secnames[lasTSec]+#9#9+
  1019. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  1020. target_asm.secnames[lasTSec]+'''');
  1021. }
  1022. AsmStartSize:=AsmSize;
  1023. end;
  1024. ait_marker :
  1025. begin
  1026. if tai_marker(hp).kind=InlineStart then
  1027. inc(InlineLevel)
  1028. else if tai_marker(hp).kind=InlineEnd then
  1029. dec(InlineLevel);
  1030. end;
  1031. else
  1032. internalerror(2002110303);
  1033. end;
  1034. hp:=tai(hp.next);
  1035. end;
  1036. end;
  1037. var
  1038. currentasmlist : TExternalAssembler;
  1039. procedure writeexternal(p:tnamedindexitem;arg:pointer);
  1040. var
  1041. s:string;
  1042. replaced: boolean;
  1043. begin
  1044. if tasmsymbol(p).defbind=AB_EXTERNAL then
  1045. begin
  1046. //Writeln('ZZZ ',p.name,' ',p.classname,' ',Ord(tasmsymbol(p).typ));
  1047. s:= p.name;
  1048. replaced:= ReplaceForbiddenChars(s);
  1049. with currentasmlist do
  1050. case tasmsymbol(p).typ of
  1051. AT_FUNCTION:
  1052. begin
  1053. AsmWrite(#9'import'#9'.');
  1054. AsmWrite(s);
  1055. if use_PR then
  1056. AsmWrite('[PR]');
  1057. if replaced then
  1058. begin
  1059. AsmWrite(' <= ''.');
  1060. AsmWrite(p.name);
  1061. if use_PR then
  1062. AsmWrite('[PR]''')
  1063. else
  1064. AsmWrite('''');
  1065. end;
  1066. AsmLn;
  1067. AsmWrite(#9'import'#9);
  1068. AsmWrite(s);
  1069. AsmWrite('[DS]');
  1070. if replaced then
  1071. begin
  1072. AsmWrite(' <= ''');
  1073. AsmWrite(p.name);
  1074. AsmWrite('[DS]''');
  1075. end;
  1076. AsmLn;
  1077. AsmWriteLn(#9'toc');
  1078. AsmWrite(#9'tc'#9);
  1079. AsmWrite(s);
  1080. AsmWrite('[TC],');
  1081. AsmWrite(s);
  1082. AsmWriteLn('[DS]');
  1083. end;
  1084. AT_DATA:
  1085. begin
  1086. AsmWrite(#9'import'#9);
  1087. AsmWrite(s);
  1088. AsmWrite('[RW]');
  1089. if replaced then
  1090. begin
  1091. AsmWrite(' <= ''');
  1092. AsmWrite(p.name);
  1093. AsmWrite('''');
  1094. end;
  1095. AsmLn;
  1096. AsmWriteLn(#9'toc');
  1097. AsmWrite(#9'tc'#9);
  1098. AsmWrite(s);
  1099. AsmWrite('[TC],');
  1100. AsmWrite(s);
  1101. AsmWriteLn('[RW]');
  1102. end
  1103. else
  1104. InternalError(2003090901);
  1105. end;
  1106. end;
  1107. end;
  1108. procedure TPPCMPWAssembler.WriteExternals;
  1109. begin
  1110. currentasmlist:=self;
  1111. objectlibrary.symbolsearch.foreach_static({$ifdef fpcprocvar}@{$endif}writeexternal,nil);
  1112. end;
  1113. function TPPCMPWAssembler.DoAssemble : boolean;
  1114. var f : file;
  1115. begin
  1116. DoAssemble:=Inherited DoAssemble;
  1117. (*
  1118. { masm does not seem to recognize specific extensions and uses .obj allways PM }
  1119. if (aktoutputformat = as_i386_masm) then
  1120. begin
  1121. if not(cs_asm_extern in aktglobalswitches) then
  1122. begin
  1123. if Not FileExists(objfile) and
  1124. FileExists(ForceExtension(objfile,'.obj')) then
  1125. begin
  1126. Assign(F,ForceExtension(objfile,'.obj'));
  1127. Rename(F,objfile);
  1128. end;
  1129. end
  1130. else
  1131. AsmRes.AddAsmCommand('mv',ForceExtension(objfile,'.obj')+' '+objfile,objfile);
  1132. end;
  1133. *)
  1134. end;
  1135. procedure TPPCMPWAssembler.WriteAsmFileHeader;
  1136. begin
  1137. (*
  1138. AsmWriteLn(#9'.386p');
  1139. { masm 6.11 does not seem to like LOCALS PM }
  1140. if (aktoutputformat = as_i386_tasm) then
  1141. begin
  1142. AsmWriteLn(#9'LOCALS '+target_asm.labelprefix);
  1143. end;
  1144. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  1145. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  1146. AsmLn;
  1147. *)
  1148. AsmWriteLn(#9'string asis'); {Interpret strings just to be the content between the quotes.}
  1149. AsmWriteLn(#9'aligning off'); {We do our own aligning.}
  1150. AsmLn;
  1151. end;
  1152. procedure TPPCMPWAssembler.WriteAsmList;
  1153. {$ifdef GDB}
  1154. var
  1155. fileinfo : tfileposinfo;
  1156. {$endif GDB}
  1157. begin
  1158. {$ifdef EXTDEBUG}
  1159. if assigned(current_module.mainsource) then
  1160. comment(v_info,'Start writing MPW-styled assembler output for '+current_module.mainsource^);
  1161. {$endif}
  1162. LasTSec:=sec_none;
  1163. {$ifdef GDB}
  1164. FillChar(stabslastfileinfo,sizeof(stabslastfileinfo),0);
  1165. {$endif GDB}
  1166. {$ifdef GDB}
  1167. //n_line:=n_bssline;
  1168. funcname:=nil;
  1169. linecount:=1;
  1170. includecount:=0;
  1171. fileinfo.fileindex:=1;
  1172. fileinfo.line:=1;
  1173. isInFunction:= false;
  1174. firstLineInFunction:= 0;
  1175. { Write main file }
  1176. WriteFileLineInfo(fileinfo);
  1177. {$endif GDB}
  1178. WriteAsmFileHeader;
  1179. WriteExternals;
  1180. { PowerPC MPW ASM doesn't support stabs, as we know.
  1181. WriteTree(debuglist);}
  1182. WriteTree(codesegment);
  1183. WriteTree(datasegment);
  1184. WriteTree(consts);
  1185. WriteTree(rttilist);
  1186. WriteTree(resourcestringlist);
  1187. WriteTree(bsssegment);
  1188. {$ifdef GDB}
  1189. WriteFileEndInfo;
  1190. {$ENDIF}
  1191. AsmWriteLn(#9'end');
  1192. AsmLn;
  1193. {$ifdef EXTDEBUG}
  1194. if assigned(current_module.mainsource) then
  1195. comment(v_info,'Done writing MPW-styled assembler output for '+current_module.mainsource^);
  1196. {$endif EXTDEBUG}
  1197. end;
  1198. {*****************************************************************************
  1199. Initialize
  1200. *****************************************************************************}
  1201. const
  1202. as_powerpc_mpw_info : tasminfo =
  1203. (
  1204. id : as_powerpc_mpw;
  1205. idtxt : 'MPW';
  1206. asmbin : 'PPCAsm';
  1207. asmcmd : '-case on $ASM -o $OBJ';
  1208. supported_target : system_any; { what should I write here ?? }
  1209. flags : [af_allowdirect,af_needar,af_smartlink_sections,af_labelprefix_only_inside_procedure];
  1210. labelprefix : '@';
  1211. comment : '; ';
  1212. );
  1213. initialization
  1214. RegisterAssembler(as_powerpc_mpw_info,TPPCMPWAssembler);
  1215. end.
  1216. {
  1217. $Log$
  1218. Revision 1.36 2004-06-20 08:55:31 florian
  1219. * logs truncated
  1220. Revision 1.35 2004/06/17 16:55:46 peter
  1221. * powerpc compiles again
  1222. Revision 1.34 2004/03/17 12:03:31 olle
  1223. * bugfix for multiline string constants
  1224. Revision 1.33 2004/03/02 00:57:01 olle
  1225. + adding missing log msg: misc fixes
  1226. Revision 1.32 2004/03/02 00:36:33 olle
  1227. Revision 1.31 2004/02/27 10:21:05 florian
  1228. * top_symbol killed
  1229. + refaddr to treference added
  1230. + refsymbol to treference added
  1231. * top_local stuff moved to an extra record to save memory
  1232. + aint introduced
  1233. * tppufile.get/putint64/aint implemented
  1234. }