ngenutil.pas 39 KB

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