ngenutil.pas 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  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) and
  339. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  340. begin
  341. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA),0));
  342. list.concat(tai_directive.Create(asd_reference,sym.name));
  343. end;
  344. list.concat(Tai_datablock.create_global(sym.mangledname,l));
  345. end
  346. else
  347. list.concat(Tai_datablock.create(sym.mangledname,l));
  348. current_filepos:=storefilepos;
  349. end;
  350. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  351. var
  352. pd: tprocdef;
  353. begin
  354. pd:=tprocdef.create(main_program_level);
  355. pd.procsym:=ps;
  356. ps.ProcdefList.Add(pd);
  357. include(pd.procoptions,po_global);
  358. { set procdef options }
  359. pd.proctypeoption:=potype;
  360. pd.proccalloption:=pocall_default;
  361. include(pd.procoptions,po_hascallingconvention);
  362. pd.forwarddef:=false;
  363. { may be required to calculate the mangled name }
  364. add_main_procdef_paras(pd);
  365. pd.setmangledname(name);
  366. pd.aliasnames.insert(pd.mangledname);
  367. result:=pd;
  368. end;
  369. procedure AddToStructInits(p:TObject;arg:pointer);
  370. var
  371. StructList: TFPList absolute arg;
  372. begin
  373. if (tdef(p).typ in [objectdef,recorddef]) and
  374. ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  375. StructList.Add(p);
  376. end;
  377. class procedure tnodeutils.InsertInitFinalTable;
  378. var
  379. hp : tused_unit;
  380. unitinits : TAsmList;
  381. count : longint;
  382. procedure write_struct_inits(u: tmodule);
  383. var
  384. i: integer;
  385. structlist: TFPList;
  386. pd: tprocdef;
  387. begin
  388. structlist := TFPList.Create;
  389. if assigned(u.globalsymtable) then
  390. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  391. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  392. { write structures }
  393. for i := 0 to structlist.Count - 1 do
  394. begin
  395. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  396. if assigned(pd) then
  397. unitinits.concat(Tai_const.Createname(pd.mangledname,0))
  398. else
  399. unitinits.concat(Tai_const.Create_pint(0));
  400. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  401. if assigned(pd) then
  402. unitinits.concat(Tai_const.Createname(pd.mangledname,0))
  403. else
  404. unitinits.concat(Tai_const.Create_pint(0));
  405. inc(count);
  406. end;
  407. structlist.free;
  408. end;
  409. begin
  410. unitinits:=TAsmList.Create;
  411. count:=0;
  412. hp:=tused_unit(usedunits.first);
  413. while assigned(hp) do
  414. begin
  415. { insert class constructors/destructors of the unit }
  416. if (hp.u.flags and uf_classinits) <> 0 then
  417. write_struct_inits(hp.u);
  418. { call the unit init code and make it external }
  419. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  420. begin
  421. if (hp.u.flags and uf_init)<>0 then
  422. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),0))
  423. else
  424. unitinits.concat(Tai_const.Create_sym(nil));
  425. if (hp.u.flags and uf_finalize)<>0 then
  426. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),0))
  427. else
  428. unitinits.concat(Tai_const.Create_sym(nil));
  429. inc(count);
  430. end;
  431. hp:=tused_unit(hp.next);
  432. end;
  433. { insert class constructors/destructor of the program }
  434. if (current_module.flags and uf_classinits) <> 0 then
  435. write_struct_inits(current_module);
  436. { Insert initialization/finalization of the program }
  437. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  438. begin
  439. if (current_module.flags and uf_init)<>0 then
  440. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),0))
  441. else
  442. unitinits.concat(Tai_const.Create_sym(nil));
  443. if (current_module.flags and uf_finalize)<>0 then
  444. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),0))
  445. else
  446. unitinits.concat(Tai_const.Create_sym(nil));
  447. inc(count);
  448. end;
  449. { Insert TableCount,InitCount at start }
  450. unitinits.insert(Tai_const.Create_32bit(0));
  451. unitinits.insert(Tai_const.Create_32bit(count));
  452. { Add to data segment }
  453. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  454. new_section(current_asmdata.asmlists[al_globals],sec_data,'INITFINAL',sizeof(pint));
  455. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITFINAL',AT_DATA,0));
  456. current_asmdata.asmlists[al_globals].concatlist(unitinits);
  457. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITFINAL'));
  458. unitinits.free;
  459. end;
  460. class procedure tnodeutils.InsertThreadvarTablesTable;
  461. var
  462. hp : tused_unit;
  463. ltvTables : TAsmList;
  464. count : longint;
  465. begin
  466. if (tf_section_threadvars in target_info.flags) then
  467. exit;
  468. ltvTables:=TAsmList.Create;
  469. count:=0;
  470. hp:=tused_unit(usedunits.first);
  471. while assigned(hp) do
  472. begin
  473. If (hp.u.flags and uf_threadvars)=uf_threadvars then
  474. begin
  475. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0));
  476. inc(count);
  477. end;
  478. hp:=tused_unit(hp.next);
  479. end;
  480. { Add program threadvars, if any }
  481. If (current_module.flags and uf_threadvars)=uf_threadvars then
  482. begin
  483. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0));
  484. inc(count);
  485. end;
  486. { Insert TableCount at start }
  487. ltvTables.insert(Tai_const.Create_32bit(count));
  488. { insert in data segment }
  489. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  490. new_section(current_asmdata.asmlists[al_globals],sec_data,'FPC_THREADVARTABLES',sizeof(pint));
  491. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('FPC_THREADVARTABLES',AT_DATA,0));
  492. current_asmdata.asmlists[al_globals].concatlist(ltvTables);
  493. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('FPC_THREADVARTABLES'));
  494. ltvTables.free;
  495. end;
  496. procedure AddToThreadvarList(p:TObject;arg:pointer);
  497. var
  498. ltvTable : TAsmList;
  499. begin
  500. ltvTable:=TAsmList(arg);
  501. if (tsym(p).typ=staticvarsym) and
  502. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  503. begin
  504. { address of threadvar }
  505. ltvTable.concat(tai_const.Createname(tstaticvarsym(p).mangledname,0));
  506. { size of threadvar }
  507. ltvTable.concat(tai_const.create_32bit(tstaticvarsym(p).getsize));
  508. end;
  509. end;
  510. class procedure tnodeutils.InsertThreadvars;
  511. var
  512. s : string;
  513. ltvTable : TAsmList;
  514. begin
  515. if (tf_section_threadvars in target_info.flags) then
  516. exit;
  517. ltvTable:=TAsmList.create;
  518. if assigned(current_module.globalsymtable) then
  519. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  520. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  521. if ltvTable.first<>nil then
  522. begin
  523. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  524. { end of the list marker }
  525. ltvTable.concat(tai_const.create_sym(nil));
  526. { add to datasegment }
  527. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  528. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  529. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  530. current_asmdata.asmlists[al_globals].concatlist(ltvTable);
  531. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  532. current_module.flags:=current_module.flags or uf_threadvars;
  533. end;
  534. ltvTable.Free;
  535. end;
  536. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  537. var
  538. hp: tused_unit;
  539. hlist: TAsmList;
  540. count: longint;
  541. begin
  542. hlist:=TAsmList.Create;
  543. count:=0;
  544. hp:=tused_unit(usedunits.first);
  545. while assigned(hp) do
  546. begin
  547. if (hp.u.flags and unitflag)=unitflag then
  548. begin
  549. hlist.concat(Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0));
  550. inc(count);
  551. end;
  552. hp:=tused_unit(hp.next);
  553. end;
  554. { Add items from program, if any }
  555. if (current_module.flags and unitflag)=unitflag then
  556. begin
  557. hlist.concat(Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0));
  558. inc(count);
  559. end;
  560. { Insert TableCount at start }
  561. hlist.insert(Tai_const.Create_32bit(count));
  562. { insert in data segment }
  563. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  564. new_section(current_asmdata.asmlists[al_globals],sec_data,tablename,sizeof(pint));
  565. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(tablename,AT_DATA,0));
  566. current_asmdata.asmlists[al_globals].concatlist(hlist);
  567. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(tablename));
  568. hlist.free;
  569. end;
  570. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  571. var
  572. s: string;
  573. item: TTCInitItem;
  574. begin
  575. item:=TTCInitItem(list.First);
  576. if item=nil then
  577. exit;
  578. s:=make_mangledname(prefix,current_module.localsymtable,'');
  579. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  580. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  581. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  582. repeat
  583. { optimize away unused local/static symbols }
  584. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  585. begin
  586. { address to initialize }
  587. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  588. { value with which to initialize }
  589. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  590. end;
  591. item:=TTCInitItem(item.Next);
  592. until item=nil;
  593. { end-of-list marker }
  594. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  595. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  596. current_module.flags:=current_module.flags or unitflag;
  597. end;
  598. class procedure tnodeutils.InsertWideInits;
  599. begin
  600. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  601. end;
  602. class procedure tnodeutils.InsertResStrInits;
  603. begin
  604. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  605. end;
  606. class procedure tnodeutils.InsertWideInitsTablesTable;
  607. begin
  608. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  609. end;
  610. class procedure tnodeutils.InsertResStrTablesTable;
  611. begin
  612. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  613. end;
  614. class procedure tnodeutils.InsertResourceTablesTable;
  615. var
  616. hp : tmodule;
  617. ResourceStringTables : tasmlist;
  618. count : longint;
  619. begin
  620. ResourceStringTables:=tasmlist.Create;
  621. count:=0;
  622. hp:=tmodule(loaded_units.first);
  623. while assigned(hp) do
  624. begin
  625. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  626. begin
  627. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),0));
  628. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),0));
  629. inc(count);
  630. end;
  631. hp:=tmodule(hp.next);
  632. end;
  633. { Insert TableCount at start }
  634. ResourceStringTables.insert(Tai_const.Create_pint(count));
  635. { Add to data segment }
  636. maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
  637. new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',sizeof(pint));
  638. current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
  639. current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
  640. current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
  641. ResourceStringTables.free;
  642. end;
  643. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  644. var
  645. ResourceInfo : TAsmList;
  646. begin
  647. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  648. begin
  649. ResourceInfo:=TAsmList.Create;
  650. maybe_new_object_file(ResourceInfo);
  651. new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
  652. ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
  653. if ResourcesUsed then
  654. { Valid pointer to resource information }
  655. ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
  656. else
  657. { Nil pointer to resource information }
  658. {$IFNDEF cpu64bitaddr}
  659. ResourceInfo.Concat(Tai_const.Create_32bit(0));
  660. {$ELSE}
  661. ResourceInfo.Concat(Tai_const.Create_64bit(0));
  662. {$ENDIF}
  663. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  664. current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
  665. ResourceInfo.free;
  666. end;
  667. end;
  668. class procedure tnodeutils.InsertMemorySizes;
  669. {$IFDEF POWERPC}
  670. var
  671. stkcookie: string;
  672. {$ENDIF POWERPC}
  673. begin
  674. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  675. { Insert Ident of the compiler in the .fpc.version section }
  676. new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
  677. current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
  678. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
  679. if not(tf_no_generic_stackcheck in target_info.flags) then
  680. begin
  681. { stacksize can be specified and is now simulated }
  682. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
  683. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
  684. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
  685. end;
  686. {$IFDEF POWERPC}
  687. { AmigaOS4 "stack cookie" support }
  688. if ( target_info.system = system_powerpc_amiga ) then
  689. begin
  690. { this symbol is needed to ignite powerpc amigaos' }
  691. { stack allocation magic for us with the given stack size. }
  692. { note: won't work for m68k amigaos or morphos. (KB) }
  693. str(stacksize,stkcookie);
  694. stkcookie:='$STACK: '+stkcookie+#0;
  695. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  696. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
  697. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
  698. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
  699. end;
  700. {$ENDIF POWERPC}
  701. { Initial heapsize }
  702. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  703. new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',sizeof(pint));
  704. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
  705. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
  706. { Initial heapsize }
  707. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  708. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',sizeof(boolean));
  709. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
  710. current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
  711. end;
  712. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  713. begin
  714. { no parameters by default }
  715. end;
  716. end.