ngenutil.pas 41 KB

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