ngenutil.pas 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  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 (vo_is_default_var in tabstractnormalvarsym(p).varoptions) and
  372. not is_managed_type(tabstractnormalvarsym(p).vardef) and
  373. not assigned(tabstractnormalvarsym(p).defaultconstsym);
  374. end;
  375. class procedure tnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  376. var
  377. size: asizeint;
  378. trashintval: int64;
  379. begin
  380. if trashable_sym(p) then
  381. begin
  382. trashintval:=trashintvalues[localvartrashing];
  383. if (p.vardef.typ=procvardef) and
  384. ([m_tp_procvar,m_mac_procvar]*current_settings.modeswitches<>[]) then
  385. begin
  386. if tprocvardef(p.vardef).is_addressonly then
  387. { in tp/delphi mode, you need @procvar to get at the contents of
  388. a procvar ... }
  389. trashn:=caddrnode.create(trashn)
  390. else
  391. { ... but if it's a procedure of object, that will only return
  392. the procedure address -> cast to tmethod instead }
  393. trashn:=ctypeconvnode.create_explicit(trashn,methodpointertype);
  394. end;
  395. if ((p.typ=localvarsym) and
  396. (not(vo_is_funcret in p.varoptions) or
  397. not is_shortstring(p.vardef))) or
  398. ((p.typ=paravarsym) and
  399. not is_shortstring(p.vardef)) then
  400. begin
  401. size:=p.getsize;
  402. case size of
  403. 0:
  404. begin
  405. { open array -> at least size 1. Can also be zero-sized
  406. record, so check it's actually an array }
  407. if p.vardef.typ=arraydef then
  408. trash_large(stat,trashn,caddnode.create(addn,cinlinenode.create(in_high_x,false,trashn.getcopy),genintconstnode(1)),trashintval)
  409. else
  410. trashn.free;
  411. end;
  412. 1: trash_small(stat,
  413. ctypeconvnode.create_internal(trashn,s8inttype),
  414. genintconstnode(shortint(trashintval)));
  415. 2: trash_small(stat,
  416. ctypeconvnode.create_internal(trashn,s16inttype),
  417. genintconstnode(smallint(trashintval)));
  418. 4: trash_small(stat,
  419. ctypeconvnode.create_internal(trashn,s32inttype),
  420. genintconstnode(longint(trashintval)));
  421. 8: trash_small(stat,
  422. ctypeconvnode.create_internal(trashn,s64inttype),
  423. genintconstnode(int64(trashintval)));
  424. else
  425. trash_large(stat,trashn,genintconstnode(size),trashintval);
  426. end;
  427. end
  428. else
  429. begin
  430. { may be an open string, even if is_open_string() returns false
  431. (for some helpers in the system unit) }
  432. { an open string has at least size 2 }
  433. trash_small(stat,
  434. cvecnode.create(trashn.getcopy,genintconstnode(0)),
  435. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  436. trash_small(stat,
  437. cvecnode.create(trashn,genintconstnode(1)),
  438. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  439. end;
  440. end
  441. else
  442. trashn.free;
  443. end;
  444. class procedure tnodeutils.maybe_trash_variable_callback(p:TObject;statn:pointer);
  445. var
  446. stat: ^tstatementnode absolute statn;
  447. begin
  448. if not(tsym(p).typ in [localvarsym,paravarsym]) then
  449. exit;
  450. maybe_trash_variable(stat^,tabstractnormalvarsym(p),cloadnode.create(tsym(p),tsym(p).owner));
  451. end;
  452. class procedure tnodeutils.trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode);
  453. begin
  454. addstatement(stat,cassignmentnode.create(trashn,trashvaln));
  455. end;
  456. class procedure tnodeutils.trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64);
  457. begin
  458. addstatement(stat,ccallnode.createintern('fpc_fillmem',
  459. ccallparanode.Create(cordconstnode.create(tconstexprint(byte(trashintval)),u8inttype,false),
  460. ccallparanode.Create(sizen,
  461. ccallparanode.Create(trashn,nil)))
  462. ));
  463. end;
  464. class procedure tnodeutils.insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint);
  465. begin
  466. if sym.globalasmsym then
  467. begin
  468. { on AIX/stabx, we cannot generate debug information that encodes
  469. the address of a global symbol, you need a symbol with the same
  470. name as the identifier -> create an extra *local* symbol.
  471. Moreover, such a local symbol will be removed if it's not
  472. referenced anywhere, so also create a reference }
  473. if (target_dbg.id=dbg_stabx) and
  474. (cs_debuginfo in current_settings.moduleswitches) and
  475. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  476. begin
  477. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA),0));
  478. list.concat(tai_directive.Create(asd_reference,sym.name));
  479. end;
  480. list.concat(Tai_datablock.create_global(sym.mangledname,size));
  481. end
  482. else
  483. list.concat(Tai_datablock.create(sym.mangledname,size));
  484. end;
  485. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  486. var
  487. l : asizeint;
  488. varalign : shortint;
  489. storefilepos : tfileposinfo;
  490. list : TAsmList;
  491. sectype : TAsmSectiontype;
  492. begin
  493. storefilepos:=current_filepos;
  494. current_filepos:=sym.fileinfo;
  495. l:=sym.getsize;
  496. varalign:=sym.vardef.alignment;
  497. if (varalign=0) then
  498. varalign:=var_align_size(l)
  499. else
  500. varalign:=var_align(varalign);
  501. if tf_section_threadvars in target_info.flags then
  502. begin
  503. if (vo_is_thread_var in sym.varoptions) then
  504. begin
  505. list:=current_asmdata.asmlists[al_threadvars];
  506. sectype:=sec_threadvar;
  507. end
  508. else
  509. begin
  510. list:=current_asmdata.asmlists[al_globals];
  511. sectype:=sec_bss;
  512. end;
  513. end
  514. else
  515. begin
  516. if (vo_is_thread_var in sym.varoptions) then
  517. begin
  518. inc(l,sizeof(pint));
  519. { it doesn't help to set a higher alignment, as }
  520. { the first sizeof(pint) bytes field will offset }
  521. { everything anyway }
  522. varalign:=sizeof(pint);
  523. end;
  524. list:=current_asmdata.asmlists[al_globals];
  525. sectype:=sec_bss;
  526. end;
  527. maybe_new_object_file(list);
  528. if vo_has_section in sym.varoptions then
  529. new_section(list,sec_user,sym.section,varalign)
  530. else
  531. new_section(list,sectype,lower(sym.mangledname),varalign);
  532. insertbsssym(list,sym,l);
  533. current_filepos:=storefilepos;
  534. end;
  535. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  536. var
  537. pd: tprocdef;
  538. begin
  539. pd:=cprocdef.create(main_program_level);
  540. pd.procsym:=ps;
  541. ps.ProcdefList.Add(pd);
  542. include(pd.procoptions,po_global);
  543. { set procdef options }
  544. pd.proctypeoption:=potype;
  545. pd.proccalloption:=pocall_default;
  546. include(pd.procoptions,po_hascallingconvention);
  547. pd.forwarddef:=false;
  548. { may be required to calculate the mangled name }
  549. add_main_procdef_paras(pd);
  550. pd.setmangledname(name);
  551. pd.aliasnames.insert(pd.mangledname);
  552. result:=pd;
  553. end;
  554. procedure AddToStructInits(p:TObject;arg:pointer);
  555. var
  556. StructList: TFPList absolute arg;
  557. begin
  558. if (tdef(p).typ in [objectdef,recorddef]) and
  559. not (df_generic in tdef(p).defoptions) and
  560. ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  561. StructList.Add(p);
  562. end;
  563. class procedure tnodeutils.InsertInitFinalTable;
  564. var
  565. hp : tused_unit;
  566. unitinits : TAsmList;
  567. count : longint;
  568. procedure write_struct_inits(u: tmodule);
  569. var
  570. i: integer;
  571. structlist: TFPList;
  572. pd: tprocdef;
  573. begin
  574. structlist := TFPList.Create;
  575. if assigned(u.globalsymtable) then
  576. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  577. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  578. { write structures }
  579. for i := 0 to structlist.Count - 1 do
  580. begin
  581. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  582. if assigned(pd) then
  583. unitinits.concat(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0))
  584. else
  585. unitinits.concat(Tai_const.Create_nil_codeptr);
  586. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  587. if assigned(pd) then
  588. unitinits.concat(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0))
  589. else
  590. unitinits.concat(Tai_const.Create_nil_codeptr);
  591. inc(count);
  592. end;
  593. structlist.free;
  594. end;
  595. begin
  596. unitinits:=TAsmList.Create;
  597. count:=0;
  598. hp:=tused_unit(usedunits.first);
  599. while assigned(hp) do
  600. begin
  601. { insert class constructors/destructors of the unit }
  602. if (hp.u.flags and uf_classinits) <> 0 then
  603. write_struct_inits(hp.u);
  604. { call the unit init code and make it external }
  605. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  606. begin
  607. if (hp.u.flags and uf_init)<>0 then
  608. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),AT_FUNCTION,0))
  609. else
  610. unitinits.concat(Tai_const.Create_nil_codeptr);
  611. if (hp.u.flags and uf_finalize)<>0 then
  612. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),AT_FUNCTION,0))
  613. else
  614. unitinits.concat(Tai_const.Create_nil_codeptr);
  615. inc(count);
  616. end;
  617. hp:=tused_unit(hp.next);
  618. end;
  619. { insert class constructors/destructor of the program }
  620. if (current_module.flags and uf_classinits) <> 0 then
  621. write_struct_inits(current_module);
  622. { Insert initialization/finalization of the program }
  623. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  624. begin
  625. if (current_module.flags and uf_init)<>0 then
  626. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),AT_FUNCTION,0))
  627. else
  628. unitinits.concat(Tai_const.Create_nil_codeptr);
  629. if (current_module.flags and uf_finalize)<>0 then
  630. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),AT_FUNCTION,0))
  631. else
  632. unitinits.concat(Tai_const.Create_nil_codeptr);
  633. inc(count);
  634. end;
  635. { Insert TableCount,InitCount at start }
  636. unitinits.insert(Tai_const.Create_pint(0));
  637. unitinits.insert(Tai_const.Create_pint(count));
  638. { Add to data segment }
  639. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  640. new_section(current_asmdata.asmlists[al_globals],sec_data,'INITFINAL',sizeof(pint));
  641. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITFINAL',AT_DATA,0));
  642. current_asmdata.asmlists[al_globals].concatlist(unitinits);
  643. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITFINAL'));
  644. unitinits.free;
  645. end;
  646. class procedure tnodeutils.InsertThreadvarTablesTable;
  647. var
  648. hp : tused_unit;
  649. ltvTables : TAsmList;
  650. count : longint;
  651. begin
  652. if (tf_section_threadvars in target_info.flags) then
  653. exit;
  654. ltvTables:=TAsmList.Create;
  655. count:=0;
  656. hp:=tused_unit(usedunits.first);
  657. while assigned(hp) do
  658. begin
  659. If (hp.u.flags and uf_threadvars)=uf_threadvars then
  660. begin
  661. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0));
  662. inc(count);
  663. end;
  664. hp:=tused_unit(hp.next);
  665. end;
  666. { Add program threadvars, if any }
  667. If (current_module.flags and uf_threadvars)=uf_threadvars then
  668. begin
  669. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0));
  670. inc(count);
  671. end;
  672. { Insert TableCount at start }
  673. ltvTables.insert(Tai_const.Create_32bit(count));
  674. { insert in data segment }
  675. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  676. new_section(current_asmdata.asmlists[al_globals],sec_data,'FPC_THREADVARTABLES',sizeof(pint));
  677. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('FPC_THREADVARTABLES',AT_DATA,0));
  678. current_asmdata.asmlists[al_globals].concatlist(ltvTables);
  679. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('FPC_THREADVARTABLES'));
  680. ltvTables.free;
  681. end;
  682. procedure AddToThreadvarList(p:TObject;arg:pointer);
  683. var
  684. ltvTable : TAsmList;
  685. begin
  686. ltvTable:=TAsmList(arg);
  687. if (tsym(p).typ=staticvarsym) and
  688. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  689. begin
  690. { address of threadvar }
  691. ltvTable.concat(tai_const.Createname(tstaticvarsym(p).mangledname,0));
  692. { size of threadvar }
  693. ltvTable.concat(tai_const.create_32bit(tstaticvarsym(p).getsize));
  694. end;
  695. end;
  696. class procedure tnodeutils.InsertThreadvars;
  697. var
  698. s : string;
  699. ltvTable : TAsmList;
  700. begin
  701. if (tf_section_threadvars in target_info.flags) then
  702. exit;
  703. ltvTable:=TAsmList.create;
  704. if assigned(current_module.globalsymtable) then
  705. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  706. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  707. if not ltvTable.Empty then
  708. begin
  709. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  710. { end of the list marker }
  711. ltvTable.concat(tai_const.create_sym(nil));
  712. { add to datasegment }
  713. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  714. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  715. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  716. current_asmdata.asmlists[al_globals].concatlist(ltvTable);
  717. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  718. current_module.flags:=current_module.flags or uf_threadvars;
  719. end;
  720. ltvTable.Free;
  721. end;
  722. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  723. var
  724. hp: tused_unit;
  725. hlist: TAsmList;
  726. count: longint;
  727. begin
  728. hlist:=TAsmList.Create;
  729. count:=0;
  730. hp:=tused_unit(usedunits.first);
  731. while assigned(hp) do
  732. begin
  733. if (hp.u.flags and unitflag)=unitflag then
  734. begin
  735. hlist.concat(Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0));
  736. inc(count);
  737. end;
  738. hp:=tused_unit(hp.next);
  739. end;
  740. { Add items from program, if any }
  741. if (current_module.flags and unitflag)=unitflag then
  742. begin
  743. hlist.concat(Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0));
  744. inc(count);
  745. end;
  746. { Insert TableCount at start }
  747. hlist.insert(Tai_const.Create_pint(count));
  748. { insert in data segment }
  749. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  750. new_section(current_asmdata.asmlists[al_globals],sec_data,tablename,sizeof(pint));
  751. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(tablename,AT_DATA,0));
  752. current_asmdata.asmlists[al_globals].concatlist(hlist);
  753. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(tablename));
  754. hlist.free;
  755. end;
  756. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  757. var
  758. s: string;
  759. item: TTCInitItem;
  760. begin
  761. item:=TTCInitItem(list.First);
  762. if item=nil then
  763. exit;
  764. s:=make_mangledname(prefix,current_module.localsymtable,'');
  765. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  766. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  767. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  768. repeat
  769. { optimize away unused local/static symbols }
  770. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  771. begin
  772. { address to initialize }
  773. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  774. { value with which to initialize }
  775. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  776. end;
  777. item:=TTCInitItem(item.Next);
  778. until item=nil;
  779. { end-of-list marker }
  780. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  781. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  782. current_module.flags:=current_module.flags or unitflag;
  783. end;
  784. class procedure tnodeutils.InsertWideInits;
  785. begin
  786. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  787. end;
  788. class procedure tnodeutils.InsertResStrInits;
  789. begin
  790. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  791. end;
  792. class procedure tnodeutils.InsertWideInitsTablesTable;
  793. begin
  794. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  795. end;
  796. class procedure tnodeutils.InsertResStrTablesTable;
  797. begin
  798. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  799. end;
  800. class procedure tnodeutils.InsertResourceTablesTable;
  801. var
  802. hp : tmodule;
  803. ResourceStringTables : tasmlist;
  804. count : longint;
  805. begin
  806. ResourceStringTables:=tasmlist.Create;
  807. count:=0;
  808. hp:=tmodule(loaded_units.first);
  809. while assigned(hp) do
  810. begin
  811. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  812. begin
  813. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),AT_DATA,0));
  814. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),AT_DATA,0));
  815. inc(count);
  816. end;
  817. hp:=tmodule(hp.next);
  818. end;
  819. { Insert TableCount at start }
  820. ResourceStringTables.insert(Tai_const.Create_pint(count));
  821. { Add to data segment }
  822. maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
  823. new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',sizeof(pint));
  824. current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
  825. current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
  826. current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
  827. ResourceStringTables.free;
  828. end;
  829. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  830. var
  831. ResourceInfo : TAsmList;
  832. begin
  833. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  834. begin
  835. ResourceInfo:=TAsmList.Create;
  836. maybe_new_object_file(ResourceInfo);
  837. new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
  838. ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
  839. if ResourcesUsed then
  840. { Valid pointer to resource information }
  841. ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
  842. else
  843. { Nil pointer to resource information }
  844. {$IFNDEF cpu64bitaddr}
  845. ResourceInfo.Concat(Tai_const.Create_32bit(0));
  846. {$ELSE}
  847. ResourceInfo.Concat(Tai_const.Create_64bit(0));
  848. {$ENDIF}
  849. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  850. current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
  851. ResourceInfo.free;
  852. end;
  853. end;
  854. class procedure tnodeutils.InsertMemorySizes;
  855. {$IFDEF POWERPC}
  856. var
  857. stkcookie: string;
  858. {$ENDIF POWERPC}
  859. begin
  860. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  861. { Insert Ident of the compiler in the .fpc.version section }
  862. new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
  863. current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
  864. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
  865. if not(tf_no_generic_stackcheck in target_info.flags) then
  866. begin
  867. { stacksize can be specified and is now simulated }
  868. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
  869. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
  870. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
  871. end;
  872. {$IFDEF POWERPC}
  873. { AmigaOS4 "stack cookie" support }
  874. if ( target_info.system = system_powerpc_amiga ) then
  875. begin
  876. { this symbol is needed to ignite powerpc amigaos' }
  877. { stack allocation magic for us with the given stack size. }
  878. { note: won't work for m68k amigaos or morphos. (KB) }
  879. str(stacksize,stkcookie);
  880. stkcookie:='$STACK: '+stkcookie+#0;
  881. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  882. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
  883. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
  884. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
  885. end;
  886. {$ENDIF POWERPC}
  887. { Initial heapsize }
  888. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  889. new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',sizeof(pint));
  890. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
  891. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
  892. { allocate an initial heap on embedded systems }
  893. if target_info.system in systems_embedded then
  894. begin
  895. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  896. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_initialheap',current_settings.alignment.varalignmax);
  897. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_initialheap',heapsize));
  898. end;
  899. { Valgrind usage }
  900. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  901. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',sizeof(boolean));
  902. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
  903. current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
  904. end;
  905. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  906. begin
  907. { no parameters by default }
  908. end;
  909. end.