ngenutil.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  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. begin
  237. result:=maybe_insert_trashing(pd,n);
  238. if target_info.system in systems_typed_constants_node_init then
  239. begin
  240. case pd.proctypeoption of
  241. potype_class_constructor:
  242. begin
  243. { even though the initialisation code for typed constants may
  244. not yet be complete at this point (there may be more inside
  245. method definitions coming after this class constructor), the
  246. ones from inside the class definition have already been parsed.
  247. in case of $j-, these are marked "final" in Java and such
  248. static fields must be initialsed in the class constructor
  249. itself -> add them here }
  250. block:=internalstatements(stat);
  251. if assigned(pd.struct.tcinitcode) then
  252. begin
  253. addstatement(stat,pd.struct.tcinitcode);
  254. pd.struct.tcinitcode:=nil;
  255. end;
  256. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  257. if assigned(psym) then
  258. begin
  259. if (psym.typ<>procsym) or
  260. (tprocsym(psym).procdeflist.count<>1) then
  261. internalerror(2011040301);
  262. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  263. pd.struct.symtable,nil,[]));
  264. end;
  265. addstatement(stat,result);
  266. result:=block
  267. end;
  268. potype_unitinit:
  269. begin
  270. if assigned(current_module.tcinitcode) then
  271. begin
  272. block:=internalstatements(stat);
  273. addstatement(stat,tnode(current_module.tcinitcode));
  274. current_module.tcinitcode:=nil;
  275. addstatement(stat,result);
  276. result:=block;
  277. end;
  278. end;
  279. else case pd.synthetickind of
  280. tsk_tcinit:
  281. begin
  282. if assigned(pd.struct.tcinitcode) then
  283. begin
  284. block:=internalstatements(stat);
  285. addstatement(stat,pd.struct.tcinitcode);
  286. pd.struct.tcinitcode:=nil;
  287. addstatement(stat,result);
  288. result:=block
  289. end
  290. end;
  291. end;
  292. end;
  293. end;
  294. end;
  295. class function tnodeutils.maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  296. var
  297. stat: tstatementnode;
  298. begin
  299. result:=n;
  300. if (localvartrashing<>-1) and
  301. not(po_assembler in pd.procoptions) then
  302. begin
  303. result:=internalstatements(stat);
  304. pd.parast.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  305. pd.localst.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  306. addstatement(stat,n);
  307. end;
  308. end;
  309. class function tnodeutils.trashable_sym(p: tsym): boolean;
  310. begin
  311. result:=
  312. ((p.typ=localvarsym) or
  313. ((p.typ=paravarsym) and
  314. ((vo_is_funcret in tabstractnormalvarsym(p).varoptions) or
  315. (tabstractnormalvarsym(p).varspez=vs_out)))) and
  316. not is_managed_type(tabstractnormalvarsym(p).vardef) and
  317. not assigned(tabstractnormalvarsym(p).defaultconstsym);
  318. end;
  319. class procedure tnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  320. var
  321. size: asizeint;
  322. trashintval: int64;
  323. begin
  324. if trashable_sym(p) then
  325. begin
  326. trashintval:=trashintvalues[localvartrashing];
  327. if (p.vardef.typ=procvardef) and
  328. ([m_tp_procvar,m_mac_procvar]*current_settings.modeswitches<>[]) then
  329. begin
  330. if tprocvardef(p.vardef).is_addressonly then
  331. { in tp/delphi mode, you need @procvar to get at the contents of
  332. a procvar ... }
  333. trashn:=caddrnode.create(trashn)
  334. else
  335. { ... but if it's a procedure of object, that will only return
  336. the procedure address -> cast to tmethod instead }
  337. trashn:=ctypeconvnode.create_explicit(trashn,methodpointertype);
  338. end;
  339. if ((p.typ=localvarsym) and
  340. (not(vo_is_funcret in p.varoptions) or
  341. not is_shortstring(p.vardef))) or
  342. ((p.typ=paravarsym) and
  343. not is_shortstring(p.vardef)) then
  344. begin
  345. size:=p.getsize;
  346. case size of
  347. 0:
  348. begin
  349. { open array -> at least size 1. Can also be zero-sized
  350. record, so check it's actually an array }
  351. if p.vardef.typ=arraydef then
  352. trash_large(stat,trashn,caddnode.create(addn,cinlinenode.create(in_high_x,false,trashn.getcopy),genintconstnode(1)),trashintval)
  353. else
  354. trashn.free;
  355. end;
  356. 1: trash_small(stat,
  357. ctypeconvnode.create_internal(trashn,s8inttype),
  358. genintconstnode(shortint(trashintval)));
  359. 2: trash_small(stat,
  360. ctypeconvnode.create_internal(trashn,s16inttype),
  361. genintconstnode(smallint(trashintval)));
  362. 4: trash_small(stat,
  363. ctypeconvnode.create_internal(trashn,s32inttype),
  364. genintconstnode(longint(trashintval)));
  365. 8: trash_small(stat,
  366. ctypeconvnode.create_internal(trashn,s64inttype),
  367. genintconstnode(int64(trashintval)));
  368. else
  369. trash_large(stat,trashn,genintconstnode(size),trashintval);
  370. end;
  371. end
  372. else
  373. begin
  374. { may be an open string, even if is_open_string() returns false
  375. (for some helpers in the system unit) }
  376. { an open string has at least size 2 }
  377. trash_small(stat,
  378. cvecnode.create(trashn.getcopy,genintconstnode(0)),
  379. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  380. trash_small(stat,
  381. cvecnode.create(trashn,genintconstnode(1)),
  382. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  383. end;
  384. end
  385. else
  386. trashn.free;
  387. end;
  388. class procedure tnodeutils.maybe_trash_variable_callback(p:TObject;statn:pointer);
  389. var
  390. stat: ^tstatementnode absolute statn;
  391. begin
  392. if not(tsym(p).typ in [localvarsym,paravarsym]) then
  393. exit;
  394. maybe_trash_variable(stat^,tabstractnormalvarsym(p),cloadnode.create(tsym(p),tsym(p).owner));
  395. end;
  396. class procedure tnodeutils.trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode);
  397. begin
  398. addstatement(stat,cassignmentnode.create(trashn,trashvaln));
  399. end;
  400. class procedure tnodeutils.trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64);
  401. begin
  402. addstatement(stat,ccallnode.createintern('fpc_fillmem',
  403. ccallparanode.Create(cordconstnode.create(tconstexprint(byte(trashintval)),u8inttype,false),
  404. ccallparanode.Create(sizen,
  405. ccallparanode.Create(trashn,nil)))
  406. ));
  407. end;
  408. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  409. var
  410. l : asizeint;
  411. varalign : shortint;
  412. storefilepos : tfileposinfo;
  413. list : TAsmList;
  414. sectype : TAsmSectiontype;
  415. begin
  416. storefilepos:=current_filepos;
  417. current_filepos:=sym.fileinfo;
  418. l:=sym.getsize;
  419. varalign:=sym.vardef.alignment;
  420. if (varalign=0) then
  421. varalign:=var_align_size(l)
  422. else
  423. varalign:=var_align(varalign);
  424. if tf_section_threadvars in target_info.flags then
  425. begin
  426. if (vo_is_thread_var in sym.varoptions) then
  427. begin
  428. list:=current_asmdata.asmlists[al_threadvars];
  429. sectype:=sec_threadvar;
  430. end
  431. else
  432. begin
  433. list:=current_asmdata.asmlists[al_globals];
  434. sectype:=sec_bss;
  435. end;
  436. end
  437. else
  438. begin
  439. if (vo_is_thread_var in sym.varoptions) then
  440. begin
  441. inc(l,sizeof(pint));
  442. { it doesn't help to set a higher alignment, as }
  443. { the first sizeof(pint) bytes field will offset }
  444. { everything anyway }
  445. varalign:=sizeof(pint);
  446. end;
  447. list:=current_asmdata.asmlists[al_globals];
  448. sectype:=sec_bss;
  449. end;
  450. maybe_new_object_file(list);
  451. if vo_has_section in sym.varoptions then
  452. new_section(list,sec_user,sym.section,varalign)
  453. else
  454. new_section(list,sectype,lower(sym.mangledname),varalign);
  455. if sym.globalasmsym then
  456. begin
  457. { on AIX/stabx, we cannot generate debug information that encodes
  458. the address of a global symbol, you need a symbol with the same
  459. name as the identifier -> create an extra *local* symbol.
  460. Moreover, such a local symbol will be removed if it's not
  461. referenced anywhere, so also create a reference }
  462. if (target_dbg.id=dbg_stabx) and
  463. (cs_debuginfo in current_settings.moduleswitches) and
  464. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  465. begin
  466. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA),0));
  467. list.concat(tai_directive.Create(asd_reference,sym.name));
  468. end;
  469. list.concat(Tai_datablock.create_global(sym.mangledname,l));
  470. end
  471. else
  472. list.concat(Tai_datablock.create(sym.mangledname,l));
  473. current_filepos:=storefilepos;
  474. end;
  475. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  476. var
  477. pd: tprocdef;
  478. begin
  479. pd:=tprocdef.create(main_program_level);
  480. pd.procsym:=ps;
  481. ps.ProcdefList.Add(pd);
  482. include(pd.procoptions,po_global);
  483. { set procdef options }
  484. pd.proctypeoption:=potype;
  485. pd.proccalloption:=pocall_default;
  486. include(pd.procoptions,po_hascallingconvention);
  487. pd.forwarddef:=false;
  488. { may be required to calculate the mangled name }
  489. add_main_procdef_paras(pd);
  490. pd.setmangledname(name);
  491. pd.aliasnames.insert(pd.mangledname);
  492. result:=pd;
  493. end;
  494. procedure AddToStructInits(p:TObject;arg:pointer);
  495. var
  496. StructList: TFPList absolute arg;
  497. begin
  498. if (tdef(p).typ in [objectdef,recorddef]) and
  499. not (df_generic in tdef(p).defoptions) and
  500. ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  501. StructList.Add(p);
  502. end;
  503. class procedure tnodeutils.InsertInitFinalTable;
  504. var
  505. hp : tused_unit;
  506. unitinits : TAsmList;
  507. count : longint;
  508. procedure write_struct_inits(u: tmodule);
  509. var
  510. i: integer;
  511. structlist: TFPList;
  512. pd: tprocdef;
  513. begin
  514. structlist := TFPList.Create;
  515. if assigned(u.globalsymtable) then
  516. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  517. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  518. { write structures }
  519. for i := 0 to structlist.Count - 1 do
  520. begin
  521. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  522. if assigned(pd) then
  523. unitinits.concat(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0))
  524. else
  525. unitinits.concat(Tai_const.Create_nil_codeptr);
  526. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  527. if assigned(pd) then
  528. unitinits.concat(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0))
  529. else
  530. unitinits.concat(Tai_const.Create_nil_codeptr);
  531. inc(count);
  532. end;
  533. structlist.free;
  534. end;
  535. begin
  536. unitinits:=TAsmList.Create;
  537. count:=0;
  538. hp:=tused_unit(usedunits.first);
  539. while assigned(hp) do
  540. begin
  541. { insert class constructors/destructors of the unit }
  542. if (hp.u.flags and uf_classinits) <> 0 then
  543. write_struct_inits(hp.u);
  544. { call the unit init code and make it external }
  545. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  546. begin
  547. if (hp.u.flags and uf_init)<>0 then
  548. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),AT_FUNCTION,0))
  549. else
  550. unitinits.concat(Tai_const.Create_nil_codeptr);
  551. if (hp.u.flags and uf_finalize)<>0 then
  552. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),AT_FUNCTION,0))
  553. else
  554. unitinits.concat(Tai_const.Create_nil_codeptr);
  555. inc(count);
  556. end;
  557. hp:=tused_unit(hp.next);
  558. end;
  559. { insert class constructors/destructor of the program }
  560. if (current_module.flags and uf_classinits) <> 0 then
  561. write_struct_inits(current_module);
  562. { Insert initialization/finalization of the program }
  563. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  564. begin
  565. if (current_module.flags and uf_init)<>0 then
  566. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),AT_FUNCTION,0))
  567. else
  568. unitinits.concat(Tai_const.Create_nil_codeptr);
  569. if (current_module.flags and uf_finalize)<>0 then
  570. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),AT_FUNCTION,0))
  571. else
  572. unitinits.concat(Tai_const.Create_nil_codeptr);
  573. inc(count);
  574. end;
  575. { Insert TableCount,InitCount at start }
  576. unitinits.insert(Tai_const.Create_32bit(0));
  577. unitinits.insert(Tai_const.Create_32bit(count));
  578. { Add to data segment }
  579. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  580. new_section(current_asmdata.asmlists[al_globals],sec_data,'INITFINAL',sizeof(pint));
  581. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITFINAL',AT_DATA,0));
  582. current_asmdata.asmlists[al_globals].concatlist(unitinits);
  583. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITFINAL'));
  584. unitinits.free;
  585. end;
  586. class procedure tnodeutils.InsertThreadvarTablesTable;
  587. var
  588. hp : tused_unit;
  589. ltvTables : TAsmList;
  590. count : longint;
  591. begin
  592. if (tf_section_threadvars in target_info.flags) then
  593. exit;
  594. ltvTables:=TAsmList.Create;
  595. count:=0;
  596. hp:=tused_unit(usedunits.first);
  597. while assigned(hp) do
  598. begin
  599. If (hp.u.flags and uf_threadvars)=uf_threadvars then
  600. begin
  601. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0));
  602. inc(count);
  603. end;
  604. hp:=tused_unit(hp.next);
  605. end;
  606. { Add program threadvars, if any }
  607. If (current_module.flags and uf_threadvars)=uf_threadvars then
  608. begin
  609. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0));
  610. inc(count);
  611. end;
  612. { Insert TableCount at start }
  613. ltvTables.insert(Tai_const.Create_32bit(count));
  614. { insert in data segment }
  615. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  616. new_section(current_asmdata.asmlists[al_globals],sec_data,'FPC_THREADVARTABLES',sizeof(pint));
  617. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('FPC_THREADVARTABLES',AT_DATA,0));
  618. current_asmdata.asmlists[al_globals].concatlist(ltvTables);
  619. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('FPC_THREADVARTABLES'));
  620. ltvTables.free;
  621. end;
  622. procedure AddToThreadvarList(p:TObject;arg:pointer);
  623. var
  624. ltvTable : TAsmList;
  625. begin
  626. ltvTable:=TAsmList(arg);
  627. if (tsym(p).typ=staticvarsym) and
  628. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  629. begin
  630. { address of threadvar }
  631. ltvTable.concat(tai_const.Createname(tstaticvarsym(p).mangledname,0));
  632. { size of threadvar }
  633. ltvTable.concat(tai_const.create_32bit(tstaticvarsym(p).getsize));
  634. end;
  635. end;
  636. class procedure tnodeutils.InsertThreadvars;
  637. var
  638. s : string;
  639. ltvTable : TAsmList;
  640. begin
  641. if (tf_section_threadvars in target_info.flags) then
  642. exit;
  643. ltvTable:=TAsmList.create;
  644. if assigned(current_module.globalsymtable) then
  645. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  646. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  647. if not ltvTable.Empty then
  648. begin
  649. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  650. { end of the list marker }
  651. ltvTable.concat(tai_const.create_sym(nil));
  652. { add to datasegment }
  653. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  654. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  655. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  656. current_asmdata.asmlists[al_globals].concatlist(ltvTable);
  657. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  658. current_module.flags:=current_module.flags or uf_threadvars;
  659. end;
  660. ltvTable.Free;
  661. end;
  662. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  663. var
  664. hp: tused_unit;
  665. hlist: TAsmList;
  666. count: longint;
  667. begin
  668. hlist:=TAsmList.Create;
  669. count:=0;
  670. hp:=tused_unit(usedunits.first);
  671. while assigned(hp) do
  672. begin
  673. if (hp.u.flags and unitflag)=unitflag then
  674. begin
  675. hlist.concat(Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0));
  676. inc(count);
  677. end;
  678. hp:=tused_unit(hp.next);
  679. end;
  680. { Add items from program, if any }
  681. if (current_module.flags and unitflag)=unitflag then
  682. begin
  683. hlist.concat(Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0));
  684. inc(count);
  685. end;
  686. { Insert TableCount at start }
  687. hlist.insert(Tai_const.Create_32bit(count));
  688. { insert in data segment }
  689. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  690. new_section(current_asmdata.asmlists[al_globals],sec_data,tablename,sizeof(pint));
  691. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(tablename,AT_DATA,0));
  692. current_asmdata.asmlists[al_globals].concatlist(hlist);
  693. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(tablename));
  694. hlist.free;
  695. end;
  696. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  697. var
  698. s: string;
  699. item: TTCInitItem;
  700. begin
  701. item:=TTCInitItem(list.First);
  702. if item=nil then
  703. exit;
  704. s:=make_mangledname(prefix,current_module.localsymtable,'');
  705. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  706. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  707. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  708. repeat
  709. { optimize away unused local/static symbols }
  710. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  711. begin
  712. { address to initialize }
  713. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  714. { value with which to initialize }
  715. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  716. end;
  717. item:=TTCInitItem(item.Next);
  718. until item=nil;
  719. { end-of-list marker }
  720. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  721. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  722. current_module.flags:=current_module.flags or unitflag;
  723. end;
  724. class procedure tnodeutils.InsertWideInits;
  725. begin
  726. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  727. end;
  728. class procedure tnodeutils.InsertResStrInits;
  729. begin
  730. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  731. end;
  732. class procedure tnodeutils.InsertWideInitsTablesTable;
  733. begin
  734. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  735. end;
  736. class procedure tnodeutils.InsertResStrTablesTable;
  737. begin
  738. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  739. end;
  740. class procedure tnodeutils.InsertResourceTablesTable;
  741. var
  742. hp : tmodule;
  743. ResourceStringTables : tasmlist;
  744. count : longint;
  745. begin
  746. ResourceStringTables:=tasmlist.Create;
  747. count:=0;
  748. hp:=tmodule(loaded_units.first);
  749. while assigned(hp) do
  750. begin
  751. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  752. begin
  753. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),AT_DATA,0));
  754. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),AT_DATA,0));
  755. inc(count);
  756. end;
  757. hp:=tmodule(hp.next);
  758. end;
  759. { Insert TableCount at start }
  760. ResourceStringTables.insert(Tai_const.Create_pint(count));
  761. { Add to data segment }
  762. maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
  763. new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',sizeof(pint));
  764. current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
  765. current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
  766. current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
  767. ResourceStringTables.free;
  768. end;
  769. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  770. var
  771. ResourceInfo : TAsmList;
  772. begin
  773. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  774. begin
  775. ResourceInfo:=TAsmList.Create;
  776. maybe_new_object_file(ResourceInfo);
  777. new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
  778. ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
  779. if ResourcesUsed then
  780. { Valid pointer to resource information }
  781. ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
  782. else
  783. { Nil pointer to resource information }
  784. {$IFNDEF cpu64bitaddr}
  785. ResourceInfo.Concat(Tai_const.Create_32bit(0));
  786. {$ELSE}
  787. ResourceInfo.Concat(Tai_const.Create_64bit(0));
  788. {$ENDIF}
  789. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  790. current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
  791. ResourceInfo.free;
  792. end;
  793. end;
  794. class procedure tnodeutils.InsertMemorySizes;
  795. {$IFDEF POWERPC}
  796. var
  797. stkcookie: string;
  798. {$ENDIF POWERPC}
  799. begin
  800. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  801. { Insert Ident of the compiler in the .fpc.version section }
  802. new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
  803. current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
  804. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
  805. if not(tf_no_generic_stackcheck in target_info.flags) then
  806. begin
  807. { stacksize can be specified and is now simulated }
  808. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
  809. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
  810. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
  811. end;
  812. {$IFDEF POWERPC}
  813. { AmigaOS4 "stack cookie" support }
  814. if ( target_info.system = system_powerpc_amiga ) then
  815. begin
  816. { this symbol is needed to ignite powerpc amigaos' }
  817. { stack allocation magic for us with the given stack size. }
  818. { note: won't work for m68k amigaos or morphos. (KB) }
  819. str(stacksize,stkcookie);
  820. stkcookie:='$STACK: '+stkcookie+#0;
  821. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  822. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
  823. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
  824. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
  825. end;
  826. {$ENDIF POWERPC}
  827. { Initial heapsize }
  828. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  829. new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',sizeof(pint));
  830. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
  831. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
  832. { allocate an initial heap on embedded systems }
  833. if target_info.system in systems_embedded then
  834. begin
  835. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  836. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_initialheap',current_settings.alignment.varalignmax);
  837. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_initialheap',heapsize));
  838. end;
  839. { Valgrind usage }
  840. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  841. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',sizeof(boolean));
  842. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
  843. current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
  844. end;
  845. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  846. begin
  847. { no parameters by default }
  848. end;
  849. end.