ngenutil.pas 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  1. {
  2. Copyright (c) 1998-2011 by Florian Klaempfl
  3. Generic version of some node tree helper routines that can be overridden
  4. by cpu-specific versions
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ngenutil;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cclasses,globtype,
  23. aasmdata,
  24. node,nbas,symtype,symsym,symconst,symdef;
  25. type
  26. tnodeutils = class
  27. class function call_fail_node:tnode; virtual;
  28. class function initialize_data_node(p:tnode; force: boolean):tnode; virtual;
  29. class function finalize_data_node(p:tnode):tnode; virtual;
  30. { returns true if the unit requires an initialisation section (e.g.,
  31. to force class constructors for the JVM target to initialise global
  32. records/arrays) }
  33. class function force_init: boolean; virtual;
  34. { idem for finalization }
  35. class function force_final: boolean; virtual;
  36. { called after parsing a routine with the code of the entire routine
  37. as argument; can be used to modify the node tree. By default handles
  38. insertion of code for systems that perform the typed constant
  39. initialisation via the node tree }
  40. class function wrap_proc_body(pd: tprocdef; n: tnode): tnode; virtual;
  41. { trashes a paravarsym or localvarsym if possible (not a managed type,
  42. "out" in case of parameter, ...) }
  43. class procedure maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode); virtual;
  44. strict protected
  45. { called from wrap_proc_body to insert the trashing for the wrapped
  46. routine's local variables and parameters }
  47. class function maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  48. class function check_insert_trashing(pd: tprocdef): boolean; virtual;
  49. { callback called for every local variable and parameter by
  50. maybe_insert_trashing(), calls through to maybe_trash_variable() }
  51. class procedure maybe_trash_variable_callback(p: TObject; statn: pointer);
  52. { returns whether a particular sym can be trashed. If not,
  53. maybe_trash_variable won't do anything }
  54. class function trashable_sym(p: tsym): boolean; virtual;
  55. { trashing for 1/2/3/4/8-byte sized variables }
  56. class procedure trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode); virtual;
  57. { trashing for differently sized variables that those handled by
  58. trash_small() }
  59. class procedure trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64); virtual;
  60. { insert a single bss sym, called by insert bssdata (factored out
  61. non-common part for llvm) }
  62. class procedure insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint; varalign: shortint); virtual;
  63. { initialization of iso styled program parameters }
  64. class procedure initialize_textrec(p : TObject; statn : pointer);
  65. { finalization of iso styled program parameters }
  66. class procedure finalize_textrec(p : TObject; statn : pointer);
  67. public
  68. class procedure insertbssdata(sym : tstaticvarsym); virtual;
  69. class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
  70. class procedure InsertInitFinalTable; virtual;
  71. protected
  72. class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal); virtual;
  73. class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal); virtual;
  74. public
  75. class procedure InsertThreadvarTablesTable; virtual;
  76. class procedure InsertThreadvars; virtual;
  77. class procedure InsertWideInitsTablesTable; virtual;
  78. class procedure InsertWideInits; virtual;
  79. class procedure InsertResStrInits; virtual;
  80. class procedure InsertResStrTablesTable; virtual;
  81. class procedure InsertResourceTablesTable; virtual;
  82. class procedure InsertResourceInfo(ResourcesUsed : boolean); virtual;
  83. class procedure InsertMemorySizes; virtual;
  84. { called right before an object is assembled, can be used to insert
  85. global information into the assembler list (used by LLVM to insert type
  86. info) }
  87. class procedure InsertObjectInfo; virtual;
  88. strict protected
  89. class procedure add_main_procdef_paras(pd: tdef); virtual;
  90. end;
  91. tnodeutilsclass = class of tnodeutils;
  92. const
  93. cnodeutils: tnodeutilsclass = tnodeutils;
  94. implementation
  95. uses
  96. verbose,version,globals,cutils,constexp,
  97. scanner,systems,procinfo,fmodule,
  98. aasmbase,aasmtai,aasmcnst,
  99. symbase,symtable,defutil,symcreat,
  100. nadd,ncal,ncnv,ncon,nflw,ninl,nld,nmem,nobj,nutils,ncgutil,
  101. ppu,
  102. pass_1;
  103. class function tnodeutils.call_fail_node:tnode;
  104. var
  105. para : tcallparanode;
  106. newstatement : tstatementnode;
  107. srsym : tsym;
  108. begin
  109. result:=internalstatements(newstatement);
  110. { call fail helper and exit normal }
  111. if is_class(current_structdef) then
  112. begin
  113. srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
  114. if assigned(srsym) and
  115. (srsym.typ=procsym) then
  116. begin
  117. { if self<>0 and vmt<>0 then freeinstance }
  118. addstatement(newstatement,cifnode.create(
  119. caddnode.create(andn,
  120. caddnode.create(unequaln,
  121. load_self_pointer_node,
  122. cnilnode.create),
  123. caddnode.create(unequaln,
  124. load_vmt_pointer_node,
  125. cnilnode.create)),
  126. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil),
  127. nil));
  128. end
  129. else
  130. internalerror(200305108);
  131. end
  132. else
  133. if is_object(current_structdef) then
  134. begin
  135. { parameter 3 : vmt_offset }
  136. { parameter 2 : pointer to vmt }
  137. { parameter 1 : self pointer }
  138. para:=ccallparanode.create(
  139. cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
  140. ccallparanode.create(
  141. ctypeconvnode.create_internal(
  142. load_vmt_pointer_node,
  143. voidpointertype),
  144. ccallparanode.create(
  145. ctypeconvnode.create_internal(
  146. load_self_pointer_node,
  147. voidpointertype),
  148. nil)));
  149. addstatement(newstatement,
  150. ccallnode.createintern('fpc_help_fail',para));
  151. end
  152. else
  153. internalerror(200305132);
  154. { self:=nil }
  155. addstatement(newstatement,cassignmentnode.create(
  156. load_self_pointer_node,
  157. cnilnode.create));
  158. { exit }
  159. addstatement(newstatement,cexitnode.create(nil));
  160. end;
  161. class function tnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
  162. begin
  163. if not assigned(p.resultdef) then
  164. typecheckpass(p);
  165. if is_ansistring(p.resultdef) or
  166. is_wide_or_unicode_string(p.resultdef) or
  167. is_interfacecom_or_dispinterface(p.resultdef) or
  168. is_dynamic_array(p.resultdef) then
  169. begin
  170. result:=cassignmentnode.create(
  171. ctypeconvnode.create_internal(p,voidpointertype),
  172. cnilnode.create
  173. );
  174. end
  175. else if (p.resultdef.typ=variantdef) then
  176. begin
  177. result:=ccallnode.createintern('fpc_variant_init',
  178. ccallparanode.create(
  179. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  180. nil));
  181. end
  182. else
  183. begin
  184. result:=ccallnode.createintern('fpc_initialize',
  185. ccallparanode.create(
  186. caddrnode.create_internal(
  187. crttinode.create(
  188. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  189. ccallparanode.create(
  190. caddrnode.create_internal(p),
  191. nil)));
  192. end;
  193. end;
  194. class function tnodeutils.finalize_data_node(p:tnode):tnode;
  195. var
  196. hs : string;
  197. begin
  198. if not assigned(p.resultdef) then
  199. typecheckpass(p);
  200. { 'decr_ref' suffix is somewhat misleading, all these helpers
  201. set the passed pointer to nil now }
  202. if is_ansistring(p.resultdef) then
  203. hs:='fpc_ansistr_decr_ref'
  204. else if is_widestring(p.resultdef) then
  205. hs:='fpc_widestr_decr_ref'
  206. else if is_unicodestring(p.resultdef) then
  207. hs:='fpc_unicodestr_decr_ref'
  208. else if is_interfacecom_or_dispinterface(p.resultdef) then
  209. hs:='fpc_intf_decr_ref'
  210. else
  211. hs:='';
  212. if hs<>'' then
  213. result:=ccallnode.createintern(hs,
  214. ccallparanode.create(
  215. ctypeconvnode.create_internal(p,voidpointertype),
  216. nil))
  217. else if p.resultdef.typ=variantdef then
  218. begin
  219. result:=ccallnode.createintern('fpc_variant_clear',
  220. ccallparanode.create(
  221. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  222. nil));
  223. end
  224. else
  225. result:=ccallnode.createintern('fpc_finalize',
  226. ccallparanode.create(
  227. caddrnode.create_internal(
  228. crttinode.create(
  229. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  230. ccallparanode.create(
  231. caddrnode.create_internal(p),
  232. nil)));
  233. end;
  234. class function tnodeutils.force_init: boolean;
  235. begin
  236. result:=
  237. (target_info.system in systems_typed_constants_node_init) and
  238. assigned(current_module.tcinitcode);
  239. end;
  240. class function tnodeutils.force_final: boolean;
  241. begin
  242. result:=false;
  243. end;
  244. class procedure tnodeutils.initialize_textrec(p:TObject;statn:pointer);
  245. var
  246. stat: ^tstatementnode absolute statn;
  247. begin
  248. if (tsym(p).typ=staticvarsym) and
  249. (tstaticvarsym(p).vardef.typ=filedef) and
  250. (tfiledef(tstaticvarsym(p).vardef).filetyp=ft_text) and
  251. (tstaticvarsym(p).isoindex<>0) then
  252. begin
  253. addstatement(stat^,ccallnode.createintern('fpc_textinit_iso',
  254. ccallparanode.create(
  255. cordconstnode.create(tstaticvarsym(p).isoindex,uinttype,false),
  256. ccallparanode.create(
  257. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  258. nil))));
  259. end;
  260. end;
  261. class procedure tnodeutils.finalize_textrec(p:TObject;statn:pointer);
  262. var
  263. stat: ^tstatementnode absolute statn;
  264. begin
  265. if (tsym(p).typ=staticvarsym) and
  266. (tstaticvarsym(p).vardef.typ=filedef) and
  267. (tfiledef(tstaticvarsym(p).vardef).filetyp=ft_text) and
  268. (tstaticvarsym(p).isoindex<>0) then
  269. begin
  270. addstatement(stat^,ccallnode.createintern('fpc_textclose_iso',
  271. ccallparanode.create(
  272. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  273. nil)));
  274. end;
  275. end;
  276. class function tnodeutils.wrap_proc_body(pd: tprocdef; n: tnode): tnode;
  277. var
  278. stat: tstatementnode;
  279. block,
  280. target: tnode;
  281. psym: tsym;
  282. begin
  283. result:=maybe_insert_trashing(pd,n);
  284. if (m_isolike_program_para in current_settings.modeswitches) and
  285. (pd.proctypeoption=potype_proginit) then
  286. begin
  287. block:=internalstatements(stat);
  288. pd.localst.SymList.ForEachCall(@initialize_textrec,@stat);
  289. addstatement(stat,result);
  290. pd.localst.SymList.ForEachCall(@finalize_textrec,@stat);
  291. result:=block;
  292. end;
  293. if target_info.system in systems_typed_constants_node_init then
  294. begin
  295. case pd.proctypeoption of
  296. potype_class_constructor:
  297. begin
  298. { even though the initialisation code for typed constants may
  299. not yet be complete at this point (there may be more inside
  300. method definitions coming after this class constructor), the
  301. ones from inside the class definition have already been parsed.
  302. in case of $j-, these are marked "final" in Java and such
  303. static fields must be initialsed in the class constructor
  304. itself -> add them here }
  305. block:=internalstatements(stat);
  306. if assigned(pd.struct.tcinitcode) then
  307. begin
  308. addstatement(stat,pd.struct.tcinitcode);
  309. pd.struct.tcinitcode:=nil;
  310. end;
  311. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  312. if assigned(psym) then
  313. begin
  314. if (psym.typ<>procsym) or
  315. (tprocsym(psym).procdeflist.count<>1) then
  316. internalerror(2011040301);
  317. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  318. pd.struct.symtable,nil,[],nil));
  319. end;
  320. addstatement(stat,result);
  321. result:=block
  322. end;
  323. potype_unitinit:
  324. begin
  325. if assigned(current_module.tcinitcode) then
  326. begin
  327. block:=internalstatements(stat);
  328. addstatement(stat,tnode(current_module.tcinitcode));
  329. current_module.tcinitcode:=nil;
  330. addstatement(stat,result);
  331. result:=block;
  332. end;
  333. end;
  334. else case pd.synthetickind of
  335. tsk_tcinit:
  336. begin
  337. if assigned(pd.struct.tcinitcode) then
  338. begin
  339. block:=internalstatements(stat);
  340. addstatement(stat,pd.struct.tcinitcode);
  341. pd.struct.tcinitcode:=nil;
  342. addstatement(stat,result);
  343. result:=block
  344. end
  345. end;
  346. end;
  347. end;
  348. end;
  349. if target_info.system in systems_fpnestedstruct then
  350. begin
  351. { if the funcretsym was moved to the parentfpstruct, move its value
  352. back into the funcretsym now, as the code generator is hardcoded
  353. to use the funcretsym when loading the value to be returned;
  354. replacing it with an absolutevarsym that redirects to the field in
  355. the parentfpstruct doesn't work, as the code generator cannot deal
  356. with such symbols }
  357. if assigned(pd.funcretsym) and
  358. tabstractnormalvarsym(pd.funcretsym).inparentfpstruct then
  359. begin
  360. block:=internalstatements(stat);
  361. addstatement(stat,result);
  362. target:=cloadnode.create(pd.funcretsym,pd.funcretsym.owner);
  363. { ensure the target of this assignment doesn't translate the
  364. funcretsym also to its alias in the parentfpstruct }
  365. include(target.flags,nf_internal);
  366. addstatement(stat,
  367. cassignmentnode.create(
  368. target,cloadnode.create(pd.funcretsym,pd.funcretsym.owner)
  369. )
  370. );
  371. result:=block;
  372. end;
  373. end;
  374. end;
  375. class function tnodeutils.maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  376. var
  377. stat: tstatementnode;
  378. begin
  379. result:=n;
  380. if check_insert_trashing(pd) then
  381. begin
  382. result:=internalstatements(stat);
  383. pd.parast.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  384. pd.localst.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  385. addstatement(stat,n);
  386. end;
  387. end;
  388. class function tnodeutils.check_insert_trashing(pd: tprocdef): boolean;
  389. begin
  390. result:=
  391. (localvartrashing<>-1) and
  392. not(po_assembler in pd.procoptions);
  393. end;
  394. class function tnodeutils.trashable_sym(p: tsym): boolean;
  395. begin
  396. result:=
  397. ((p.typ=localvarsym) or
  398. ((p.typ=paravarsym) and
  399. ((vo_is_funcret in tabstractnormalvarsym(p).varoptions) or
  400. (tabstractnormalvarsym(p).varspez=vs_out)))) and
  401. not (vo_is_default_var in tabstractnormalvarsym(p).varoptions) and
  402. (not is_managed_type(tabstractnormalvarsym(p).vardef) or
  403. (is_string(tabstractnormalvarsym(p).vardef) and
  404. (vo_is_funcret in tabstractnormalvarsym(p).varoptions)
  405. )
  406. ) and
  407. not assigned(tabstractnormalvarsym(p).defaultconstsym);
  408. end;
  409. class procedure tnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  410. var
  411. size: asizeint;
  412. trashintval: int64;
  413. begin
  414. if trashable_sym(p) then
  415. begin
  416. trashintval:=trashintvalues[localvartrashing];
  417. if (p.vardef.typ=procvardef) and
  418. ([m_tp_procvar,m_mac_procvar]*current_settings.modeswitches<>[]) then
  419. begin
  420. if tprocvardef(p.vardef).is_addressonly then
  421. { in tp/delphi mode, you need @procvar to get at the contents of
  422. a procvar ... }
  423. trashn:=caddrnode.create(trashn)
  424. else
  425. { ... but if it's a procedure of object, that will only return
  426. the procedure address -> cast to tmethod instead }
  427. trashn:=ctypeconvnode.create_explicit(trashn,methodpointertype);
  428. end;
  429. if is_managed_type(p.vardef) then
  430. begin
  431. if is_string(p.vardef) then
  432. trash_small(stat,trashn,
  433. cstringconstnode.createstr(
  434. 'uninitialized function result in '+
  435. tprocdef(p.owner.defowner).customprocname([pno_proctypeoption, pno_paranames,pno_ownername, pno_noclassmarker])
  436. )
  437. )
  438. else
  439. internalerror(2016030601);
  440. end
  441. else if ((p.typ=localvarsym) and
  442. (not(vo_is_funcret in p.varoptions) or
  443. not is_shortstring(p.vardef))) or
  444. ((p.typ=paravarsym) and
  445. not is_shortstring(p.vardef)) then
  446. begin
  447. size:=p.getsize;
  448. case size of
  449. 0:
  450. begin
  451. { open array -> at least size 1. Can also be zero-sized
  452. record, so check it's actually an array }
  453. if p.vardef.typ=arraydef then
  454. trash_large(stat,trashn,caddnode.create(addn,cinlinenode.create(in_high_x,false,trashn.getcopy),genintconstnode(1)),trashintval)
  455. else
  456. trashn.free;
  457. end;
  458. 1: trash_small(stat,
  459. ctypeconvnode.create_internal(trashn,s8inttype),
  460. genintconstnode(shortint(trashintval)));
  461. 2: trash_small(stat,
  462. ctypeconvnode.create_internal(trashn,s16inttype),
  463. genintconstnode(smallint(trashintval)));
  464. 4: trash_small(stat,
  465. ctypeconvnode.create_internal(trashn,s32inttype),
  466. genintconstnode(longint(trashintval)));
  467. 8: trash_small(stat,
  468. ctypeconvnode.create_internal(trashn,s64inttype),
  469. genintconstnode(int64(trashintval)));
  470. else
  471. trash_large(stat,trashn,genintconstnode(size),trashintval);
  472. end;
  473. end
  474. else
  475. begin
  476. { may be an open string, even if is_open_string() returns false
  477. (for some helpers in the system unit) }
  478. { an open string has at least size 2 }
  479. trash_small(stat,
  480. cvecnode.create(trashn.getcopy,genintconstnode(0)),
  481. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  482. trash_small(stat,
  483. cvecnode.create(trashn,genintconstnode(1)),
  484. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  485. end;
  486. end
  487. else
  488. trashn.free;
  489. end;
  490. class procedure tnodeutils.maybe_trash_variable_callback(p:TObject;statn:pointer);
  491. var
  492. stat: ^tstatementnode absolute statn;
  493. begin
  494. if not(tsym(p).typ in [localvarsym,paravarsym]) then
  495. exit;
  496. maybe_trash_variable(stat^,tabstractnormalvarsym(p),cloadnode.create(tsym(p),tsym(p).owner));
  497. end;
  498. class procedure tnodeutils.trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode);
  499. begin
  500. addstatement(stat,cassignmentnode.create(trashn,trashvaln));
  501. end;
  502. class procedure tnodeutils.trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64);
  503. begin
  504. addstatement(stat,ccallnode.createintern('fpc_fillmem',
  505. ccallparanode.Create(cordconstnode.create(tconstexprint(byte(trashintval)),u8inttype,false),
  506. ccallparanode.Create(sizen,
  507. ccallparanode.Create(trashn,nil)))
  508. ));
  509. end;
  510. class procedure tnodeutils.insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint; varalign: shortint);
  511. var
  512. symind : tasmsymbol;
  513. begin
  514. if sym.globalasmsym then
  515. begin
  516. { on AIX/stabx, we cannot generate debug information that encodes
  517. the address of a global symbol, you need a symbol with the same
  518. name as the identifier -> create an extra *local* symbol.
  519. Moreover, such a local symbol will be removed if it's not
  520. referenced anywhere, so also create a reference }
  521. if (target_dbg.id=dbg_stabx) and
  522. (cs_debuginfo in current_settings.moduleswitches) and
  523. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  524. begin
  525. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA),0));
  526. list.concat(tai_directive.Create(asd_reference,sym.name));
  527. end;
  528. list.concat(Tai_datablock.create_global(sym.mangledname,size));
  529. end
  530. else
  531. list.concat(Tai_datablock.create(sym.mangledname,size));
  532. { add the indirect symbol if needed }
  533. new_section(list,sec_rodata,lower(sym.mangledname),const_align(sym.vardef.alignment));
  534. symind:=current_asmdata.DefineAsmSymbol(sym.mangledname,AB_INDIRECT,AT_DATA);
  535. list.concat(Tai_symbol.Create_Global(symind,0));
  536. list.concat(Tai_const.Createname(sym.mangledname,AT_DATA,0));
  537. list.concat(tai_symbol_end.Create(symind));
  538. end;
  539. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  540. var
  541. l : asizeint;
  542. varalign : shortint;
  543. storefilepos : tfileposinfo;
  544. list : TAsmList;
  545. sectype : TAsmSectiontype;
  546. begin
  547. storefilepos:=current_filepos;
  548. current_filepos:=sym.fileinfo;
  549. l:=sym.getsize;
  550. varalign:=sym.vardef.alignment;
  551. if (varalign=0) then
  552. varalign:=var_align_size(l)
  553. else
  554. varalign:=var_align(varalign);
  555. if tf_section_threadvars in target_info.flags then
  556. begin
  557. if (vo_is_thread_var in sym.varoptions) then
  558. begin
  559. list:=current_asmdata.asmlists[al_threadvars];
  560. sectype:=sec_threadvar;
  561. end
  562. else
  563. begin
  564. list:=current_asmdata.asmlists[al_globals];
  565. sectype:=sec_bss;
  566. end;
  567. end
  568. else
  569. begin
  570. if (vo_is_thread_var in sym.varoptions) then
  571. begin
  572. inc(l,sizeof(pint));
  573. { it doesn't help to set a higher alignment, as }
  574. { the first sizeof(pint) bytes field will offset }
  575. { everything anyway }
  576. varalign:=sizeof(pint);
  577. end;
  578. list:=current_asmdata.asmlists[al_globals];
  579. sectype:=sec_bss;
  580. end;
  581. maybe_new_object_file(list);
  582. if vo_has_section in sym.varoptions then
  583. new_section(list,sec_user,sym.section,varalign)
  584. else
  585. new_section(list,sectype,lower(sym.mangledname),varalign);
  586. insertbsssym(list,sym,l,varalign);
  587. current_filepos:=storefilepos;
  588. end;
  589. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  590. var
  591. pd: tprocdef;
  592. begin
  593. if potype<>potype_mainstub then
  594. pd:=cprocdef.create(main_program_level,true)
  595. else
  596. pd:=cprocdef.create(normal_function_level,true);
  597. { always register the def }
  598. pd.register_def;
  599. pd.procsym:=ps;
  600. ps.ProcdefList.Add(pd);
  601. include(pd.procoptions,po_global);
  602. { set procdef options }
  603. pd.proctypeoption:=potype;
  604. pd.proccalloption:=pocall_default;
  605. include(pd.procoptions,po_hascallingconvention);
  606. pd.forwarddef:=false;
  607. { may be required to calculate the mangled name }
  608. add_main_procdef_paras(pd);
  609. pd.setmangledname(name);
  610. { the mainstub is generated via a synthetic proc -> parsed via
  611. psub.read_proc_body() -> that one will insert the mangled name in the
  612. alias names already }
  613. if potype<>potype_mainstub then
  614. pd.aliasnames.insert(pd.mangledname);
  615. result:=pd;
  616. end;
  617. procedure AddToStructInits(p:TObject;arg:pointer);
  618. var
  619. StructList: TFPList absolute arg;
  620. begin
  621. if (tdef(p).typ in [objectdef,recorddef]) and
  622. not (df_generic in tdef(p).defoptions) then
  623. begin
  624. { first add the class... }
  625. if ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  626. StructList.Add(p);
  627. { ... and then also add all subclasses }
  628. tabstractrecorddef(p).symtable.deflist.foreachcall(@AddToStructInits,arg);
  629. end;
  630. end;
  631. class procedure tnodeutils.InsertInitFinalTable;
  632. var
  633. hp : tused_unit;
  634. unitinits : ttai_typedconstbuilder;
  635. count : aint;
  636. tablecountplaceholder: ttypedconstplaceholder;
  637. nameinit,namefini : TSymStr;
  638. procedure write_struct_inits(u: tmodule);
  639. var
  640. i: integer;
  641. structlist: TFPList;
  642. pd: tprocdef;
  643. begin
  644. structlist := TFPList.Create;
  645. if assigned(u.globalsymtable) then
  646. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  647. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  648. { write structures }
  649. for i:=0 to structlist.Count-1 do
  650. begin
  651. pd:=tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  652. if assigned(pd) then
  653. begin
  654. unitinits.emit_procdef_const(pd);
  655. if u<>current_module then
  656. u.addimportedsym(pd.procsym);
  657. end
  658. else
  659. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  660. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  661. if assigned(pd) then
  662. begin
  663. unitinits.emit_procdef_const(pd);
  664. if u<>current_module then
  665. u.addimportedsym(pd.procsym);
  666. end
  667. else
  668. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  669. inc(count);
  670. end;
  671. structlist.free;
  672. end;
  673. procedure add_initfinal_import(symtable:tsymtable);
  674. var
  675. i,j : longint;
  676. foundinit,foundfini : boolean;
  677. sym : TSymEntry;
  678. pd : tprocdef;
  679. begin
  680. if (nameinit='') and (namefini='') then
  681. exit;
  682. foundinit:=nameinit='';
  683. foundfini:=namefini='';
  684. for i:=0 to symtable.SymList.Count-1 do
  685. begin
  686. sym:=tsymentry(symtable.SymList[i]);
  687. if sym.typ<>procsym then
  688. continue;
  689. for j:=0 to tprocsym(sym).procdeflist.count-1 do
  690. begin
  691. pd:=tprocdef(tprocsym(sym).procdeflist[j]);
  692. if (nameinit<>'') and not foundinit and has_alias_name(pd,nameinit) then
  693. begin
  694. current_module.addimportedsym(sym);
  695. foundinit:=true;
  696. end;
  697. if (namefini<>'') and not foundfini and has_alias_name(pd,namefini) then
  698. begin
  699. current_module.addimportedsym(sym);
  700. foundfini:=true;
  701. end;
  702. if foundinit and foundfini then
  703. break;
  704. end;
  705. if foundinit and foundfini then
  706. break;
  707. end;
  708. if not foundinit or not foundfini then
  709. internalerror(2016041401);
  710. end;
  711. begin
  712. unitinits:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  713. unitinits.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  714. targetinfos[target_info.system]^.alignment.recordalignmin,
  715. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  716. { placeholder for tablecount }
  717. tablecountplaceholder:=unitinits.emit_placeholder(sinttype);
  718. { initcount (initialised at run time }
  719. unitinits.emit_ord_const(0,sinttype);
  720. count:=0;
  721. hp:=tused_unit(usedunits.first);
  722. while assigned(hp) do
  723. begin
  724. { insert class constructors/destructors of the unit }
  725. if (hp.u.flags and uf_classinits) <> 0 then
  726. write_struct_inits(hp.u);
  727. { call the unit init code and make it external }
  728. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  729. begin
  730. if count=high(aint) then
  731. Message1(cg_f_max_units_reached,tostr(count));
  732. nameinit:='';
  733. namefini:='';
  734. if (hp.u.flags and uf_init)<>0 then
  735. begin
  736. nameinit:=make_mangledname('INIT$',hp.u.globalsymtable,'');
  737. unitinits.emit_tai(
  738. Tai_const.Createname(nameinit,AT_FUNCTION,0),
  739. voidcodepointertype);
  740. end
  741. else
  742. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  743. if (hp.u.flags and uf_finalize)<>0 then
  744. begin
  745. namefini:=make_mangledname('FINALIZE$',hp.u.globalsymtable,'');
  746. unitinits.emit_tai(
  747. Tai_const.Createname(namefini,AT_FUNCTION,0),
  748. voidcodepointertype)
  749. end
  750. else
  751. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  752. add_initfinal_import(hp.u.localsymtable);
  753. inc(count);
  754. end;
  755. hp:=tused_unit(hp.next);
  756. end;
  757. { insert class constructors/destructor of the program }
  758. if (current_module.flags and uf_classinits) <> 0 then
  759. write_struct_inits(current_module);
  760. { Insert initialization/finalization of the program }
  761. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  762. begin
  763. if (current_module.flags and uf_init)<>0 then
  764. unitinits.emit_tai(
  765. Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),AT_FUNCTION,0),
  766. voidcodepointertype)
  767. else
  768. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  769. if (current_module.flags and uf_finalize)<>0 then
  770. unitinits.emit_tai(
  771. Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),AT_FUNCTION,0),
  772. voidcodepointertype)
  773. else
  774. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  775. inc(count);
  776. end;
  777. { fill in tablecount }
  778. tablecountplaceholder.replace(tai_const.Create_aint(count),sinttype);
  779. tablecountplaceholder.free;
  780. { Add to data segment }
  781. current_asmdata.asmlists[al_globals].concatlist(
  782. unitinits.get_final_asmlist(
  783. current_asmdata.DefineAsmSymbol('INITFINAL',AB_GLOBAL,AT_DATA),
  784. unitinits.end_anonymous_record,
  785. sec_data,'INITFINAL',sizeof(pint)
  786. )
  787. );
  788. unitinits.free;
  789. end;
  790. class procedure tnodeutils.InsertThreadvarTablesTable;
  791. var
  792. hp : tused_unit;
  793. tcb: ttai_typedconstbuilder;
  794. count: longint;
  795. sym: tasmsymbol;
  796. placeholder: ttypedconstplaceholder;
  797. begin
  798. if (tf_section_threadvars in target_info.flags) then
  799. exit;
  800. count:=0;
  801. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  802. tcb.begin_anonymous_record('',1,sizeof(pint),
  803. targetinfos[target_info.system]^.alignment.recordalignmin,
  804. targetinfos[target_info.system]^.alignment.maxCrecordalign
  805. );
  806. placeholder:=tcb.emit_placeholder(u32inttype);
  807. hp:=tused_unit(usedunits.first);
  808. while assigned(hp) do
  809. begin
  810. if (hp.u.flags and uf_threadvars)=uf_threadvars then
  811. begin
  812. tcb.emit_tai(
  813. tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0),
  814. voidpointertype);
  815. inc(count);
  816. end;
  817. hp:=tused_unit(hp.next);
  818. end;
  819. { Add program threadvars, if any }
  820. if (current_module.flags and uf_threadvars)=uf_threadvars then
  821. begin
  822. tcb.emit_tai(
  823. Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0),
  824. voidpointertype);
  825. inc(count);
  826. end;
  827. { set the count at the start }
  828. placeholder.replace(tai_const.Create_32bit(count),u32inttype);
  829. placeholder.free;
  830. { insert in data segment }
  831. sym:=current_asmdata.DefineAsmSymbol('FPC_THREADVARTABLES',AB_GLOBAL,AT_DATA);
  832. current_asmdata.asmlists[al_globals].concatlist(
  833. tcb.get_final_asmlist(
  834. sym,tcb.end_anonymous_record,sec_data,'FPC_THREADVARTABLES',sizeof(pint)
  835. )
  836. );
  837. tcb.free;
  838. end;
  839. procedure AddToThreadvarList(p:TObject;arg:pointer);
  840. var
  841. tcb: ttai_typedconstbuilder;
  842. field1, field2: tsym;
  843. begin
  844. if (tsym(p).typ=staticvarsym) and
  845. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  846. begin
  847. tcb:=ttai_typedconstbuilder(arg);
  848. { address of threadvar }
  849. tcb.emit_tai(tai_const.Createname(tstaticvarsym(p).mangledname,0),
  850. cpointerdef.getreusable(
  851. get_threadvar_record(tstaticvarsym(p).vardef,field1,field2)
  852. )
  853. );
  854. { size of threadvar }
  855. tcb.emit_ord_const(tstaticvarsym(p).getsize,u32inttype);
  856. end;
  857. end;
  858. class procedure tnodeutils.InsertThreadvars;
  859. var
  860. s : string;
  861. tcb: ttai_typedconstbuilder;
  862. sym: tasmsymbol;
  863. tabledef: trecorddef;
  864. begin
  865. if (tf_section_threadvars in target_info.flags) then
  866. exit;
  867. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  868. tabledef:=tcb.begin_anonymous_record('',1,sizeof(pint),
  869. targetinfos[target_info.system]^.alignment.recordalignmin,
  870. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  871. if assigned(current_module.globalsymtable) then
  872. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,tcb);
  873. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,tcb);
  874. if trecordsymtable(tabledef.symtable).datasize<>0 then
  875. { terminator }
  876. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  877. tcb.end_anonymous_record;
  878. if trecordsymtable(tabledef.symtable).datasize<>0 then
  879. begin
  880. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  881. sym:=current_asmdata.DefineAsmSymbol(s,AB_GLOBAL,AT_DATA);
  882. current_asmdata.asmlists[al_globals].concatlist(
  883. tcb.get_final_asmlist(sym,tabledef,sec_data,s,sizeof(pint)));
  884. current_module.flags:=current_module.flags or uf_threadvars;
  885. end;
  886. tcb.Free;
  887. end;
  888. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  889. var
  890. hp: tused_unit;
  891. tcb: ttai_typedconstbuilder;
  892. countplaceholder: ttypedconstplaceholder;
  893. count: longint;
  894. begin
  895. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  896. tcb.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  897. targetinfos[target_info.system]^.alignment.recordalignmin,
  898. targetinfos[target_info.system]^.alignment.maxCrecordalign
  899. );
  900. { placeholder for the count }
  901. countplaceholder:=tcb.emit_placeholder(ptruinttype);
  902. count:=0;
  903. hp:=tused_unit(usedunits.first);
  904. while assigned(hp) do
  905. begin
  906. if (hp.u.flags and unitflag)=unitflag then
  907. begin
  908. tcb.emit_tai(
  909. Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0),
  910. voidcodepointertype);
  911. inc(count);
  912. end;
  913. hp:=tused_unit(hp.next);
  914. end;
  915. { Add items from program, if any }
  916. if (current_module.flags and unitflag)=unitflag then
  917. begin
  918. tcb.emit_tai(
  919. Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0),
  920. voidcodepointertype);
  921. inc(count);
  922. end;
  923. { Insert TableCount at start }
  924. countplaceholder.replace(Tai_const.Create_pint(count),ptruinttype);
  925. countplaceholder.free;
  926. { insert in data segment }
  927. current_asmdata.asmlists[al_globals].concatlist(
  928. tcb.get_final_asmlist(
  929. current_asmdata.DefineAsmSymbol(tablename,AB_GLOBAL,AT_DATA),
  930. tcb.end_anonymous_record,
  931. sec_data,tablename,sizeof(pint)
  932. )
  933. );
  934. tcb.free;
  935. end;
  936. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  937. var
  938. s: string;
  939. item: TTCInitItem;
  940. begin
  941. item:=TTCInitItem(list.First);
  942. if item=nil then
  943. exit;
  944. s:=make_mangledname(prefix,current_module.localsymtable,'');
  945. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  946. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  947. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  948. repeat
  949. { optimize away unused local/static symbols }
  950. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  951. begin
  952. { address to initialize }
  953. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  954. { value with which to initialize }
  955. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  956. end;
  957. item:=TTCInitItem(item.Next);
  958. until item=nil;
  959. { end-of-list marker }
  960. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  961. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  962. current_module.flags:=current_module.flags or unitflag;
  963. end;
  964. class procedure tnodeutils.InsertWideInits;
  965. begin
  966. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  967. end;
  968. class procedure tnodeutils.InsertResStrInits;
  969. begin
  970. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  971. end;
  972. class procedure tnodeutils.InsertWideInitsTablesTable;
  973. begin
  974. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  975. end;
  976. class procedure tnodeutils.InsertResStrTablesTable;
  977. begin
  978. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  979. end;
  980. class procedure tnodeutils.InsertResourceTablesTable;
  981. var
  982. hp : tmodule;
  983. count : longint;
  984. tcb : ttai_typedconstbuilder;
  985. countplaceholder : ttypedconstplaceholder;
  986. begin
  987. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  988. count:=0;
  989. hp:=tmodule(loaded_units.first);
  990. tcb.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  991. targetinfos[target_info.system]^.alignment.recordalignmin,
  992. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  993. countplaceholder:=tcb.emit_placeholder(ptruinttype);
  994. while assigned(hp) do
  995. begin
  996. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  997. begin
  998. tcb.emit_tai(Tai_const.Create_sym(
  999. ctai_typedconstbuilder.get_vectorized_dead_strip_section_symbol_start('RESSTR',hp.localsymtable,false)),
  1000. voidpointertype
  1001. );
  1002. tcb.emit_tai(Tai_const.Create_sym(
  1003. ctai_typedconstbuilder.get_vectorized_dead_strip_section_symbol_end('RESSTR',hp.localsymtable,false)),
  1004. voidpointertype
  1005. );
  1006. inc(count);
  1007. end;
  1008. hp:=tmodule(hp.next);
  1009. end;
  1010. { Insert TableCount at start }
  1011. countplaceholder.replace(Tai_const.Create_pint(count),ptruinttype);
  1012. countplaceholder.free;
  1013. { Add to data segment }
  1014. current_asmdata.AsmLists[al_globals].concatList(
  1015. tcb.get_final_asmlist(
  1016. current_asmdata.DefineAsmSymbol('FPC_RESOURCESTRINGTABLES',AB_GLOBAL,AT_DATA),
  1017. tcb.end_anonymous_record,sec_rodata,'FPC_RESOURCESTRINGTABLES',sizeof(pint)
  1018. )
  1019. );
  1020. tcb.free;
  1021. end;
  1022. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  1023. var
  1024. tcb: ttai_typedconstbuilder;
  1025. begin
  1026. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  1027. begin
  1028. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1029. if ResourcesUsed then
  1030. tcb.emit_tai(Tai_const.Createname('FPC_RESSYMBOL',0),voidpointertype)
  1031. else
  1032. { Nil pointer to resource information }
  1033. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  1034. current_asmdata.asmlists[al_globals].concatList(
  1035. tcb.get_final_asmlist(
  1036. current_asmdata.DefineAsmSymbol('FPC_RESLOCATION',AB_GLOBAL,AT_DATA),
  1037. voidpointertype,
  1038. sec_rodata,
  1039. 'FPC_RESLOCATION',
  1040. sizeof(puint)
  1041. )
  1042. );
  1043. tcb.free;
  1044. end;
  1045. end;
  1046. class procedure tnodeutils.InsertMemorySizes;
  1047. var
  1048. tcb: ttai_typedconstbuilder;
  1049. s: shortstring;
  1050. sym: tasmsymbol;
  1051. def: tdef;
  1052. begin
  1053. { Insert Ident of the compiler in the .fpc.version section }
  1054. tcb:=ctai_typedconstbuilder.create([tcalo_no_dead_strip]);
  1055. s:='FPC '+full_version_string+
  1056. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname;
  1057. def:=carraydef.getreusable(cansichartype,length(s));
  1058. tcb.maybe_begin_aggregate(def);
  1059. tcb.emit_tai(Tai_string.Create(s),def);
  1060. tcb.maybe_end_aggregate(def);
  1061. sym:=current_asmdata.DefineAsmSymbol('__fpc_ident',AB_LOCAL,AT_DATA);
  1062. current_asmdata.asmlists[al_globals].concatlist(
  1063. tcb.get_final_asmlist(sym,def,sec_fpc,'version',const_align(32))
  1064. );
  1065. tcb.free;
  1066. if not(tf_no_generic_stackcheck in target_info.flags) then
  1067. begin
  1068. { stacksize can be specified and is now simulated }
  1069. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1070. tcb.emit_tai(Tai_const.Create_pint(stacksize),ptruinttype);
  1071. sym:=current_asmdata.DefineAsmSymbol('__stklen',AB_GLOBAL,AT_DATA);
  1072. current_asmdata.asmlists[al_globals].concatlist(
  1073. tcb.get_final_asmlist(sym,ptruinttype,sec_data,'__stklen',sizeof(pint))
  1074. );
  1075. tcb.free;
  1076. end;
  1077. {$IFDEF POWERPC}
  1078. { AmigaOS4 "stack cookie" support }
  1079. if ( target_info.system = system_powerpc_amiga ) then
  1080. begin
  1081. { this symbol is needed to ignite powerpc amigaos' }
  1082. { stack allocation magic for us with the given stack size. }
  1083. { note: won't work for m68k amigaos or morphos. (KB) }
  1084. str(stacksize,s);
  1085. s:='$STACK: '+s+#0;
  1086. def:=carraydef.getreusable(cansichartype,length(s));
  1087. tcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
  1088. tcb.maybe_begin_aggregate(def);
  1089. tcb.emit_tai(Tai_string.Create(s),def);
  1090. tcb.maybe_end_aggregate(def);
  1091. sym:=current_asmdata.DefineAsmSymbol('__stack_cookie',AB_GLOBAL,AT_DATA);
  1092. current_asmdata.asmlists[al_globals].concatlist(
  1093. tcb.get_final_asmlist(sym,def,sec_data,'__stack_cookie',sizeof(pint))
  1094. );
  1095. tcb.free;
  1096. end;
  1097. {$ENDIF POWERPC}
  1098. { Initial heapsize }
  1099. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1100. tcb.emit_tai(Tai_const.Create_pint(heapsize),ptruinttype);
  1101. sym:=current_asmdata.DefineAsmSymbol('__heapsize',AB_GLOBAL,AT_DATA);
  1102. current_asmdata.asmlists[al_globals].concatlist(
  1103. tcb.get_final_asmlist(sym,ptruinttype,sec_data,'__heapsize',sizeof(pint))
  1104. );
  1105. tcb.free;
  1106. { allocate an initial heap on embedded systems }
  1107. if target_info.system in systems_embedded then
  1108. begin
  1109. { tai_datablock cannot yet be handled via the high level typed const
  1110. builder, because it implies the generation of a symbol, while this
  1111. is separate in the builder }
  1112. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1113. new_section(current_asmdata.asmlists[al_globals],sec_bss,'__fpc_initialheap',current_settings.alignment.varalignmax);
  1114. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_initialheap',heapsize));
  1115. end;
  1116. { Valgrind usage }
  1117. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1118. tcb.emit_ord_const(byte(cs_gdb_valgrind in current_settings.globalswitches),u8inttype);
  1119. sym:=current_asmdata.DefineAsmSymbol('__fpc_valgrind',AB_GLOBAL,AT_DATA);
  1120. current_asmdata.asmlists[al_globals].concatlist(
  1121. tcb.get_final_asmlist(sym,ptruinttype,sec_data,'__fpc_valgrind',sizeof(pint))
  1122. );
  1123. tcb.free;
  1124. end;
  1125. class procedure tnodeutils.InsertObjectInfo;
  1126. begin
  1127. { don't do anything by default }
  1128. end;
  1129. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  1130. var
  1131. pvs: tparavarsym;
  1132. begin
  1133. { stub for calling FPC_SYSTEMMAIN from the C main -> add argc/argv/argp }
  1134. if (tprocdef(pd).proctypeoption=potype_mainstub) and
  1135. (target_info.system in (systems_darwin+[system_powerpc_macos]+systems_aix)) then
  1136. begin
  1137. pvs:=cparavarsym.create('ARGC',1,vs_const,s32inttype,[]);
  1138. tprocdef(pd).parast.insert(pvs);
  1139. pvs:=cparavarsym.create('ARGV',2,vs_const,cpointerdef.getreusable(charpointertype),[]);
  1140. tprocdef(pd).parast.insert(pvs);
  1141. pvs:=cparavarsym.create('ARGP',3,vs_const,cpointerdef.getreusable(charpointertype),[]);
  1142. tprocdef(pd).parast.insert(pvs);
  1143. tprocdef(pd).calcparas;
  1144. end;
  1145. end;
  1146. end.