ngenutil.pas 36 KB

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