ngenutil.pas 39 KB

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