ngenutil.pas 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804
  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. fmodule,
  24. aasmbase,aasmdata,
  25. node,nbas,symtype,symsym,symconst,symdef;
  26. type
  27. tinitfinalentry = record
  28. initfunc : TSymStr;
  29. finifunc : TSymStr;
  30. initpd : tprocdef;
  31. finipd : tprocdef;
  32. module : tmodule;
  33. end;
  34. pinitfinalentry = ^tinitfinalentry;
  35. tnodeutils = class
  36. class function call_fail_node:tnode; virtual;
  37. class function initialize_data_node(p:tnode; force: boolean):tnode; virtual;
  38. class function finalize_data_node(p:tnode):tnode; virtual;
  39. strict protected
  40. type
  41. tstructinifinipotype = potype_class_constructor..potype_class_destructor;
  42. class procedure sym_maybe_initialize(p: TObject; arg: pointer);
  43. { generates the code for finalisation of local variables }
  44. class procedure local_varsyms_finalize(p:TObject;arg:pointer);
  45. { generates the code for finalization of static symtable and
  46. all local (static) typed consts }
  47. class procedure static_syms_finalize(p: TObject; arg: pointer);
  48. class procedure sym_maybe_finalize(var stat: tstatementnode; sym: tsym);
  49. class procedure append_struct_initfinis(u: tmodule; initfini: tstructinifinipotype; var stat: tstatementnode); virtual;
  50. public
  51. class procedure procdef_block_add_implicit_initialize_nodes(pd: tprocdef; var stat: tstatementnode);
  52. class procedure procdef_block_add_implicit_finalize_nodes(pd: tprocdef; var stat: tstatementnode);
  53. { returns true if the unit requires an initialisation section (e.g.,
  54. to force class constructors for the JVM target to initialise global
  55. records/arrays) }
  56. class function force_init: boolean; virtual;
  57. { idem for finalization }
  58. class function force_final: boolean; virtual;
  59. { if the funcretsym was moved to the parentfpstruct, use this method to
  60. move its value back back into the funcretsym before the function exit, as
  61. the code generator is hardcoded to use to use the funcretsym when loading
  62. the value to be returned; replacing it with an absolutevarsym that
  63. redirects to the field in the parentfpstruct doesn't work, as the code
  64. generator cannot deal with such symbols }
  65. class procedure load_parentfpstruct_nested_funcret(ressym: tsym; var stat: tstatementnode);
  66. { called after parsing a routine with the code of the entire routine
  67. as argument; can be used to modify the node tree. By default handles
  68. insertion of code for systems that perform the typed constant
  69. initialisation via the node tree }
  70. class function wrap_proc_body(pd: tprocdef; n: tnode): tnode; virtual;
  71. { trashes a paravarsym or localvarsym if possible (not a managed type,
  72. "out" in case of parameter, ...) }
  73. class procedure maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode); virtual;
  74. class function check_insert_trashing(pd: tprocdef): boolean; virtual;
  75. strict protected
  76. { called from wrap_proc_body to insert the trashing for the wrapped
  77. routine's local variables and parameters }
  78. class function maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  79. { callback called for every local variable and parameter by
  80. maybe_insert_trashing(), calls through to maybe_trash_variable() }
  81. class procedure maybe_trash_variable_callback(p: TObject; statn: pointer);
  82. { returns whether a particular sym can be trashed. If not,
  83. maybe_trash_variable won't do anything }
  84. class function trashable_sym(p: tsym): boolean; virtual;
  85. { trashing for 1/2/3/4/8-byte sized variables }
  86. class procedure trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode); virtual;
  87. { trashing for differently sized variables that those handled by
  88. trash_small() }
  89. class procedure trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64); virtual;
  90. { insert a single bss sym, called by insert bssdata (factored out
  91. non-common part for llvm) }
  92. class procedure insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint; varalign: shortint; _typ: Tasmsymtype); virtual;
  93. { initialization of iso styled program parameters }
  94. class procedure initialize_filerecs(p : TObject; statn : pointer);
  95. { finalization of iso styled program parameters }
  96. class procedure finalize_filerecs(p : TObject; statn : pointer);
  97. public
  98. class procedure insertbssdata(sym : tstaticvarsym); virtual;
  99. class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
  100. class procedure InsertInitFinalTable(main : tmodule);
  101. protected
  102. class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:tmoduleflag); virtual;
  103. class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:tmoduleflag); virtual;
  104. class procedure insert_init_final_table(main: tmodule; entries:tfplist); virtual;
  105. class function get_init_final_list(main : tmodule): tfplist;
  106. class procedure release_init_final_list(list:tfplist);
  107. public
  108. class procedure InsertThreadvarTablesTable; virtual;
  109. class procedure InsertThreadvars; virtual;
  110. class procedure InsertWideInitsTablesTable; virtual;
  111. class procedure InsertWideInits; virtual;
  112. class procedure InsertResStrInits; virtual;
  113. class procedure InsertResStrTablesTable; virtual;
  114. class procedure InsertResourceTablesTable; virtual;
  115. class procedure InsertResourceInfo(ResourcesUsed : boolean); virtual;
  116. class procedure InsertMemorySizes; virtual;
  117. { Call this to check if init code is required }
  118. class function has_init_list: boolean; static;
  119. { called right before an object is assembled, can be used to insert
  120. global information into the assembler list (used by LLVM to insert type
  121. info) }
  122. class procedure InsertObjectInfo; virtual;
  123. { register that asm symbol sym with type def has to be considered as "used" even if not
  124. references to it can be found. If compileronly, this is only for the compiler, otherwise
  125. also for the linker }
  126. class procedure RegisterUsedAsmSym(sym: TAsmSymbol; def: tdef; compileronly: boolean); virtual;
  127. class procedure RegisterModuleInitFunction(pd: tprocdef); virtual;
  128. class procedure RegisterModuleFiniFunction(pd: tprocdef); virtual;
  129. strict protected
  130. class procedure add_main_procdef_paras(pd: tdef); virtual;
  131. end;
  132. tnodeutilsclass = class of tnodeutils;
  133. const
  134. cnodeutils: tnodeutilsclass = tnodeutils;
  135. implementation
  136. uses
  137. verbose,version,globals,cutils,constexp,compinnr,
  138. systems,procinfo,pparautl,
  139. aasmtai,aasmcnst,
  140. symbase,symtable,defutil,
  141. nadd,ncal,ncnv,ncon,nflw,ninl,nld,nmem,nutils,
  142. ppu,
  143. pass_1,
  144. export;
  145. class function tnodeutils.call_fail_node:tnode;
  146. var
  147. para : tcallparanode;
  148. newstatement : tstatementnode;
  149. srsym : tsym;
  150. begin
  151. result:=internalstatements(newstatement);
  152. { call fail helper and exit normal }
  153. if is_class(current_structdef) then
  154. begin
  155. srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
  156. if assigned(srsym) and
  157. (srsym.typ=procsym) then
  158. begin
  159. { if self<>0 and vmt<>0 then freeinstance }
  160. addstatement(newstatement,cifnode.create(
  161. caddnode.create(andn,
  162. caddnode.create(unequaln,
  163. load_self_pointer_node,
  164. cnilnode.create),
  165. caddnode.create(unequaln,
  166. load_vmt_pointer_node,
  167. cnilnode.create)),
  168. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil),
  169. nil));
  170. end
  171. else
  172. internalerror(2003051002);
  173. end
  174. else
  175. if is_object(current_structdef) then
  176. begin
  177. { parameter 3 : vmt_offset }
  178. { parameter 2 : pointer to vmt }
  179. { parameter 1 : self pointer }
  180. para:=ccallparanode.create(
  181. cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
  182. ccallparanode.create(
  183. ctypeconvnode.create_internal(
  184. load_vmt_pointer_node,
  185. voidpointertype),
  186. ccallparanode.create(
  187. ctypeconvnode.create_internal(
  188. load_self_pointer_node,
  189. voidpointertype),
  190. nil)));
  191. addstatement(newstatement,
  192. ccallnode.createintern('fpc_help_fail',para));
  193. end
  194. else
  195. internalerror(200305132);
  196. { self:=nil }
  197. addstatement(newstatement,cassignmentnode.create(
  198. load_self_pointer_node,
  199. cnilnode.create));
  200. { exit }
  201. addstatement(newstatement,cexitnode.create(nil));
  202. end;
  203. class function tnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
  204. begin
  205. { prevent initialisation of hidden syms that were moved to
  206. parentfpstructs: the original symbol isn't used anymore, the version
  207. in parentfpstruct will be initialised when that struct gets initialised,
  208. and references to it will actually be translated into references to the
  209. field in the parentfpstruct (so we'll initialise it twice) }
  210. if (target_info.system in systems_fpnestedstruct) and
  211. (p.nodetype=loadn) and
  212. (tloadnode(p).symtableentry.typ=localvarsym) and
  213. tlocalvarsym(tloadnode(p).symtableentry).inparentfpstruct then
  214. begin
  215. p.free;
  216. p := nil;
  217. result:=cnothingnode.create;
  218. end
  219. else
  220. begin
  221. if not assigned(p.resultdef) then
  222. typecheckpass(p);
  223. if is_ansistring(p.resultdef) or
  224. is_wide_or_unicode_string(p.resultdef) or
  225. is_interfacecom_or_dispinterface(p.resultdef) or
  226. is_dynamic_array(p.resultdef) then
  227. begin
  228. result:=cassignmentnode.create(
  229. ctypeconvnode.create_internal(p,voidpointertype),
  230. cnilnode.create
  231. );
  232. end
  233. else if (p.resultdef.typ=variantdef) then
  234. begin
  235. result:=ccallnode.createintern('fpc_variant_init',
  236. ccallparanode.create(
  237. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  238. nil));
  239. end
  240. else
  241. begin
  242. result:=ccallnode.createintern('fpc_initialize',
  243. ccallparanode.create(
  244. caddrnode.create_internal(
  245. crttinode.create(
  246. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  247. ccallparanode.create(
  248. caddrnode.create_internal(p),
  249. nil)));
  250. end;
  251. end;
  252. end;
  253. class function tnodeutils.finalize_data_node(p:tnode):tnode;
  254. var
  255. hs : string;
  256. begin
  257. { see comment in initialize_data_node above }
  258. if (target_info.system in systems_fpnestedstruct) and
  259. (p.nodetype=loadn) and
  260. (tloadnode(p).symtableentry.typ=localvarsym) and
  261. tlocalvarsym(tloadnode(p).symtableentry).inparentfpstruct then
  262. begin
  263. p.free;
  264. p := nil;
  265. result:=cnothingnode.create;
  266. end
  267. else
  268. begin
  269. if not assigned(p.resultdef) then
  270. typecheckpass(p);
  271. { 'decr_ref' suffix is somewhat misleading, all these helpers
  272. set the passed pointer to nil now }
  273. if is_ansistring(p.resultdef) then
  274. hs:='fpc_ansistr_decr_ref'
  275. else if is_widestring(p.resultdef) then
  276. hs:='fpc_widestr_decr_ref'
  277. else if is_unicodestring(p.resultdef) then
  278. hs:='fpc_unicodestr_decr_ref'
  279. else if is_interfacecom_or_dispinterface(p.resultdef) then
  280. hs:='fpc_intf_decr_ref'
  281. else
  282. hs:='';
  283. if hs<>'' then
  284. result:=ccallnode.createintern(hs,
  285. ccallparanode.create(
  286. ctypeconvnode.create_internal(p,voidpointertype),
  287. nil))
  288. else if p.resultdef.typ=variantdef then
  289. begin
  290. result:=ccallnode.createintern('fpc_variant_clear',
  291. ccallparanode.create(
  292. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  293. nil));
  294. end
  295. else
  296. result:=ccallnode.createintern('fpc_finalize',
  297. ccallparanode.create(
  298. caddrnode.create_internal(
  299. crttinode.create(
  300. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  301. ccallparanode.create(
  302. caddrnode.create_internal(p),
  303. nil)));
  304. end;
  305. end;
  306. class procedure tnodeutils.sym_maybe_initialize(p: TObject; arg: pointer);
  307. var
  308. hp : tnode;
  309. begin
  310. if ((tsym(p).typ = localvarsym) or
  311. { check staticvarsym for record management opeators and for objects
  312. which might contain record with management operators }
  313. ((tsym(p).typ = staticvarsym) and
  314. (
  315. is_record(tabstractvarsym(p).vardef) or
  316. is_object(tabstractvarsym(p).vardef)
  317. )
  318. )
  319. ) and
  320. { local (procedure or unit) variables only need initialization if
  321. they are used }
  322. ((tabstractvarsym(p).refs>0) or
  323. { managed return symbols must be inited }
  324. ((tsym(p).typ=localvarsym) and (vo_is_funcret in tlocalvarsym(p).varoptions)) or
  325. { public managed records with Initialize operator need to be initialized
  326. even if they aren't referenced in *this* unit }
  327. (
  328. (tsym(p).owner.symtabletype=globalsymtable) and
  329. is_record(tabstractvarsym(p).vardef) and
  330. (mop_initialize in trecordsymtable(trecorddef(tabstractvarsym(p).vardef).symtable).managementoperators)
  331. )
  332. ) and
  333. not(vo_is_typed_const in tabstractvarsym(p).varoptions) and
  334. not(vo_is_external in tabstractvarsym(p).varoptions) and
  335. (
  336. not (vo_is_default_var in tabstractvarsym(p).varoptions) or
  337. (tabstractvarsym(p).varspez<>vs_const)
  338. ) and
  339. (is_managed_type(tabstractvarsym(p).vardef) or
  340. ((m_iso in current_settings.modeswitches) and (tabstractvarsym(p).vardef.typ=filedef))
  341. ) then
  342. begin
  343. hp:=cloadnode.create(tsym(p),tsym(p).owner);
  344. { ensure that a function reference is not converted to a call }
  345. include(hp.flags,nf_load_procvar);
  346. addstatement(tstatementnode(arg^),initialize_data_node(hp,false));
  347. end;
  348. end;
  349. class procedure tnodeutils.local_varsyms_finalize(p: TObject; arg: pointer);
  350. begin
  351. if (tsym(p).typ=localvarsym) and
  352. (tlocalvarsym(p).refs>0) and
  353. not(vo_is_typed_const in tlocalvarsym(p).varoptions) and
  354. not(vo_is_external in tlocalvarsym(p).varoptions) and
  355. not(vo_is_funcret in tlocalvarsym(p).varoptions) and
  356. (
  357. not(vo_is_default_var in tabstractvarsym(p).varoptions) or
  358. (tabstractvarsym(p).varspez<>vs_const)
  359. ) and
  360. is_managed_type(tlocalvarsym(p).vardef) then
  361. sym_maybe_finalize(tstatementnode(arg^),tsym(p));
  362. end;
  363. class procedure tnodeutils.static_syms_finalize(p: TObject; arg: pointer);
  364. var
  365. i : longint;
  366. pd : tprocdef;
  367. begin
  368. case tsym(p).typ of
  369. staticvarsym :
  370. begin
  371. { local (procedure or unit) variables only need finalization
  372. if they are used
  373. }
  374. if ((tstaticvarsym(p).refs>0) or
  375. { global (unit) variables always need finalization, since
  376. they may also be used in another unit
  377. }
  378. (tstaticvarsym(p).owner.symtabletype=globalsymtable)) and
  379. (
  380. (tstaticvarsym(p).varspez<>vs_const) or
  381. (vo_force_finalize in tstaticvarsym(p).varoptions)
  382. ) and
  383. not(vo_is_funcret in tstaticvarsym(p).varoptions) and
  384. not(vo_is_external in tstaticvarsym(p).varoptions) and
  385. is_managed_type(tstaticvarsym(p).vardef) and
  386. not (
  387. assigned(tstaticvarsym(p).fieldvarsym) and
  388. assigned(tstaticvarsym(p).fieldvarsym.owner.defowner) and
  389. (df_generic in tdef(tstaticvarsym(p).fieldvarsym.owner.defowner).defoptions)
  390. )
  391. then
  392. sym_maybe_finalize(tstatementnode(arg^),tsym(p));
  393. end;
  394. procsym :
  395. begin
  396. for i:=0 to tprocsym(p).ProcdefList.Count-1 do
  397. begin
  398. pd:=tprocdef(tprocsym(p).ProcdefList[i]);
  399. if assigned(pd.localst) and
  400. (pd.procsym=tprocsym(p)) and
  401. (pd.localst.symtabletype<>staticsymtable) then
  402. pd.localst.SymList.ForEachCall(@static_syms_finalize,arg);
  403. end;
  404. end;
  405. else
  406. ;
  407. end;
  408. end;
  409. class procedure tnodeutils.sym_maybe_finalize(var stat: tstatementnode; sym: tsym);
  410. var
  411. hp: tnode;
  412. begin
  413. include(current_procinfo.flags,pi_needs_implicit_finally);
  414. hp:=cloadnode.create(sym,sym.owner);
  415. if (sym.typ=staticvarsym) and (vo_force_finalize in tstaticvarsym(sym).varoptions) then
  416. include(tloadnode(hp).loadnodeflags,loadnf_isinternal_ignoreconst);
  417. { ensure that a function reference interface is not converted to a call }
  418. include(hp.flags,nf_load_procvar);
  419. addstatement(stat,finalize_data_node(hp));
  420. end;
  421. procedure AddToStructInits(p:TObject;arg:pointer);
  422. var
  423. StructList: TFPList absolute arg;
  424. begin
  425. if (tdef(p).typ in [objectdef,recorddef]) and
  426. not (df_generic in tdef(p).defoptions) then
  427. begin
  428. { first add the class... }
  429. if ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  430. StructList.Add(p);
  431. { ... and then also add all subclasses }
  432. tabstractrecorddef(p).symtable.deflist.foreachcall(@AddToStructInits,arg);
  433. end;
  434. end;
  435. class procedure tnodeutils.append_struct_initfinis(u: tmodule; initfini: tstructinifinipotype; var stat: tstatementnode);
  436. var
  437. structlist: tfplist;
  438. i: integer;
  439. pd: tprocdef;
  440. begin
  441. structlist:=tfplist.Create;
  442. if assigned(u.globalsymtable) then
  443. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  444. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  445. { write structures }
  446. for i:=0 to structlist.Count-1 do
  447. begin
  448. pd:=tabstractrecorddef(structlist[i]).find_procdef_bytype(initfini);
  449. if assigned(pd) then
  450. begin
  451. { class constructors are private -> ignore visibility checks }
  452. addstatement(stat,
  453. ccallnode.create(nil,tprocsym(pd.procsym),pd.owner,nil,[cnf_ignore_visibility],nil))
  454. end;
  455. end;
  456. structlist.free;
  457. structlist := nil;
  458. end;
  459. class procedure tnodeutils.procdef_block_add_implicit_initialize_nodes(pd: tprocdef; var stat: tstatementnode);
  460. begin
  461. { initialize local data like ansistrings }
  462. case pd.proctypeoption of
  463. potype_unitinit:
  464. begin
  465. { this is also used for initialization of variables in a
  466. program which does not have a globalsymtable }
  467. if assigned(current_module.globalsymtable) then
  468. TSymtable(current_module.globalsymtable).SymList.ForEachCall(@sym_maybe_initialize,@stat);
  469. TSymtable(current_module.localsymtable).SymList.ForEachCall(@sym_maybe_initialize,@stat);
  470. { insert class constructors }
  471. if mf_classinits in current_module.moduleflags then
  472. append_struct_initfinis(current_module, potype_class_constructor, stat);
  473. end;
  474. { units have separate code for initilization and finalization }
  475. potype_unitfinalize: ;
  476. { program init/final is generated in separate procedure }
  477. potype_proginit: ;
  478. else
  479. current_procinfo.procdef.localst.SymList.ForEachCall(@sym_maybe_initialize,@stat);
  480. end;
  481. end;
  482. class procedure tnodeutils.procdef_block_add_implicit_finalize_nodes(pd: tprocdef; var stat: tstatementnode);
  483. begin
  484. { no finalization in exceptfilters, they /are/ the finalization code }
  485. if current_procinfo.procdef.proctypeoption=potype_exceptfilter then
  486. exit;
  487. { finalize local data like ansistrings}
  488. case current_procinfo.procdef.proctypeoption of
  489. potype_unitfinalize:
  490. begin
  491. { insert class destructors }
  492. if mf_classinits in current_module.moduleflags then
  493. append_struct_initfinis(current_module, potype_class_destructor, stat);
  494. { this is also used for initialization of variables in a
  495. program which does not have a globalsymtable }
  496. if assigned(current_module.globalsymtable) then
  497. TSymtable(current_module.globalsymtable).SymList.ForEachCall(@static_syms_finalize,@stat);
  498. TSymtable(current_module.localsymtable).SymList.ForEachCall(@static_syms_finalize,@stat);
  499. end;
  500. { units/progs have separate code for initialization and finalization }
  501. potype_unitinit: ;
  502. { program init/final is generated in separate procedure }
  503. potype_proginit: ;
  504. else
  505. current_procinfo.procdef.localst.SymList.ForEachCall(@local_varsyms_finalize,@stat);
  506. end;
  507. end;
  508. class function tnodeutils.force_init: boolean;
  509. begin
  510. result:=
  511. (target_info.system in systems_typed_constants_node_init) and
  512. assigned(current_module.tcinitcode);
  513. end;
  514. class function tnodeutils.force_final: boolean;
  515. begin
  516. result:=false;
  517. end;
  518. class procedure tnodeutils.initialize_filerecs(p:TObject;statn:pointer);
  519. var
  520. stat: ^tstatementnode absolute statn;
  521. begin
  522. if (tsym(p).typ=staticvarsym) and
  523. (tstaticvarsym(p).vardef.typ=filedef) and
  524. (tstaticvarsym(p).isoindex<>0) then
  525. case tfiledef(tstaticvarsym(p).vardef).filetyp of
  526. ft_text:
  527. begin
  528. if cs_transparent_file_names in current_settings.globalswitches then
  529. addstatement(stat^,ccallnode.createintern('fpc_textinit_filename_iso',
  530. ccallparanode.create(
  531. cstringconstnode.createstr(tstaticvarsym(p).Name),
  532. ccallparanode.create(
  533. cordconstnode.create(tstaticvarsym(p).isoindex,uinttype,false),
  534. ccallparanode.create(
  535. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  536. nil)))))
  537. else
  538. addstatement(stat^,ccallnode.createintern('fpc_textinit_iso',
  539. ccallparanode.create(
  540. cordconstnode.create(tstaticvarsym(p).isoindex,uinttype,false),
  541. ccallparanode.create(
  542. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  543. nil))));
  544. end;
  545. ft_typed:
  546. begin
  547. if cs_transparent_file_names in current_settings.globalswitches then
  548. addstatement(stat^,ccallnode.createintern('fpc_typedfile_init_filename_iso',
  549. ccallparanode.create(
  550. cstringconstnode.createstr(tstaticvarsym(p).Name),
  551. ccallparanode.create(
  552. cordconstnode.create(tstaticvarsym(p).isoindex,uinttype,false),
  553. ccallparanode.create(
  554. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  555. nil)))))
  556. else
  557. addstatement(stat^,ccallnode.createintern('fpc_typedfile_init_iso',
  558. ccallparanode.create(
  559. cordconstnode.create(tstaticvarsym(p).isoindex,uinttype,false),
  560. ccallparanode.create(
  561. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  562. nil))));
  563. end;
  564. else
  565. ;
  566. end;
  567. end;
  568. class procedure tnodeutils.finalize_filerecs(p:TObject;statn:pointer);
  569. var
  570. stat: ^tstatementnode absolute statn;
  571. begin
  572. if (tsym(p).typ=staticvarsym) and
  573. (tstaticvarsym(p).vardef.typ=filedef) and
  574. (tstaticvarsym(p).isoindex<>0) then
  575. case tfiledef(tstaticvarsym(p).vardef).filetyp of
  576. ft_text:
  577. begin
  578. addstatement(stat^,ccallnode.createintern('fpc_textclose_iso',
  579. ccallparanode.create(
  580. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  581. nil)));
  582. end;
  583. ft_typed:
  584. begin
  585. addstatement(stat^,ccallnode.createintern('fpc_typedfile_close_iso',
  586. ccallparanode.create(
  587. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  588. nil)));
  589. end;
  590. else
  591. ;
  592. end;
  593. end;
  594. class procedure tnodeutils.load_parentfpstruct_nested_funcret(ressym: tsym; var stat: tstatementnode);
  595. var
  596. target: tnode;
  597. begin
  598. target:=cloadnode.create(ressym, ressym.owner);
  599. { ensure the target of this assignment doesn't translate the
  600. funcretsym also to its alias in the parentfpstruct }
  601. include(target.flags, nf_internal);
  602. addstatement(stat,
  603. cassignmentnode.create(
  604. target, cloadnode.create(ressym, ressym.owner)
  605. )
  606. );
  607. end;
  608. class function tnodeutils.wrap_proc_body(pd: tprocdef; n: tnode): tnode;
  609. var
  610. stat: tstatementnode;
  611. block: tnode;
  612. ressym,
  613. psym: tsym;
  614. resdef: tdef;
  615. begin
  616. result:=maybe_insert_trashing(pd,n);
  617. { initialise safecall result variable }
  618. if pd.generate_safecall_wrapper then
  619. begin
  620. ressym:=tsym(pd.localst.Find('safecallresult'));
  621. block:=internalstatements(stat);
  622. addstatement(stat,
  623. cassignmentnode.create(
  624. cloadnode.create(ressym,ressym.owner),
  625. genintconstnode(0)
  626. )
  627. );
  628. addstatement(stat,result);
  629. result:=block;
  630. end;
  631. if (m_isolike_program_para in current_settings.modeswitches) and
  632. (pd.proctypeoption=potype_proginit) then
  633. begin
  634. block:=internalstatements(stat);
  635. pd.localst.SymList.ForEachCall(@initialize_filerecs,@stat);
  636. addstatement(stat,result);
  637. pd.localst.SymList.ForEachCall(@finalize_filerecs,@stat);
  638. result:=block;
  639. end;
  640. if target_info.system in systems_typed_constants_node_init then
  641. begin
  642. case pd.proctypeoption of
  643. potype_class_constructor:
  644. begin
  645. { even though the initialisation code for typed constants may
  646. not yet be complete at this point (there may be more inside
  647. method definitions coming after this class constructor), the
  648. ones from inside the class definition have already been parsed.
  649. in case of $j-, these are marked "final" in Java and such
  650. static fields must be initialsed in the class constructor
  651. itself -> add them here }
  652. block:=internalstatements(stat);
  653. if assigned(pd.struct.tcinitcode) then
  654. begin
  655. addstatement(stat,pd.struct.tcinitcode);
  656. pd.struct.tcinitcode:=nil;
  657. end;
  658. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  659. if assigned(psym) then
  660. begin
  661. if (psym.typ<>procsym) or
  662. (tprocsym(psym).procdeflist.count<>1) then
  663. internalerror(2011040301);
  664. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  665. pd.struct.symtable,nil,[],nil));
  666. end;
  667. addstatement(stat,result);
  668. result:=block
  669. end;
  670. potype_unitinit:
  671. begin
  672. if assigned(current_module.tcinitcode) then
  673. begin
  674. block:=internalstatements(stat);
  675. addstatement(stat,tnode(current_module.tcinitcode));
  676. current_module.tcinitcode:=nil;
  677. addstatement(stat,result);
  678. result:=block;
  679. end;
  680. end;
  681. else case pd.synthetickind of
  682. tsk_tcinit:
  683. begin
  684. if assigned(pd.struct.tcinitcode) then
  685. begin
  686. block:=internalstatements(stat);
  687. addstatement(stat,pd.struct.tcinitcode);
  688. pd.struct.tcinitcode:=nil;
  689. addstatement(stat,result);
  690. result:=block
  691. end
  692. end;
  693. else
  694. ;
  695. end;
  696. end;
  697. end;
  698. if (target_info.system in systems_fpnestedstruct) and
  699. pd.get_funcretsym_info(ressym,resdef) and
  700. (tabstractnormalvarsym(ressym).inparentfpstruct) then
  701. begin
  702. block:=internalstatements(stat);
  703. addstatement(stat,result);
  704. load_parentfpstruct_nested_funcret(ressym,stat);
  705. result:=block;
  706. end;
  707. end;
  708. class function tnodeutils.maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  709. var
  710. stat: tstatementnode;
  711. begin
  712. result:=n;
  713. if check_insert_trashing(pd) then
  714. begin
  715. result:=internalstatements(stat);
  716. pd.parast.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  717. pd.localst.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  718. addstatement(stat,n);
  719. end;
  720. end;
  721. class function tnodeutils.check_insert_trashing(pd: tprocdef): boolean;
  722. begin
  723. result:=
  724. (localvartrashing<>-1) and
  725. not(po_assembler in pd.procoptions);
  726. end;
  727. class function tnodeutils.trashable_sym(p: tsym): boolean;
  728. begin
  729. result:=
  730. ((p.typ=localvarsym) or
  731. ((p.typ=paravarsym) and
  732. ((vo_is_funcret in tabstractnormalvarsym(p).varoptions) or
  733. (tabstractnormalvarsym(p).varspez=vs_out)))) and
  734. not (vo_is_default_var in tabstractnormalvarsym(p).varoptions) and
  735. (not is_managed_type(tabstractnormalvarsym(p).vardef) or
  736. (is_string(tabstractnormalvarsym(p).vardef) and
  737. (vo_is_funcret in tabstractnormalvarsym(p).varoptions)
  738. )
  739. ) and
  740. (tabstractnormalvarsym(p).varoptions*[vo_is_parentfp,vo_is_internal]=[]) and
  741. not assigned(tabstractnormalvarsym(p).defaultconstsym);
  742. end;
  743. class procedure tnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  744. var
  745. size: asizeint;
  746. trashintval: int64;
  747. stringres: tstringconstnode;
  748. begin
  749. if trashable_sym(p) then
  750. begin
  751. trashintval:=trashintvalues[localvartrashing];
  752. if (p.vardef.typ=procvardef) and
  753. ([m_tp_procvar,m_mac_procvar]*current_settings.modeswitches<>[]) then
  754. begin
  755. if tprocvardef(p.vardef).is_addressonly then
  756. { in tp/delphi mode, you need @procvar to get at the contents of
  757. a procvar ... }
  758. trashn:=caddrnode.create(trashn)
  759. else
  760. { ... but if it's a procedure of object, that will only return
  761. the procedure address -> cast to tmethod instead }
  762. trashn:=ctypeconvnode.create_explicit(trashn,methodpointertype);
  763. end;
  764. if is_managed_type(p.vardef) then
  765. begin
  766. if is_string(p.vardef) then
  767. begin
  768. stringres:=
  769. cstringconstnode.createstr(
  770. 'uninitialized function result in '+
  771. tprocdef(p.owner.defowner).customprocname([pno_proctypeoption, pno_paranames,pno_ownername, pno_noclassmarker])
  772. );
  773. { prevent attempts to convert the string to the specified
  774. code page at compile time, as it may not be available (and
  775. it does not matter) }
  776. if is_ansistring(p.vardef) then
  777. stringres.changestringtype(search_system_type('RAWBYTESTRING').typedef);
  778. trash_small(stat,trashn,stringres);
  779. end
  780. else
  781. internalerror(2016030601);
  782. end
  783. else if ((p.typ=localvarsym) and
  784. (not(vo_is_funcret in p.varoptions) or
  785. not is_shortstring(p.vardef))) or
  786. ((p.typ=paravarsym) and
  787. not is_shortstring(p.vardef)) then
  788. begin
  789. size:=p.getsize;
  790. case size of
  791. 0:
  792. begin
  793. { open array -> at least size 1. Can also be zero-sized
  794. record, so check it's actually an array }
  795. if p.vardef.typ=arraydef then
  796. trash_large(stat,trashn,caddnode.create(addn,cinlinenode.create(in_high_x,false,trashn.getcopy),genintconstnode(1)),trashintval)
  797. else
  798. trashn.free;
  799. trashn := nil;
  800. end;
  801. 1: trash_small(stat,
  802. ctypeconvnode.create_internal(trashn,s8inttype),
  803. genintconstnode(shortint(trashintval)));
  804. 2: trash_small(stat,
  805. ctypeconvnode.create_internal(trashn,s16inttype),
  806. genintconstnode(smallint(trashintval)));
  807. 4: trash_small(stat,
  808. ctypeconvnode.create_internal(trashn,s32inttype),
  809. genintconstnode(longint(trashintval)));
  810. 8: trash_small(stat,
  811. ctypeconvnode.create_internal(trashn,s64inttype),
  812. genintconstnode(int64(trashintval)));
  813. else
  814. trash_large(stat,trashn,genintconstnode(size),trashintval);
  815. end;
  816. end
  817. else
  818. begin
  819. { may be an open string, even if is_open_string() returns false
  820. (for some helpers in the system unit) }
  821. { an open string has at least size 2 }
  822. trash_small(stat,
  823. cvecnode.create(trashn.getcopy,genintconstnode(0)),
  824. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  825. trash_small(stat,
  826. cvecnode.create(trashn,genintconstnode(1)),
  827. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  828. end;
  829. end
  830. else
  831. trashn.free;
  832. trashn := nil;
  833. end;
  834. class procedure tnodeutils.maybe_trash_variable_callback(p:TObject;statn:pointer);
  835. var
  836. stat: ^tstatementnode absolute statn;
  837. begin
  838. if not(tsym(p).typ in [localvarsym,paravarsym]) then
  839. exit;
  840. if sp_internal in tsym(p).symoptions then
  841. exit;
  842. maybe_trash_variable(stat^,tabstractnormalvarsym(p),cloadnode.create(tsym(p),tsym(p).owner));
  843. end;
  844. class procedure tnodeutils.trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode);
  845. begin
  846. addstatement(stat,cassignmentnode.create(trashn,trashvaln));
  847. end;
  848. class procedure tnodeutils.trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64);
  849. begin
  850. addstatement(stat,ccallnode.createintern('fpc_fillmem',
  851. ccallparanode.Create(cordconstnode.create(tconstexprint(byte(trashintval)),u8inttype,false),
  852. ccallparanode.Create(sizen,
  853. ccallparanode.Create(trashn,nil)))
  854. ));
  855. end;
  856. class procedure tnodeutils.insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint; varalign: shortint; _typ:Tasmsymtype);
  857. begin
  858. if sym.globalasmsym then
  859. begin
  860. { on AIX/stabx, we cannot generate debug information that encodes
  861. the address of a global symbol, you need a symbol with the same
  862. name as the identifier -> create an extra *local* symbol.
  863. Moreover, such a local symbol will be removed if it's not
  864. referenced anywhere, so also create a reference }
  865. if (target_dbg.id=dbg_stabx) and
  866. (cs_debuginfo in current_settings.moduleswitches) and
  867. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  868. begin
  869. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA,sym.vardef),0));
  870. list.concat(tai_directive.Create(asd_reference,sym.name));
  871. end;
  872. list.concat(Tai_datablock.create_global(sym.mangledname,size,sym.vardef,_typ));
  873. end
  874. else
  875. list.concat(Tai_datablock.create_hidden(sym.mangledname,size,sym.vardef,_typ));
  876. end;
  877. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  878. var
  879. l : asizeint;
  880. varalign,wantedalign,explicitalign : shortint;
  881. storefilepos : tfileposinfo;
  882. list : TAsmList;
  883. sectype : TAsmSectiontype;
  884. asmtype: TAsmsymtype;
  885. begin
  886. storefilepos:=current_filepos;
  887. current_filepos:=sym.fileinfo;
  888. l:=sym.getsize;
  889. wantedalign:=sym.vardef.alignment;
  890. if sym.vardef.inheritsfrom(tabstractrecorddef) and
  891. (sym.vardef.typ in [recorddef]) then
  892. explicitalign:=tabstractrecordsymtable(tabstractrecorddef(sym.vardef).symtable).explicitrecordalignment
  893. else
  894. explicitalign:=0;
  895. if (wantedalign=0) then
  896. varalign:=var_align_size(l)
  897. else
  898. begin
  899. varalign:=var_align(wantedalign);
  900. if (explicitalign>varalign) then
  901. begin
  902. Message1(scanner_w_alignment_larger_than_max,sym.name);
  903. varalign:=explicitalign;
  904. end
  905. else if (wantedalign>varalign) then
  906. begin
  907. { varalign:=wantedalign; this can lead to
  908. troubles on systems like for instance
  909. msdos which do not support 8-byte alignment }
  910. Message1(scanner_n_alignment_larger_than_max,sym.name);
  911. end;
  912. end;
  913. asmtype:=AT_DATA;
  914. if tf_section_threadvars in target_info.flags then
  915. begin
  916. if (vo_is_thread_var in sym.varoptions) then
  917. begin
  918. list:=current_asmdata.asmlists[al_threadvars];
  919. sectype:=sec_threadvar;
  920. asmtype:=AT_TLS;
  921. end
  922. else
  923. begin
  924. list:=current_asmdata.asmlists[al_globals];
  925. sectype:=sec_bss;
  926. end;
  927. end
  928. else
  929. begin
  930. if (vo_is_thread_var in sym.varoptions) then
  931. begin
  932. inc(l,sizeof(pint));
  933. { it doesn't help to set a higher alignment, as }
  934. { the first sizeof(pint) bytes field will offset }
  935. { everything anyway }
  936. varalign:=sizeof(pint);
  937. end;
  938. list:=current_asmdata.asmlists[al_globals];
  939. sectype:=sec_bss;
  940. end;
  941. maybe_new_object_file(list);
  942. if vo_has_section in sym.varoptions then
  943. new_section(list,sec_user,sym.section,varalign)
  944. else
  945. new_section(list,sectype,lower(sym.mangledname),varalign);
  946. insertbsssym(list,sym,l,varalign,asmtype);
  947. current_filepos:=storefilepos;
  948. end;
  949. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  950. var
  951. pd: tprocdef;
  952. begin
  953. if potype<>potype_mainstub then
  954. pd:=cprocdef.create(main_program_level,true)
  955. else
  956. pd:=cprocdef.create(normal_function_level,true);
  957. { always register the def }
  958. pd.register_def;
  959. pd.procsym:=ps;
  960. ps.ProcdefList.Add(pd);
  961. include(pd.procoptions,po_global);
  962. { set procdef options }
  963. pd.proctypeoption:=potype;
  964. pd.proccalloption:=pocall_default;
  965. include(pd.procoptions,po_hascallingconvention);
  966. pd.forwarddef:=false;
  967. { may be required to calculate the mangled name }
  968. add_main_procdef_paras(pd);
  969. pd.setmangledname(name);
  970. { the mainstub is generated via a synthetic proc -> parsed via
  971. psub.read_proc_body() -> that one will insert the mangled name in the
  972. alias names already }
  973. if not(potype in [potype_mainstub,potype_libmainstub]) then
  974. pd.aliasnames.insert(pd.mangledname);
  975. result:=pd;
  976. end;
  977. class function tnodeutils.get_init_final_list(main : tmodule):tfplist;
  978. procedure addusedunits(m : tmodule);
  979. var
  980. hp : tused_unit;
  981. entry : pinitfinalentry;
  982. begin
  983. hp:=tused_unit(m.used_units.first);
  984. while assigned(hp) do
  985. begin
  986. if (not hp.u.initfinalchecked) then
  987. begin
  988. hp.u.initfinalchecked:=True;
  989. addusedunits(hp.u);
  990. if ((hp.u.moduleflags * [mf_init,mf_finalize])<>[]) then
  991. begin
  992. new(entry);
  993. entry^.module:=hp.u;
  994. entry^.initpd:=nil;
  995. entry^.finipd:=nil;
  996. if mf_init in hp.u.moduleflags then
  997. entry^.initfunc:=make_mangledname('INIT$',hp.u.globalsymtable,'')
  998. else
  999. entry^.initfunc:='';
  1000. if mf_finalize in hp.u.moduleflags then
  1001. entry^.finifunc:=make_mangledname('FINALIZE$',hp.u.globalsymtable,'')
  1002. else
  1003. entry^.finifunc:='';
  1004. result.add(entry);
  1005. end;
  1006. end;
  1007. hp:=tused_unit(hp.next);
  1008. end;
  1009. end;
  1010. var
  1011. entry : pinitfinalentry;
  1012. begin
  1013. result:=tfplist.create;
  1014. { Insert initialization/finalization of the used units }
  1015. addusedunits(main);
  1016. { Insert initialization/finalization of the program }
  1017. if (main.moduleflags * [mf_init,mf_finalize])<>[] then
  1018. begin
  1019. new(entry);
  1020. entry^.module:=current_module;
  1021. entry^.initpd:=nil;
  1022. entry^.finipd:=nil;
  1023. if mf_init in current_module.moduleflags then
  1024. entry^.initfunc:=make_mangledname('INIT$',current_module.localsymtable,'')
  1025. else
  1026. entry^.initfunc:='';
  1027. if mf_finalize in current_module.moduleflags then
  1028. entry^.finifunc:=make_mangledname('FINALIZE$',current_module.localsymtable,'')
  1029. else
  1030. entry^.finifunc:='';
  1031. result.add(entry);
  1032. end;
  1033. end;
  1034. class procedure tnodeutils.release_init_final_list(list:tfplist);
  1035. begin
  1036. if not assigned(list) then
  1037. internalerror(2017051901);
  1038. TFPList.FreeAndNilDisposing(list,typeinfo(tinitfinalentry));
  1039. end;
  1040. class procedure tnodeutils.InsertInitFinalTable(main : tmodule);
  1041. var
  1042. entries : tfplist;
  1043. begin
  1044. entries := get_init_final_list(main);
  1045. insert_init_final_table(main,entries);
  1046. release_init_final_list(entries);
  1047. end;
  1048. class procedure tnodeutils.insert_init_final_table(main : tmodule; entries:tfplist);
  1049. var
  1050. i : longint;
  1051. unitinits : ttai_typedconstbuilder;
  1052. nameinit,namefini : TSymStr;
  1053. tabledef: tdef;
  1054. entry : pinitfinalentry;
  1055. unitnametcb : ttai_typedconstbuilder;
  1056. unitnamedef : tdef;
  1057. unitnamelbl : tasmlabel;
  1058. procedure add_initfinal_import(symtable:tsymtable);
  1059. var
  1060. i,j : longint;
  1061. foundinit,foundfini : boolean;
  1062. sym : TSymEntry;
  1063. pd : tprocdef;
  1064. begin
  1065. if (nameinit='') and (namefini='') then
  1066. exit;
  1067. foundinit:=nameinit='';
  1068. foundfini:=namefini='';
  1069. for i:=0 to symtable.SymList.Count-1 do
  1070. begin
  1071. sym:=tsymentry(symtable.SymList[i]);
  1072. if sym.typ<>procsym then
  1073. continue;
  1074. for j:=0 to tprocsym(sym).procdeflist.count-1 do
  1075. begin
  1076. pd:=tprocdef(tprocsym(sym).procdeflist[j]);
  1077. if (nameinit<>'') and not foundinit and pd.has_alias_name(nameinit) then
  1078. begin
  1079. current_module.addimportedsym(sym);
  1080. foundinit:=true;
  1081. end;
  1082. if (namefini<>'') and not foundfini and pd.has_alias_name(namefini) then
  1083. begin
  1084. current_module.addimportedsym(sym);
  1085. foundfini:=true;
  1086. end;
  1087. if foundinit and foundfini then
  1088. break;
  1089. end;
  1090. if foundinit and foundfini then
  1091. break;
  1092. end;
  1093. if not foundinit or not foundfini then
  1094. internalerror(2016041401);
  1095. end;
  1096. begin
  1097. unitinits:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1098. unitinits.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  1099. targetinfos[target_info.system]^.alignment.recordalignmin);
  1100. { tablecount }
  1101. unitinits.emit_ord_const(entries.count,aluuinttype);
  1102. { initcount (initialised at run time }
  1103. unitinits.emit_ord_const(0,aluuinttype);
  1104. for i:=0 to entries.count-1 do
  1105. begin
  1106. entry:=pinitfinalentry(entries[i]);
  1107. if assigned(entry^.initpd) or assigned(entry^.finipd) then
  1108. begin
  1109. if assigned(entry^.initpd) then
  1110. begin
  1111. unitinits.emit_procdef_const(entry^.initpd);
  1112. if entry^.module<>current_module then
  1113. current_module.addimportedsym(entry^.initpd.procsym);
  1114. end
  1115. else
  1116. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  1117. if assigned(entry^.finipd) then
  1118. begin
  1119. unitinits.emit_procdef_const(entry^.finipd);
  1120. if entry^.module<>current_module then
  1121. current_module.addimportedsym(entry^.finipd.procsym);
  1122. end
  1123. else
  1124. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  1125. end
  1126. else
  1127. begin
  1128. nameinit:='';
  1129. namefini:='';
  1130. if entry^.initfunc<>'' then
  1131. begin
  1132. nameinit:=entry^.initfunc;
  1133. unitinits.emit_tai(
  1134. Tai_const.Createname(nameinit,AT_FUNCTION,0),
  1135. voidcodepointertype);
  1136. end
  1137. else
  1138. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  1139. if entry^.finifunc<>'' then
  1140. begin
  1141. namefini:=entry^.finifunc;
  1142. unitinits.emit_tai(
  1143. Tai_const.Createname(namefini,AT_FUNCTION,0),
  1144. voidcodepointertype);
  1145. end
  1146. else
  1147. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  1148. if entry^.module<>current_module then
  1149. add_initfinal_import(entry^.module.localsymtable);
  1150. end;
  1151. { Add pointer to unit name }
  1152. if assigned(entry^.module.realmodulename) then
  1153. begin
  1154. { Create string constant and emit pointer to it }
  1155. unitinits.start_internal_data_builder(current_asmdata.asmlists[al_globals],sec_rodata,'',unitnametcb,unitnamelbl);
  1156. unitnamedef:=unitnametcb.emit_shortstring_const(entry^.module.realmodulename^);
  1157. unitinits.finish_internal_data_builder(unitnametcb,unitnamelbl,unitnamedef,sizeof(pint));
  1158. unitinits.queue_init(charpointertype);
  1159. unitinits.queue_emit_asmsym(unitnamelbl,unitnamedef);
  1160. end
  1161. else
  1162. unitinits.emit_tai(Tai_const.Create_nil_dataptr,charpointertype);
  1163. end;
  1164. { Add to data segment }
  1165. tabledef:=unitinits.end_anonymous_record;
  1166. current_asmdata.asmlists[al_globals].concatlist(
  1167. unitinits.get_final_asmlist(
  1168. current_asmdata.DefineAsmSymbol('INITFINAL',AB_GLOBAL,AT_DATA,tabledef),
  1169. tabledef,
  1170. sec_data,'INITFINAL',const_align(sizeof(pint))
  1171. )
  1172. );
  1173. unitinits.free;
  1174. unitinits := nil;
  1175. end;
  1176. class function tnodeutils.has_init_list: boolean;
  1177. var
  1178. hp : tused_unit;
  1179. begin
  1180. Result:=True;
  1181. { Check current module first }
  1182. if mf_init in current_module.moduleflags then
  1183. Exit;
  1184. { Check used units }
  1185. hp:=tused_unit(usedunits.first);
  1186. while assigned(hp) do
  1187. begin
  1188. if mf_init in hp.u.moduleflags then
  1189. Exit;
  1190. hp:=tused_unit(hp.next);
  1191. end;
  1192. { We reach this point, none of the used units have an initialisation list }
  1193. Result:=False;
  1194. end;
  1195. class procedure tnodeutils.InsertThreadvarTablesTable;
  1196. var
  1197. hp : tused_unit;
  1198. tcb: ttai_typedconstbuilder;
  1199. count: longint;
  1200. sym: tasmsymbol;
  1201. placeholder: ttypedconstplaceholder;
  1202. tabledef: tdef;
  1203. begin
  1204. if (tf_section_threadvars in target_info.flags) then
  1205. exit;
  1206. count:=0;
  1207. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1208. tcb.begin_anonymous_record('',default_settings.packrecords,voidpointertype.alignment,targetinfos[target_info.system]^.alignment.recordalignmin);
  1209. placeholder:=tcb.emit_placeholder(sizesinttype);
  1210. hp:=tused_unit(usedunits.first);
  1211. while assigned(hp) do
  1212. begin
  1213. if mf_threadvars in hp.u.moduleflags then
  1214. begin
  1215. sym:=current_asmdata.RefAsmSymbol(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),AT_DATA,true);
  1216. tcb.emit_tai(
  1217. tai_const.Create_sym(sym),
  1218. voidpointertype);
  1219. current_module.add_extern_asmsym(sym);
  1220. inc(count);
  1221. end;
  1222. hp:=tused_unit(hp.next);
  1223. end;
  1224. { Add program threadvars, if any }
  1225. if mf_threadvars in current_module.moduleflags then
  1226. begin
  1227. sym:=current_asmdata.RefAsmSymbol(make_mangledname('THREADVARLIST',current_module.localsymtable,''),AT_DATA,true);
  1228. tcb.emit_tai(
  1229. Tai_const.Create_sym(sym),
  1230. voidpointertype);
  1231. inc(count);
  1232. end;
  1233. { set the count at the start }
  1234. placeholder.replace(tai_const.Create_sizeint(count),sizesinttype);
  1235. placeholder.free;
  1236. placeholder := nil;
  1237. { insert in data segment }
  1238. tabledef:=tcb.end_anonymous_record;
  1239. sym:=current_asmdata.DefineAsmSymbol('FPC_THREADVARTABLES',AB_GLOBAL,AT_DATA,tabledef);
  1240. current_asmdata.asmlists[al_globals].concatlist(
  1241. tcb.get_final_asmlist(
  1242. sym,tabledef,sec_data,'FPC_THREADVARTABLES',const_align(sizeof(pint))
  1243. )
  1244. );
  1245. tcb.free;
  1246. tcb := nil;
  1247. end;
  1248. procedure AddToThreadvarList(p:TObject;arg:pointer);
  1249. var
  1250. tcb: ttai_typedconstbuilder;
  1251. field1, field2: tsym;
  1252. begin
  1253. if (tsym(p).typ=staticvarsym) and
  1254. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  1255. begin
  1256. tcb:=ttai_typedconstbuilder(arg);
  1257. { address of threadvar }
  1258. tcb.emit_tai(tai_const.Createname(tstaticvarsym(p).mangledname,0),
  1259. cpointerdef.getreusable(
  1260. get_threadvar_record(tstaticvarsym(p).vardef,field1,field2)
  1261. )
  1262. );
  1263. { size of threadvar }
  1264. tcb.emit_ord_const(tstaticvarsym(p).getsize,u32inttype);
  1265. end;
  1266. end;
  1267. class procedure tnodeutils.InsertThreadvars;
  1268. var
  1269. s : TSymStr;
  1270. tcb: ttai_typedconstbuilder;
  1271. sym: tasmsymbol;
  1272. tabledef: trecorddef;
  1273. add : boolean;
  1274. begin
  1275. if (tf_section_threadvars in target_info.flags) then
  1276. exit;
  1277. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1278. tabledef:=tcb.begin_anonymous_record('',default_settings.packrecords,voidpointertype.alignment,targetinfos[target_info.system]^.alignment.recordalignmin);
  1279. if assigned(current_module.globalsymtable) then
  1280. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,tcb);
  1281. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,tcb);
  1282. if trecordsymtable(tabledef.symtable).datasize<>0 then
  1283. { terminator }
  1284. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  1285. tcb.end_anonymous_record;
  1286. add:=trecordsymtable(tabledef.symtable).datasize<>0;
  1287. if add then
  1288. begin
  1289. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  1290. sym:=current_asmdata.DefineAsmSymbol(s,AB_GLOBAL,AT_DATA_FORCEINDIRECT,tabledef);
  1291. current_asmdata.asmlists[al_globals].concatlist(
  1292. tcb.get_final_asmlist(sym,tabledef,sec_data,s,const_align(sizeof(pint))));
  1293. include(current_module.moduleflags,mf_threadvars);
  1294. current_module.add_public_asmsym(sym);
  1295. end;
  1296. tcb.Free;
  1297. tcb := nil;
  1298. end;
  1299. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:tmoduleflag);
  1300. var
  1301. hp: tused_unit;
  1302. tcb: ttai_typedconstbuilder;
  1303. countplaceholder: ttypedconstplaceholder;
  1304. tabledef: tdef;
  1305. count: longint;
  1306. begin
  1307. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1308. tcb.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  1309. targetinfos[target_info.system]^.alignment.recordalignmin
  1310. );
  1311. { placeholder for the count }
  1312. countplaceholder:=tcb.emit_placeholder(sizesinttype);
  1313. count:=0;
  1314. hp:=tused_unit(usedunits.first);
  1315. while assigned(hp) do
  1316. begin
  1317. if unitflag in hp.u.moduleflags then
  1318. begin
  1319. tcb.emit_tai(
  1320. Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0),
  1321. voidcodepointertype);
  1322. inc(count);
  1323. end;
  1324. hp:=tused_unit(hp.next);
  1325. end;
  1326. { Add items from program, if any }
  1327. if unitflag in current_module.moduleflags then
  1328. begin
  1329. tcb.emit_tai(
  1330. Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0),
  1331. voidcodepointertype);
  1332. inc(count);
  1333. end;
  1334. { Insert TableCount at start }
  1335. countplaceholder.replace(Tai_const.Create_sizeint(count),sizesinttype);
  1336. countplaceholder.free;
  1337. countplaceholder := nil;
  1338. { insert in data segment }
  1339. tabledef:=tcb.end_anonymous_record;
  1340. current_asmdata.asmlists[al_globals].concatlist(
  1341. tcb.get_final_asmlist(
  1342. current_asmdata.DefineAsmSymbol(tablename,AB_GLOBAL,AT_DATA,tabledef),
  1343. tabledef,
  1344. sec_data,tablename,const_align(sizeof(pint))
  1345. )
  1346. );
  1347. tcb.free;
  1348. tcb := nil;
  1349. end;
  1350. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:tmoduleflag);
  1351. var
  1352. s: string;
  1353. item: TTCInitItem;
  1354. tcb: ttai_typedconstbuilder;
  1355. rawdatadef: tdef;
  1356. begin
  1357. item:=TTCInitItem(list.First);
  1358. if item=nil then
  1359. exit;
  1360. s:=make_mangledname(prefix,current_module.localsymtable,'');
  1361. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1362. tcb.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  1363. targetinfos[target_info.system]^.alignment.recordalignmin);
  1364. repeat
  1365. { optimize away unused local/static symbols }
  1366. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  1367. begin
  1368. { address to initialize }
  1369. tcb.queue_init(voidpointertype);
  1370. rawdatadef:=carraydef.getreusable(cansichartype,tstaticvarsym(item.sym).vardef.size);
  1371. tcb.queue_vecn(rawdatadef,item.offset);
  1372. tcb.queue_typeconvn(cpointerdef.getreusable(tstaticvarsym(item.sym).vardef),cpointerdef.getreusable(rawdatadef));
  1373. tcb.queue_emit_staticvar(tstaticvarsym(item.sym));
  1374. { value with which to initialize }
  1375. tcb.emit_tai(Tai_const.Create_sym(item.datalabel),item.datadef)
  1376. end;
  1377. item:=TTCInitItem(item.Next);
  1378. until item=nil;
  1379. { end-of-list marker }
  1380. tcb.emit_tai(Tai_const.Create_nil_dataptr,voidpointertype);
  1381. rawdatadef:=tcb.end_anonymous_record;
  1382. current_asmdata.asmlists[al_globals].concatList(
  1383. tcb.get_final_asmlist(
  1384. current_asmdata.DefineAsmSymbol(s,AB_GLOBAL,AT_DATA,rawdatadef),
  1385. rawdatadef,sec_data,s,const_align(sizeof(pint))));
  1386. tcb.free;
  1387. tcb := nil;
  1388. include(current_module.moduleflags,unitflag);
  1389. end;
  1390. class procedure tnodeutils.InsertWideInits;
  1391. begin
  1392. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,mf_wideinits);
  1393. end;
  1394. class procedure tnodeutils.InsertResStrInits;
  1395. begin
  1396. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,mf_resstrinits);
  1397. end;
  1398. class procedure tnodeutils.InsertWideInitsTablesTable;
  1399. begin
  1400. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',mf_wideinits);
  1401. end;
  1402. class procedure tnodeutils.InsertResStrTablesTable;
  1403. begin
  1404. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',mf_resstrinits);
  1405. end;
  1406. class procedure tnodeutils.InsertResourceTablesTable;
  1407. var
  1408. hp : tmodule;
  1409. count : longint;
  1410. tcb : ttai_typedconstbuilder;
  1411. countplaceholder : ttypedconstplaceholder;
  1412. tabledef: tdef;
  1413. begin
  1414. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1415. count:=0;
  1416. hp:=tmodule(loaded_units.first);
  1417. tcb.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  1418. targetinfos[target_info.system]^.alignment.recordalignmin);
  1419. countplaceholder:=tcb.emit_placeholder(sizesinttype);
  1420. while assigned(hp) do
  1421. begin
  1422. if mf_has_resourcestrings in hp.moduleflags then
  1423. begin
  1424. tcb.emit_tai(Tai_const.Create_sym(
  1425. ctai_typedconstbuilder.get_vectorized_dead_strip_section_symbol_start('RESSTR',hp.localsymtable,[tcdssso_register_asmsym,tcdssso_use_indirect])),
  1426. voidpointertype
  1427. );
  1428. tcb.emit_tai(Tai_const.Create_sym(
  1429. ctai_typedconstbuilder.get_vectorized_dead_strip_section_symbol_end('RESSTR',hp.localsymtable,[tcdssso_register_asmsym,tcdssso_use_indirect])),
  1430. voidpointertype
  1431. );
  1432. inc(count);
  1433. end;
  1434. hp:=tmodule(hp.next);
  1435. end;
  1436. { Insert TableCount at start }
  1437. countplaceholder.replace(Tai_const.Create_sizeint(count),sizesinttype);
  1438. countplaceholder.free;
  1439. countplaceholder := nil;
  1440. { Add to data segment }
  1441. tabledef:=tcb.end_anonymous_record;
  1442. current_asmdata.AsmLists[al_globals].concatList(
  1443. tcb.get_final_asmlist(
  1444. current_asmdata.DefineAsmSymbol('FPC_RESOURCESTRINGTABLES',AB_GLOBAL,AT_DATA,tabledef),
  1445. tabledef,sec_rodata,'FPC_RESOURCESTRINGTABLES',const_align(sizeof(pint))
  1446. )
  1447. );
  1448. tcb.free;
  1449. tcb := nil;
  1450. end;
  1451. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  1452. var
  1453. tcb: ttai_typedconstbuilder;
  1454. begin
  1455. if (target_res.id in [res_elf,res_macho,res_xcoff,res_wasm]) or
  1456. { generate the FPC_RESLOCATION symbol even when using external resources,
  1457. because in SysInit we can only reference it unconditionally }
  1458. ((target_res.id=res_ext) and (target_info.system in systems_darwin)) then
  1459. begin
  1460. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1461. if ResourcesUsed and (target_res.id<>res_ext) then
  1462. tcb.emit_tai(Tai_const.Createname('FPC_RESSYMBOL',0),voidpointertype)
  1463. else
  1464. { Nil pointer to resource information }
  1465. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  1466. current_asmdata.asmlists[al_globals].concatList(
  1467. tcb.get_final_asmlist(
  1468. current_asmdata.DefineAsmSymbol('FPC_RESLOCATION',AB_GLOBAL,AT_DATA,voidpointertype),
  1469. voidpointertype,
  1470. sec_rodata,
  1471. 'FPC_RESLOCATION',
  1472. const_align(sizeof(puint))
  1473. )
  1474. );
  1475. tcb.free;
  1476. tcb := nil;
  1477. end;
  1478. end;
  1479. class procedure tnodeutils.InsertMemorySizes;
  1480. var
  1481. tcb: ttai_typedconstbuilder;
  1482. s: shortstring;
  1483. sym: tasmsymbol;
  1484. def: tdef;
  1485. begin
  1486. { Insert Ident of the compiler in the .fpc.version section }
  1487. tcb:=ctai_typedconstbuilder.create([tcalo_no_dead_strip]);
  1488. s:='FPC '+full_version_string+
  1489. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname;
  1490. {$ifdef m68k}
  1491. { Ensure that the size of s is multiple of 2 to avoid problems
  1492. like on m68k-amiga which has a .balignw just after,
  1493. causes an assembler error }
  1494. while (length(s) mod 2) <> 0 do
  1495. s:=s+' ';
  1496. {$endif m68k}
  1497. def:=carraydef.getreusable(cansichartype,length(s));
  1498. tcb.maybe_begin_aggregate(def);
  1499. tcb.emit_tai(Tai_string.Create(s),def);
  1500. tcb.maybe_end_aggregate(def);
  1501. sym:=current_asmdata.DefineAsmSymbol('__fpc_ident',AB_LOCAL,AT_DATA,def);
  1502. current_asmdata.asmlists[al_globals].concatlist(
  1503. tcb.get_final_asmlist(sym,def,sec_fpc,'version',const_align(32))
  1504. );
  1505. tcb.free;
  1506. if (tf_emit_stklen in target_info.flags) or
  1507. not(tf_no_generic_stackcheck in target_info.flags) then
  1508. begin
  1509. { stacksize can be specified and is now simulated }
  1510. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1511. tcb.emit_tai(Tai_const.Create_int_dataptr(stacksize),ptruinttype);
  1512. sym:=current_asmdata.DefineAsmSymbol('__stklen',AB_GLOBAL,AT_DATA,ptruinttype);
  1513. current_asmdata.asmlists[al_globals].concatlist(
  1514. tcb.get_final_asmlist(sym,ptruinttype,sec_data,'__stklen',const_align(sizeof(pint)))
  1515. );
  1516. tcb.free;
  1517. tcb := nil;
  1518. end;
  1519. { allocate the stack on the ZX Spectrum system }
  1520. if target_info.system in [system_z80_zxspectrum] then
  1521. begin
  1522. { tai_datablock cannot yet be handled via the high level typed const
  1523. builder, because it implies the generation of a symbol, while this
  1524. is separate in the builder }
  1525. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1526. new_section(current_asmdata.asmlists[al_globals],sec_stack,'__fpc_stackarea_start',current_settings.alignment.varalignmax);
  1527. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_stackarea_start',stacksize-1,carraydef.getreusable(u8inttype,stacksize-1),AT_DATA));
  1528. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_stackarea_end',1,carraydef.getreusable(u8inttype,1),AT_DATA));
  1529. end;
  1530. {$IFDEF POWERPC}
  1531. { AmigaOS4 "stack cookie" support }
  1532. if ( target_info.system = system_powerpc_amiga ) then
  1533. begin
  1534. { this symbol is needed to ignite powerpc amigaos' }
  1535. { stack allocation magic for us with the given stack size. }
  1536. { note: won't work for m68k amigaos or morphos. (KB) }
  1537. str(stacksize,s);
  1538. s:='$STACK: '+s+#0;
  1539. def:=carraydef.getreusable(cansichartype,length(s));
  1540. tcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
  1541. tcb.maybe_begin_aggregate(def);
  1542. tcb.emit_tai(Tai_string.Create(s),def);
  1543. tcb.maybe_end_aggregate(def);
  1544. sym:=current_asmdata.DefineAsmSymbol('__stack_cookie',AB_GLOBAL,AT_DATA,def);
  1545. current_asmdata.asmlists[al_globals].concatlist(
  1546. tcb.get_final_asmlist(sym,def,sec_data,'__stack_cookie',sizeof(pint))
  1547. );
  1548. tcb.free;
  1549. tcb := nil;
  1550. end;
  1551. {$ENDIF POWERPC}
  1552. { Initial heapsize }
  1553. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1554. tcb.emit_tai(Tai_const.Create_int_dataptr(heapsize),ptruinttype);
  1555. sym:=current_asmdata.DefineAsmSymbol('__heapsize',AB_GLOBAL,AT_DATA,ptruinttype);
  1556. current_asmdata.asmlists[al_globals].concatlist(
  1557. tcb.get_final_asmlist(sym,ptruinttype,sec_data,'__heapsize',const_align(sizeof(pint)))
  1558. );
  1559. tcb.free;
  1560. tcb := nil;
  1561. { allocate an initial heap on embedded systems }
  1562. if target_info.system in (systems_embedded+systems_freertos+[system_z80_zxspectrum,system_z80_msxdos]) then
  1563. begin
  1564. { tai_datablock cannot yet be handled via the high level typed const
  1565. builder, because it implies the generation of a symbol, while this
  1566. is separate in the builder }
  1567. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1568. new_section(current_asmdata.asmlists[al_globals],sec_bss,'__fpc_initialheap',current_settings.alignment.varalignmax);
  1569. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_initialheap',heapsize,carraydef.getreusable(u8inttype,heapsize),AT_DATA));
  1570. end;
  1571. { Valgrind usage }
  1572. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1573. tcb.emit_ord_const(byte(cs_gdb_valgrind in current_settings.globalswitches),u8inttype);
  1574. sym:=current_asmdata.DefineAsmSymbol('__fpc_valgrind',AB_GLOBAL,AT_DATA,u8inttype);
  1575. current_asmdata.asmlists[al_globals].concatlist(
  1576. tcb.get_final_asmlist(sym,u8inttype,sec_data,'__fpc_valgrind',const_align(sizeof(pint)))
  1577. );
  1578. tcb.free;
  1579. tcb := nil;
  1580. end;
  1581. class procedure tnodeutils.InsertObjectInfo;
  1582. var
  1583. tcb: ttai_typedconstbuilder;
  1584. begin
  1585. if (m_objectivec1 in current_settings.modeswitches) then
  1586. begin
  1587. { first 4 bytes contain version information about this section (currently version 0),
  1588. next 4 bytes contain flags (currently only regarding whether the code in the object
  1589. file supports or requires garbage collection)
  1590. }
  1591. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_no_dead_strip]);
  1592. tcb.emit_ord_const(0,u64inttype);
  1593. current_asmdata.asmlists[al_objc_data].concatList(
  1594. tcb.get_final_asmlist(
  1595. current_asmdata.DefineAsmSymbol(target_asm.labelprefix+'_OBJC_IMAGE_INFO',AB_LOCAL,AT_DATA,u64inttype),
  1596. u64inttype,sec_objc_image_info,'_OBJC_IMAGE_INFO',const_align(sizeof(pint))
  1597. )
  1598. );
  1599. tcb.free;
  1600. tcb := nil;
  1601. end;
  1602. end;
  1603. class procedure tnodeutils.RegisterUsedAsmSym(sym: TAsmSymbol; def: tdef; compileronly: boolean);
  1604. begin
  1605. { don't do anything by default }
  1606. end;
  1607. class procedure tnodeutils.RegisterModuleInitFunction(pd: tprocdef);
  1608. begin
  1609. { setinitname may generate a new section -> don't add to the
  1610. current list, because we assume this remains a text section }
  1611. exportlib.setinitname(current_asmdata.AsmLists[al_pure_assembler],pd.mangledname);
  1612. end;
  1613. class procedure tnodeutils.RegisterModuleFiniFunction(pd: tprocdef);
  1614. begin
  1615. exportlib.setfininame(current_asmdata.AsmLists[al_pure_assembler],pd.mangledname);
  1616. end;
  1617. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  1618. var
  1619. pvs: tparavarsym;
  1620. begin
  1621. { stub for calling FPC_SYSTEMMAIN from the C main -> add argc/argv/argp }
  1622. if (tprocdef(pd).proctypeoption=potype_mainstub) and
  1623. (target_info.system in (systems_darwin+[system_powerpc_macosclassic]+systems_aix)) then
  1624. begin
  1625. pvs:=cparavarsym.create('ARGC',1,vs_const,s32inttype,[]);
  1626. tprocdef(pd).parast.insertsym(pvs);
  1627. pvs:=cparavarsym.create('ARGV',2,vs_const,cpointerdef.getreusable(charpointertype),[]);
  1628. tprocdef(pd).parast.insertsym(pvs);
  1629. pvs:=cparavarsym.create('ARGP',3,vs_const,cpointerdef.getreusable(charpointertype),[]);
  1630. tprocdef(pd).parast.insertsym(pvs);
  1631. tprocdef(pd).calcparas;
  1632. end
  1633. { package stub for Windows is a DLLMain }
  1634. else if (tprocdef(pd).proctypeoption=potype_pkgstub) and
  1635. (target_info.system in systems_all_windows+systems_nativent) then
  1636. begin
  1637. pvs:=cparavarsym.create('HINSTANCE',1,vs_const,uinttype,[]);
  1638. tprocdef(pd).parast.insertsym(pvs);
  1639. pvs:=cparavarsym.create('DLLREASON',2,vs_const,u32inttype,[]);
  1640. tprocdef(pd).parast.insertsym(pvs);
  1641. pvs:=cparavarsym.create('DLLPARAM',3,vs_const,voidpointertype,[]);
  1642. tprocdef(pd).parast.insertsym(pvs);
  1643. tprocdef(pd).returndef:=bool32type;
  1644. insert_funcret_para(tprocdef(pd));
  1645. tprocdef(pd).calcparas;
  1646. end;
  1647. end;
  1648. end.