ngenutil.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. {
  2. Copyright (c) 1998-2011 by Florian Klaempfl
  3. Generic version of some node tree helper routines that can be overridden
  4. by cpu-specific versions
  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 ngenutil;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cclasses,
  23. node,symtype,symsym,symconst,symdef;
  24. type
  25. tnodeutils = class
  26. class function call_fail_node:tnode; virtual;
  27. class function initialize_data_node(p:tnode; force: boolean):tnode; virtual;
  28. class function finalize_data_node(p:tnode):tnode; virtual;
  29. { returns true if the unit requires an initialisation section (e.g.,
  30. to force class constructors for the JVM target to initialise global
  31. records/arrays) }
  32. class function force_init: boolean; virtual;
  33. { idem for finalization }
  34. class function force_final: boolean; virtual;
  35. { called after parsing a routine with the code of the entire routine
  36. as argument; can be used to modify the node tree. By default handles
  37. insertion of code for systems that perform the typed constant
  38. initialisation via the node tree }
  39. class function wrap_proc_body(pd: tprocdef; n: tnode): tnode; virtual;
  40. class procedure insertbssdata(sym : tstaticvarsym); virtual;
  41. class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
  42. class procedure InsertInitFinalTable; virtual;
  43. protected
  44. class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal); virtual;
  45. class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal); virtual;
  46. public
  47. class procedure InsertThreadvarTablesTable; virtual;
  48. class procedure InsertThreadvars; virtual;
  49. class procedure InsertWideInitsTablesTable; virtual;
  50. class procedure InsertWideInits; virtual;
  51. class procedure InsertResStrInits; virtual;
  52. class procedure InsertResStrTablesTable; virtual;
  53. class procedure InsertResourceTablesTable; virtual;
  54. class procedure InsertResourceInfo(ResourcesUsed : boolean); virtual;
  55. class procedure InsertMemorySizes; virtual;
  56. strict protected
  57. class procedure add_main_procdef_paras(pd: tdef); virtual;
  58. end;
  59. tnodeutilsclass = class of tnodeutils;
  60. const
  61. cnodeutils: tnodeutilsclass = tnodeutils;
  62. implementation
  63. uses
  64. verbose,version,globtype,globals,cutils,constexp,
  65. scanner,systems,procinfo,fmodule,
  66. aasmbase,aasmdata,aasmtai,
  67. symbase,symtable,defutil,
  68. nadd,nbas,ncal,ncnv,ncon,nflw,nld,nmem,nobj,nutils,
  69. ppu,
  70. pass_1;
  71. class function tnodeutils.call_fail_node:tnode;
  72. var
  73. para : tcallparanode;
  74. newstatement : tstatementnode;
  75. srsym : tsym;
  76. begin
  77. result:=internalstatements(newstatement);
  78. { call fail helper and exit normal }
  79. if is_class(current_structdef) then
  80. begin
  81. srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
  82. if assigned(srsym) and
  83. (srsym.typ=procsym) then
  84. begin
  85. { if self<>0 and vmt<>0 then freeinstance }
  86. addstatement(newstatement,cifnode.create(
  87. caddnode.create(andn,
  88. caddnode.create(unequaln,
  89. load_self_pointer_node,
  90. cnilnode.create),
  91. caddnode.create(unequaln,
  92. load_vmt_pointer_node,
  93. cnilnode.create)),
  94. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  95. nil));
  96. end
  97. else
  98. internalerror(200305108);
  99. end
  100. else
  101. if is_object(current_structdef) then
  102. begin
  103. { parameter 3 : vmt_offset }
  104. { parameter 2 : pointer to vmt }
  105. { parameter 1 : self pointer }
  106. para:=ccallparanode.create(
  107. cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
  108. ccallparanode.create(
  109. ctypeconvnode.create_internal(
  110. load_vmt_pointer_node,
  111. voidpointertype),
  112. ccallparanode.create(
  113. ctypeconvnode.create_internal(
  114. load_self_pointer_node,
  115. voidpointertype),
  116. nil)));
  117. addstatement(newstatement,
  118. ccallnode.createintern('fpc_help_fail',para));
  119. end
  120. else
  121. internalerror(200305132);
  122. { self:=nil }
  123. addstatement(newstatement,cassignmentnode.create(
  124. load_self_pointer_node,
  125. cnilnode.create));
  126. { exit }
  127. addstatement(newstatement,cexitnode.create(nil));
  128. end;
  129. class function tnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
  130. begin
  131. if not assigned(p.resultdef) then
  132. typecheckpass(p);
  133. if is_ansistring(p.resultdef) or
  134. is_wide_or_unicode_string(p.resultdef) or
  135. is_interfacecom_or_dispinterface(p.resultdef) or
  136. is_dynamic_array(p.resultdef) then
  137. begin
  138. result:=cassignmentnode.create(
  139. ctypeconvnode.create_internal(p,voidpointertype),
  140. cnilnode.create
  141. );
  142. end
  143. else if (p.resultdef.typ=variantdef) then
  144. begin
  145. result:=ccallnode.createintern('fpc_variant_init',
  146. ccallparanode.create(
  147. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  148. nil));
  149. end
  150. else
  151. begin
  152. result:=ccallnode.createintern('fpc_initialize',
  153. ccallparanode.create(
  154. caddrnode.create_internal(
  155. crttinode.create(
  156. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  157. ccallparanode.create(
  158. caddrnode.create_internal(p),
  159. nil)));
  160. end;
  161. end;
  162. class function tnodeutils.finalize_data_node(p:tnode):tnode;
  163. var
  164. hs : string;
  165. begin
  166. if not assigned(p.resultdef) then
  167. typecheckpass(p);
  168. { 'decr_ref' suffix is somewhat misleading, all these helpers
  169. set the passed pointer to nil now }
  170. if is_ansistring(p.resultdef) then
  171. hs:='fpc_ansistr_decr_ref'
  172. else if is_widestring(p.resultdef) then
  173. hs:='fpc_widestr_decr_ref'
  174. else if is_unicodestring(p.resultdef) then
  175. hs:='fpc_unicodestr_decr_ref'
  176. else if is_interfacecom_or_dispinterface(p.resultdef) then
  177. hs:='fpc_intf_decr_ref'
  178. else
  179. hs:='';
  180. if hs<>'' then
  181. result:=ccallnode.createintern(hs,
  182. ccallparanode.create(
  183. ctypeconvnode.create_internal(p,voidpointertype),
  184. nil))
  185. else if p.resultdef.typ=variantdef then
  186. begin
  187. result:=ccallnode.createintern('fpc_variant_clear',
  188. ccallparanode.create(
  189. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  190. nil));
  191. end
  192. else
  193. result:=ccallnode.createintern('fpc_finalize',
  194. ccallparanode.create(
  195. caddrnode.create_internal(
  196. crttinode.create(
  197. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  198. ccallparanode.create(
  199. caddrnode.create_internal(p),
  200. nil)));
  201. end;
  202. class function tnodeutils.force_init: boolean;
  203. begin
  204. result:=
  205. (target_info.system in systems_typed_constants_node_init) and
  206. assigned(current_module.tcinitcode);
  207. end;
  208. class function tnodeutils.force_final: boolean;
  209. begin
  210. result:=false;
  211. end;
  212. class function tnodeutils.wrap_proc_body(pd: tprocdef; n: tnode): tnode;
  213. var
  214. stat: tstatementnode;
  215. block: tnode;
  216. psym: tsym;
  217. tcinitproc: tprocdef;
  218. begin
  219. result:=n;
  220. if target_info.system in systems_typed_constants_node_init then
  221. begin
  222. case pd.proctypeoption of
  223. potype_class_constructor:
  224. begin
  225. { even though the initialisation code for typed constants may
  226. not yet be complete at this point (there may be more inside
  227. method definitions coming after this class constructor), the
  228. ones from inside the class definition have already been parsed.
  229. in case of $j-, these are marked "final" in Java and such
  230. static fields must be initialsed in the class constructor
  231. itself -> add them here }
  232. block:=internalstatements(stat);
  233. if assigned(pd.struct.tcinitcode) then
  234. begin
  235. addstatement(stat,pd.struct.tcinitcode);
  236. pd.struct.tcinitcode:=nil;
  237. end;
  238. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  239. if assigned(psym) then
  240. begin
  241. if (psym.typ<>procsym) or
  242. (tprocsym(psym).procdeflist.count<>1) then
  243. internalerror(2011040301);
  244. tcinitproc:=tprocdef(tprocsym(psym).procdeflist[0]);
  245. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  246. pd.struct.symtable,nil,[]));
  247. end;
  248. addstatement(stat,result);
  249. result:=block
  250. end;
  251. potype_unitinit:
  252. begin
  253. if assigned(current_module.tcinitcode) then
  254. begin
  255. block:=internalstatements(stat);
  256. addstatement(stat,tnode(current_module.tcinitcode));
  257. current_module.tcinitcode:=nil;
  258. addstatement(stat,result);
  259. result:=block;
  260. end;
  261. end;
  262. else case pd.synthetickind of
  263. tsk_tcinit:
  264. begin
  265. if assigned(pd.struct.tcinitcode) then
  266. begin
  267. block:=internalstatements(stat);
  268. addstatement(stat,pd.struct.tcinitcode);
  269. pd.struct.tcinitcode:=nil;
  270. addstatement(stat,result);
  271. result:=block
  272. end
  273. end;
  274. end;
  275. end;
  276. end;
  277. end;
  278. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  279. var
  280. l : asizeint;
  281. varalign : shortint;
  282. storefilepos : tfileposinfo;
  283. list : TAsmList;
  284. sectype : TAsmSectiontype;
  285. begin
  286. storefilepos:=current_filepos;
  287. current_filepos:=sym.fileinfo;
  288. l:=sym.getsize;
  289. varalign:=sym.vardef.alignment;
  290. if (varalign=0) then
  291. varalign:=var_align_size(l)
  292. else
  293. varalign:=var_align(varalign);
  294. if tf_section_threadvars in target_info.flags then
  295. begin
  296. if (vo_is_thread_var in sym.varoptions) then
  297. begin
  298. list:=current_asmdata.asmlists[al_threadvars];
  299. sectype:=sec_threadvar;
  300. end
  301. else
  302. begin
  303. list:=current_asmdata.asmlists[al_globals];
  304. sectype:=sec_bss;
  305. end;
  306. end
  307. else
  308. begin
  309. if (vo_is_thread_var in sym.varoptions) then
  310. begin
  311. inc(l,sizeof(pint));
  312. { it doesn't help to set a higher alignment, as }
  313. { the first sizeof(pint) bytes field will offset }
  314. { everything anyway }
  315. varalign:=sizeof(pint);
  316. end;
  317. list:=current_asmdata.asmlists[al_globals];
  318. sectype:=sec_bss;
  319. end;
  320. maybe_new_object_file(list);
  321. if vo_has_section in sym.varoptions then
  322. new_section(list,sec_user,sym.section,varalign)
  323. else
  324. new_section(list,sectype,lower(sym.mangledname),varalign);
  325. if (sym.owner.symtabletype=globalsymtable) or
  326. create_smartlink or
  327. DLLSource or
  328. (assigned(current_procinfo) and
  329. (po_inline in current_procinfo.procdef.procoptions)) or
  330. (vo_is_public in sym.varoptions) then
  331. begin
  332. { on AIX/stabx, we cannot generate debug information that encodes
  333. the address of a global symbol, you need a symbol with the same
  334. name as the identifier -> create an extra *local* symbol.
  335. Moreover, such a local symbol will be removed if it's not
  336. referenced anywhere, so also create a reference }
  337. if (target_dbg.id=dbg_stabx) and
  338. (cs_debuginfo in current_settings.moduleswitches) then
  339. begin
  340. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA),0));
  341. list.concat(tai_directive.Create(asd_reference,sym.name));
  342. end;
  343. list.concat(Tai_datablock.create_global(sym.mangledname,l));
  344. end
  345. else
  346. list.concat(Tai_datablock.create(sym.mangledname,l));
  347. current_filepos:=storefilepos;
  348. end;
  349. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  350. var
  351. pd: tprocdef;
  352. begin
  353. pd:=tprocdef.create(main_program_level);
  354. pd.procsym:=ps;
  355. ps.ProcdefList.Add(pd);
  356. include(pd.procoptions,po_global);
  357. { set procdef options }
  358. pd.proctypeoption:=potype;
  359. pd.proccalloption:=pocall_default;
  360. include(pd.procoptions,po_hascallingconvention);
  361. pd.forwarddef:=false;
  362. { may be required to calculate the mangled name }
  363. add_main_procdef_paras(pd);
  364. pd.setmangledname(name);
  365. pd.aliasnames.insert(pd.mangledname);
  366. result:=pd;
  367. end;
  368. procedure AddToStructInits(p:TObject;arg:pointer);
  369. var
  370. StructList: TFPList absolute arg;
  371. begin
  372. if (tdef(p).typ in [objectdef,recorddef]) and
  373. ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  374. StructList.Add(p);
  375. end;
  376. class procedure tnodeutils.InsertInitFinalTable;
  377. var
  378. hp : tused_unit;
  379. unitinits : TAsmList;
  380. count : longint;
  381. procedure write_struct_inits(u: tmodule);
  382. var
  383. i: integer;
  384. structlist: TFPList;
  385. pd: tprocdef;
  386. begin
  387. structlist := TFPList.Create;
  388. if assigned(u.globalsymtable) then
  389. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  390. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  391. { write structures }
  392. for i := 0 to structlist.Count - 1 do
  393. begin
  394. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  395. if assigned(pd) then
  396. unitinits.concat(Tai_const.Createname(pd.mangledname,0))
  397. else
  398. unitinits.concat(Tai_const.Create_pint(0));
  399. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  400. if assigned(pd) then
  401. unitinits.concat(Tai_const.Createname(pd.mangledname,0))
  402. else
  403. unitinits.concat(Tai_const.Create_pint(0));
  404. inc(count);
  405. end;
  406. structlist.free;
  407. end;
  408. begin
  409. unitinits:=TAsmList.Create;
  410. count:=0;
  411. hp:=tused_unit(usedunits.first);
  412. while assigned(hp) do
  413. begin
  414. { insert class constructors/destructors of the unit }
  415. if (hp.u.flags and uf_classinits) <> 0 then
  416. write_struct_inits(hp.u);
  417. { call the unit init code and make it external }
  418. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  419. begin
  420. if (hp.u.flags and uf_init)<>0 then
  421. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),0))
  422. else
  423. unitinits.concat(Tai_const.Create_sym(nil));
  424. if (hp.u.flags and uf_finalize)<>0 then
  425. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),0))
  426. else
  427. unitinits.concat(Tai_const.Create_sym(nil));
  428. inc(count);
  429. end;
  430. hp:=tused_unit(hp.next);
  431. end;
  432. { insert class constructors/destructor of the program }
  433. if (current_module.flags and uf_classinits) <> 0 then
  434. write_struct_inits(current_module);
  435. { Insert initialization/finalization of the program }
  436. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  437. begin
  438. if (current_module.flags and uf_init)<>0 then
  439. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),0))
  440. else
  441. unitinits.concat(Tai_const.Create_sym(nil));
  442. if (current_module.flags and uf_finalize)<>0 then
  443. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),0))
  444. else
  445. unitinits.concat(Tai_const.Create_sym(nil));
  446. inc(count);
  447. end;
  448. { Insert TableCount,InitCount at start }
  449. unitinits.insert(Tai_const.Create_32bit(0));
  450. unitinits.insert(Tai_const.Create_32bit(count));
  451. { Add to data segment }
  452. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  453. new_section(current_asmdata.asmlists[al_globals],sec_data,'INITFINAL',sizeof(pint));
  454. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITFINAL',AT_DATA,0));
  455. current_asmdata.asmlists[al_globals].concatlist(unitinits);
  456. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITFINAL'));
  457. unitinits.free;
  458. end;
  459. class procedure tnodeutils.InsertThreadvarTablesTable;
  460. var
  461. hp : tused_unit;
  462. ltvTables : TAsmList;
  463. count : longint;
  464. begin
  465. if (tf_section_threadvars in target_info.flags) then
  466. exit;
  467. ltvTables:=TAsmList.Create;
  468. count:=0;
  469. hp:=tused_unit(usedunits.first);
  470. while assigned(hp) do
  471. begin
  472. If (hp.u.flags and uf_threadvars)=uf_threadvars then
  473. begin
  474. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0));
  475. inc(count);
  476. end;
  477. hp:=tused_unit(hp.next);
  478. end;
  479. { Add program threadvars, if any }
  480. If (current_module.flags and uf_threadvars)=uf_threadvars then
  481. begin
  482. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0));
  483. inc(count);
  484. end;
  485. { Insert TableCount at start }
  486. ltvTables.insert(Tai_const.Create_32bit(count));
  487. { insert in data segment }
  488. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  489. new_section(current_asmdata.asmlists[al_globals],sec_data,'FPC_THREADVARTABLES',sizeof(pint));
  490. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('FPC_THREADVARTABLES',AT_DATA,0));
  491. current_asmdata.asmlists[al_globals].concatlist(ltvTables);
  492. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('FPC_THREADVARTABLES'));
  493. ltvTables.free;
  494. end;
  495. procedure AddToThreadvarList(p:TObject;arg:pointer);
  496. var
  497. ltvTable : TAsmList;
  498. begin
  499. ltvTable:=TAsmList(arg);
  500. if (tsym(p).typ=staticvarsym) and
  501. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  502. begin
  503. { address of threadvar }
  504. ltvTable.concat(tai_const.Createname(tstaticvarsym(p).mangledname,0));
  505. { size of threadvar }
  506. ltvTable.concat(tai_const.create_32bit(tstaticvarsym(p).getsize));
  507. end;
  508. end;
  509. class procedure tnodeutils.InsertThreadvars;
  510. var
  511. s : string;
  512. ltvTable : TAsmList;
  513. begin
  514. if (tf_section_threadvars in target_info.flags) then
  515. exit;
  516. ltvTable:=TAsmList.create;
  517. if assigned(current_module.globalsymtable) then
  518. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  519. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  520. if ltvTable.first<>nil then
  521. begin
  522. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  523. { end of the list marker }
  524. ltvTable.concat(tai_const.create_sym(nil));
  525. { add to datasegment }
  526. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  527. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  528. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  529. current_asmdata.asmlists[al_globals].concatlist(ltvTable);
  530. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  531. current_module.flags:=current_module.flags or uf_threadvars;
  532. end;
  533. ltvTable.Free;
  534. end;
  535. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  536. var
  537. hp: tused_unit;
  538. hlist: TAsmList;
  539. count: longint;
  540. begin
  541. hlist:=TAsmList.Create;
  542. count:=0;
  543. hp:=tused_unit(usedunits.first);
  544. while assigned(hp) do
  545. begin
  546. if (hp.u.flags and unitflag)=unitflag then
  547. begin
  548. hlist.concat(Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0));
  549. inc(count);
  550. end;
  551. hp:=tused_unit(hp.next);
  552. end;
  553. { Add items from program, if any }
  554. if (current_module.flags and unitflag)=unitflag then
  555. begin
  556. hlist.concat(Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0));
  557. inc(count);
  558. end;
  559. { Insert TableCount at start }
  560. hlist.insert(Tai_const.Create_32bit(count));
  561. { insert in data segment }
  562. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  563. new_section(current_asmdata.asmlists[al_globals],sec_data,tablename,sizeof(pint));
  564. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(tablename,AT_DATA,0));
  565. current_asmdata.asmlists[al_globals].concatlist(hlist);
  566. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(tablename));
  567. hlist.free;
  568. end;
  569. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  570. var
  571. s: string;
  572. item: TTCInitItem;
  573. begin
  574. item:=TTCInitItem(list.First);
  575. if item=nil then
  576. exit;
  577. s:=make_mangledname(prefix,current_module.localsymtable,'');
  578. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  579. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  580. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  581. repeat
  582. { optimize away unused local/static symbols }
  583. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  584. begin
  585. { address to initialize }
  586. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  587. { value with which to initialize }
  588. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  589. end;
  590. item:=TTCInitItem(item.Next);
  591. until item=nil;
  592. { end-of-list marker }
  593. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  594. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  595. current_module.flags:=current_module.flags or unitflag;
  596. end;
  597. class procedure tnodeutils.InsertWideInits;
  598. begin
  599. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  600. end;
  601. class procedure tnodeutils.InsertResStrInits;
  602. begin
  603. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  604. end;
  605. class procedure tnodeutils.InsertWideInitsTablesTable;
  606. begin
  607. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  608. end;
  609. class procedure tnodeutils.InsertResStrTablesTable;
  610. begin
  611. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  612. end;
  613. class procedure tnodeutils.InsertResourceTablesTable;
  614. var
  615. hp : tmodule;
  616. ResourceStringTables : tasmlist;
  617. count : longint;
  618. begin
  619. ResourceStringTables:=tasmlist.Create;
  620. count:=0;
  621. hp:=tmodule(loaded_units.first);
  622. while assigned(hp) do
  623. begin
  624. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  625. begin
  626. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),0));
  627. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),0));
  628. inc(count);
  629. end;
  630. hp:=tmodule(hp.next);
  631. end;
  632. { Insert TableCount at start }
  633. ResourceStringTables.insert(Tai_const.Create_pint(count));
  634. { Add to data segment }
  635. maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
  636. new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',sizeof(pint));
  637. current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
  638. current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
  639. current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
  640. ResourceStringTables.free;
  641. end;
  642. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  643. var
  644. ResourceInfo : TAsmList;
  645. begin
  646. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  647. begin
  648. ResourceInfo:=TAsmList.Create;
  649. maybe_new_object_file(ResourceInfo);
  650. new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
  651. ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
  652. if ResourcesUsed then
  653. { Valid pointer to resource information }
  654. ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
  655. else
  656. { Nil pointer to resource information }
  657. {$IFNDEF cpu64bitaddr}
  658. ResourceInfo.Concat(Tai_const.Create_32bit(0));
  659. {$ELSE}
  660. ResourceInfo.Concat(Tai_const.Create_64bit(0));
  661. {$ENDIF}
  662. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  663. current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
  664. ResourceInfo.free;
  665. end;
  666. end;
  667. class procedure tnodeutils.InsertMemorySizes;
  668. {$IFDEF POWERPC}
  669. var
  670. stkcookie: string;
  671. {$ENDIF POWERPC}
  672. begin
  673. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  674. { Insert Ident of the compiler in the .fpc.version section }
  675. new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
  676. current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
  677. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
  678. if not(tf_no_generic_stackcheck in target_info.flags) then
  679. begin
  680. { stacksize can be specified and is now simulated }
  681. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
  682. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
  683. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
  684. end;
  685. {$IFDEF POWERPC}
  686. { AmigaOS4 "stack cookie" support }
  687. if ( target_info.system = system_powerpc_amiga ) then
  688. begin
  689. { this symbol is needed to ignite powerpc amigaos' }
  690. { stack allocation magic for us with the given stack size. }
  691. { note: won't work for m68k amigaos or morphos. (KB) }
  692. str(stacksize,stkcookie);
  693. stkcookie:='$STACK: '+stkcookie+#0;
  694. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  695. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
  696. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
  697. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
  698. end;
  699. {$ENDIF POWERPC}
  700. { Initial heapsize }
  701. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  702. new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',sizeof(pint));
  703. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
  704. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
  705. { Initial heapsize }
  706. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  707. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',sizeof(boolean));
  708. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
  709. current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
  710. end;
  711. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  712. begin
  713. { no parameters by default }
  714. end;
  715. end.