n386obj.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Kovacs Attila Zoltan
  4. Generate i386 assembly wrapper code interface implementor objects
  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 n386obj;
  19. {$i fpcdefs.inc}
  20. interface
  21. implementation
  22. uses
  23. systems,
  24. verbose,globals,globtype,
  25. aasmbase,aasmtai,
  26. symconst,symdef,
  27. fmodule,
  28. nobj,
  29. cpuinfo,cpubase,
  30. cga,cgutils,cgobj;
  31. type
  32. ti386classheader=class(tclassheader)
  33. protected
  34. procedure cgintfwrapper(asmlist: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  35. end;
  36. {
  37. possible calling conventions:
  38. default stdcall cdecl pascal register saveregisters
  39. default(0): OK OK OK(1) OK OK OK
  40. virtual(2): OK OK OK(3) OK OK OK(4)
  41. (0):
  42. set self parameter to correct value
  43. jmp mangledname
  44. (1): The code is the following
  45. set self parameter to correct value
  46. call mangledname
  47. set self parameter to interface value
  48. (2): The wrapper code use %eax to reach the virtual method address
  49. set self to correct value
  50. move self,%eax
  51. mov 0(%eax),%eax ; load vmt
  52. jmp vmtoffs(%eax) ; method offs
  53. (3): The wrapper code use %eax to reach the virtual method address
  54. set self to correct value
  55. move self,%eax
  56. mov 0(%eax),%eax ; load vmt
  57. jmp vmtoffs(%eax) ; method offs
  58. set self parameter to interface value
  59. (4): Virtual use values pushed on stack to reach the method address
  60. so the following code be generated:
  61. set self to correct value
  62. push %ebx ; allocate space for function address
  63. push %eax
  64. mov self,%eax
  65. mov 0(%eax),%eax ; load vmt
  66. mov vmtoffs(%eax),eax ; method offs
  67. mov %eax,4(%esp)
  68. pop %eax
  69. ret 0; jmp the address
  70. }
  71. function getselfoffsetfromsp(procdef: tprocdef): longint;
  72. begin
  73. { framepointer is pushed for nested procs }
  74. if procdef.parast.symtablelevel>normal_function_level then
  75. getselfoffsetfromsp:=2*POINTER_SIZE
  76. else
  77. getselfoffsetfromsp:=POINTER_SIZE;
  78. end;
  79. procedure ti386classheader.cgintfwrapper(asmlist: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  80. procedure getselftoeax(offs: longint);
  81. var
  82. href : treference;
  83. begin
  84. { mov offset(%esp),%eax }
  85. if (procdef.proccalloption<>pocall_register) then
  86. begin
  87. reference_reset_base(href,NR_ESP,getselfoffsetfromsp(procdef)+offs);
  88. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,NR_EAX);
  89. end;
  90. end;
  91. procedure loadvmttoeax;
  92. var
  93. href : treference;
  94. begin
  95. { mov 0(%eax),%eax ; load vmt}
  96. reference_reset_base(href,NR_EAX,0);
  97. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,NR_EAX);
  98. end;
  99. procedure op_oneaxmethodaddr(op: TAsmOp);
  100. var
  101. href : treference;
  102. begin
  103. if (procdef.extnumber=$ffff) then
  104. Internalerror(200006139);
  105. { call/jmp vmtoffs(%eax) ; method offs }
  106. reference_reset_base(href,NR_EAX,procdef._class.vmtmethodoffset(procdef.extnumber));
  107. emit_ref(op,S_L,href);
  108. end;
  109. procedure loadmethodoffstoeax;
  110. var
  111. href : treference;
  112. begin
  113. if (procdef.extnumber=$ffff) then
  114. Internalerror(200006139);
  115. { mov vmtoffs(%eax),%eax ; method offs }
  116. reference_reset_base(href,NR_EAX,procdef._class.vmtmethodoffset(procdef.extnumber));
  117. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,NR_EAX);
  118. end;
  119. var
  120. oldexprasmlist: TAAsmoutput;
  121. lab : tasmsymbol;
  122. make_global : boolean;
  123. href : treference;
  124. begin
  125. if procdef.proctypeoption<>potype_none then
  126. Internalerror(200006137);
  127. if not assigned(procdef._class) or
  128. (procdef.procoptions*[po_classmethod, po_staticmethod,
  129. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  130. Internalerror(200006138);
  131. if procdef.owner.symtabletype<>objectsymtable then
  132. Internalerror(200109191);
  133. oldexprasmlist:=exprasmlist;
  134. exprasmlist:=asmlist;
  135. make_global:=false;
  136. if (not current_module.is_unit) or
  137. (cs_create_smart in aktmoduleswitches) or
  138. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  139. make_global:=true;
  140. if make_global then
  141. exprasmList.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  142. else
  143. exprasmList.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  144. { set param1 interface to self }
  145. adjustselfvalue(procdef,ioffset);
  146. { case 1 or 2 }
  147. if (procdef.proccalloption in clearstack_pocalls) then
  148. begin
  149. if po_virtualmethod in procdef.procoptions then
  150. begin
  151. { case 2 }
  152. getselftoeax(0);
  153. loadvmttoeax;
  154. op_oneaxmethodaddr(A_CALL);
  155. end
  156. else
  157. begin
  158. { case 1 }
  159. cg.a_call_name(exprasmlist,procdef.mangledname);
  160. end;
  161. { restore param1 value self to interface }
  162. adjustselfvalue(procdef,-ioffset);
  163. end
  164. else if po_virtualmethod in procdef.procoptions then
  165. begin
  166. if (procdef.proccalloption=pocall_register) or
  167. (po_saveregisters in procdef.procoptions) then
  168. begin
  169. { case 4 }
  170. emit_reg(A_PUSH,S_L,NR_EBX); { allocate space for address}
  171. emit_reg(A_PUSH,S_L,NR_EAX);
  172. getselftoeax(8);
  173. loadvmttoeax;
  174. loadmethodoffstoeax;
  175. { mov %eax,4(%esp) }
  176. reference_reset_base(href,NR_ESP,4);
  177. emit_reg_ref(A_MOV,S_L,NR_EAX,href);
  178. { pop %eax }
  179. emit_reg(A_POP,S_L,NR_EAX);
  180. { ret ; jump to the address }
  181. emit_none(A_RET,S_L);
  182. end
  183. else
  184. begin
  185. { case 3 }
  186. getselftoeax(0);
  187. loadvmttoeax;
  188. op_oneaxmethodaddr(A_JMP);
  189. end;
  190. end
  191. { case 0 }
  192. else
  193. begin
  194. lab:=objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION);
  195. emit_sym(A_JMP,S_NO,lab);
  196. end;
  197. exprasmList.concat(Tai_symbol_end.Createname(labelname));
  198. exprasmlist:=oldexprasmlist;
  199. end;
  200. initialization
  201. cclassheader:=ti386classheader;
  202. end.
  203. {
  204. $Log$
  205. Revision 1.32 2004-03-02 00:36:33 olle
  206. * big transformation of Tai_[const_]Symbol.Create[data]name*
  207. Revision 1.31 2004/02/27 13:42:52 olle
  208. + added Tai_symbol_end
  209. Revision 1.30 2004/02/27 10:21:05 florian
  210. * top_symbol killed
  211. + refaddr to treference added
  212. + refsymbol to treference added
  213. * top_local stuff moved to an extra record to save memory
  214. + aint introduced
  215. * tppufile.get/putint64/aint implemented
  216. Revision 1.29 2003/12/23 23:12:44 peter
  217. * extnumber failure is $ffff instead of -1
  218. * fix non-vmt call for register calling on i386
  219. Revision 1.28 2003/12/17 21:59:59 peter
  220. * register call fix
  221. Revision 1.27 2003/10/10 17:48:14 peter
  222. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  223. * tregisteralloctor renamed to trgobj
  224. * removed rgobj from a lot of units
  225. * moved location_* and reference_* to cgobj
  226. * first things for mmx register allocation
  227. Revision 1.26 2003/10/01 20:34:49 peter
  228. * procinfo unit contains tprocinfo
  229. * cginfo renamed to cgbase
  230. * moved cgmessage to verbose
  231. * fixed ppc and sparc compiles
  232. Revision 1.25 2003/09/25 21:30:11 peter
  233. * parameter fixes
  234. Revision 1.24 2003/09/25 14:59:06 peter
  235. * fix intf wrapper code
  236. Revision 1.23 2003/09/23 17:56:06 peter
  237. * locals and paras are allocated in the code generation
  238. * tvarsym.localloc contains the location of para/local when
  239. generating code for the current procedure
  240. Revision 1.22 2003/09/07 22:09:35 peter
  241. * preparations for different default calling conventions
  242. * various RA fixes
  243. Revision 1.21 2003/09/03 15:55:01 peter
  244. * NEWRA branch merged
  245. Revision 1.20.2.1 2003/08/29 17:29:00 peter
  246. * next batch of updates
  247. Revision 1.20 2003/06/03 21:11:09 peter
  248. * cg.a_load_* get a from and to size specifier
  249. * makeregsize only accepts newregister
  250. * i386 uses generic tcgnotnode,tcgunaryminus
  251. Revision 1.19 2003/05/15 18:58:54 peter
  252. * removed selfpointer_offset, vmtpointer_offset
  253. * tvarsym.adjusted_address
  254. * address in localsymtable is now in the real direction
  255. * removed some obsolete globals
  256. Revision 1.18 2003/04/22 14:33:38 peter
  257. * removed some notes/hints
  258. Revision 1.17 2003/01/13 14:54:34 daniel
  259. * Further work to convert codegenerator register convention;
  260. internalerror bug fixed.
  261. Revision 1.16 2003/01/08 18:43:57 daniel
  262. * Tregister changed into a record
  263. Revision 1.15 2002/08/11 14:32:30 peter
  264. * renamed current_library to objectlibrary
  265. Revision 1.14 2002/08/11 13:24:17 peter
  266. * saving of asmsymbols in ppu supported
  267. * asmsymbollist global is removed and moved into a new class
  268. tasmlibrarydata that will hold the info of a .a file which
  269. corresponds with a single module. Added librarydata to tmodule
  270. to keep the library info stored for the module. In the future the
  271. objectfiles will also be stored to the tasmlibrarydata class
  272. * all getlabel/newasmsymbol and friends are moved to the new class
  273. Revision 1.13 2002/08/09 07:33:04 florian
  274. * a couple of interface related fixes
  275. Revision 1.12 2002/07/16 15:34:21 florian
  276. * exit is now a syssym instead of a keyword
  277. Revision 1.11 2002/07/01 18:46:33 peter
  278. * internal linker
  279. * reorganized aasm layer
  280. Revision 1.10 2002/05/18 13:34:25 peter
  281. * readded missing revisions
  282. Revision 1.9 2002/05/16 19:46:52 carl
  283. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  284. + try to fix temp allocation (still in ifdef)
  285. + generic constructor calls
  286. + start of tassembler / tmodulebase class cleanup
  287. Revision 1.7 2002/05/12 16:53:17 peter
  288. * moved entry and exitcode to ncgutil and cgobj
  289. * foreach gets extra argument for passing local data to the
  290. iterator function
  291. * -CR checks also class typecasts at runtime by changing them
  292. into as
  293. * fixed compiler to cycle with the -CR option
  294. * fixed stabs with elf writer, finally the global variables can
  295. be watched
  296. * removed a lot of routines from cga unit and replaced them by
  297. calls to cgobj
  298. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  299. u32bit then the other is typecasted also to u32bit without giving
  300. a rangecheck warning/error.
  301. * fixed pascal calling method with reversing also the high tree in
  302. the parast, detected by tcalcst3 test
  303. Revision 1.6 2002/04/02 17:11:36 peter
  304. * tlocation,treference update
  305. * LOC_CONSTANT added for better constant handling
  306. * secondadd splitted in multiple routines
  307. * location_force_reg added for loading a location to a register
  308. of a specified size
  309. * secondassignment parses now first the right and then the left node
  310. (this is compatible with Kylix). This saves a lot of push/pop especially
  311. with string operations
  312. * adapted some routines to use the new cg methods
  313. Revision 1.5 2002/03/31 20:26:39 jonas
  314. + a_loadfpu_* and a_loadmm_* methods in tcg
  315. * register allocation is now handled by a class and is mostly processor
  316. independent (+rgobj.pas and i386/rgcpu.pas)
  317. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  318. * some small improvements and fixes to the optimizer
  319. * some register allocation fixes
  320. * some fpuvaroffset fixes in the unary minus node
  321. * push/popusedregisters is now called rg.save/restoreusedregisters and
  322. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  323. also better optimizable)
  324. * fixed and optimized register saving/restoring for new/dispose nodes
  325. * LOC_FPU locations now also require their "register" field to be set to
  326. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  327. - list field removed of the tnode class because it's not used currently
  328. and can cause hard-to-find bugs
  329. }