2
0

ngenutil.pas 66 KB

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