n386obj.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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,symtype,symdef,symsym,
  27. fmodule,
  28. nobj,
  29. cpubase,
  30. cga,tgobj,rgobj,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 popstack register saveregisters
  39. default(0): OK OK OK(1) OK OK(1) OK OK
  40. virtual(2): OK OK OK(3) OK OK(3) 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 eax to reach the method address so the following code be generated:
  60. set self to correct value
  61. push %ebx ; allocate space for function address
  62. push %eax
  63. mov self,%eax
  64. mov 0(%eax),%eax ; load vmt
  65. mov vmtoffs(%eax),eax ; method offs
  66. mov %eax,4(%esp)
  67. pop %eax
  68. ret 0; jmp the address
  69. }
  70. function getselfoffsetfromsp(procdef: tprocdef): longint;
  71. begin
  72. if not assigned(procdef.parast.symindex.first) then
  73. getselfoffsetfromsp:=4
  74. else
  75. if tsym(procdef.parast.symindex.first).typ=varsym then
  76. getselfoffsetfromsp:=tvarsym(procdef.parast.symindex.first).address+4
  77. else
  78. Internalerror(2000061310);
  79. end;
  80. procedure ti386classheader.cgintfwrapper(asmlist: TAAsmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  81. procedure checkvirtual;
  82. begin
  83. if (procdef.extnumber=-1) then
  84. Internalerror(200006139);
  85. end;
  86. procedure getselftoeax(offs: longint);
  87. var
  88. href : treference;
  89. r:Tregister;
  90. begin
  91. { mov offset(%esp),%eax }
  92. r.enum:=R_INTREGISTER;
  93. r.number:=NR_ESP;
  94. reference_reset_base(href,r,getselfoffsetfromsp(procdef));
  95. r.number:=NR_EAX;
  96. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,r);
  97. end;
  98. procedure loadvmttoeax;
  99. var
  100. href : treference;
  101. r:Tregister;
  102. begin
  103. checkvirtual;
  104. { mov 0(%eax),%eax ; load vmt}
  105. r.enum:=R_INTREGISTER;
  106. r.number:=NR_EAX;
  107. reference_reset_base(href,r,0);
  108. emit_ref_reg(A_MOV,S_L,href,r);
  109. end;
  110. procedure op_oneaxmethodaddr(op: TAsmOp);
  111. var
  112. href : treference;
  113. r:Tregister;
  114. begin
  115. { call/jmp vmtoffs(%eax) ; method offs }
  116. r.enum:=R_INTREGISTER;
  117. r.number:=NR_EAX;
  118. reference_reset_base(href,r,procdef._class.vmtmethodoffset(procdef.extnumber));
  119. emit_ref(op,S_L,href);
  120. end;
  121. procedure loadmethodoffstoeax;
  122. var
  123. href : treference;
  124. r:Tregister;
  125. begin
  126. { mov vmtoffs(%eax),%eax ; method offs }
  127. r.enum:=R_INTREGISTER;
  128. r.number:=NR_EAX;
  129. reference_reset_base(href,r,procdef._class.vmtmethodoffset(procdef.extnumber));
  130. emit_ref_reg(A_MOV,S_L,href,r);
  131. end;
  132. var
  133. oldexprasmlist: TAAsmoutput;
  134. lab : tasmsymbol;
  135. make_global : boolean;
  136. href : treference;
  137. r:Tregister;
  138. begin
  139. if procdef.proctypeoption<>potype_none then
  140. Internalerror(200006137);
  141. if not assigned(procdef._class) or
  142. (procdef.procoptions*[po_classmethod, po_staticmethod,
  143. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  144. Internalerror(200006138);
  145. if procdef.owner.symtabletype<>objectsymtable then
  146. Internalerror(200109191);
  147. oldexprasmlist:=exprasmlist;
  148. exprasmlist:=asmlist;
  149. make_global:=false;
  150. if (not current_module.is_unit) or
  151. (cs_create_smart in aktmoduleswitches) or
  152. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  153. make_global:=true;
  154. if make_global then
  155. exprasmList.concat(Tai_symbol.Createname_global(labelname,0))
  156. else
  157. exprasmList.concat(Tai_symbol.Createname(labelname,0));
  158. { set param1 interface to self }
  159. adjustselfvalue(procdef,ioffset);
  160. { case 1 or 2 }
  161. if (po_clearstack in procdef.procoptions) then
  162. begin
  163. if po_virtualmethod in procdef.procoptions then
  164. begin { case 2 }
  165. getselftoeax(0);
  166. loadvmttoeax;
  167. op_oneaxmethodaddr(A_CALL);
  168. end
  169. else { case 1 }
  170. cg.a_call_name(exprasmlist,procdef.mangledname);
  171. { restore param1 value self to interface }
  172. adjustselfvalue(procdef,-ioffset);
  173. end
  174. { case 3 }
  175. else if [po_virtualmethod,po_saveregisters]*procdef.procoptions=[po_virtualmethod,po_saveregisters] then
  176. begin
  177. r.enum:=R_INTREGISTER;
  178. r.number:=NR_EBX;
  179. emit_reg(A_PUSH,S_L,r); { allocate space for address}
  180. r.number:=NR_EAX;
  181. emit_reg(A_PUSH,S_L,r);
  182. getselftoeax(8);
  183. loadvmttoeax;
  184. loadmethodoffstoeax;
  185. { mov %eax,4(%esp) }
  186. r.number:=NR_ESP;
  187. reference_reset_base(href,r,4);
  188. r.number:=NR_EAX;
  189. emit_reg_ref(A_MOV,S_L,r,href);
  190. { pop %eax }
  191. emit_reg(A_POP,S_L,r);
  192. { ret ; jump to the address }
  193. emit_none(A_RET,S_L);
  194. end
  195. { case 4 }
  196. else if po_virtualmethod in procdef.procoptions then
  197. begin
  198. getselftoeax(0);
  199. loadvmttoeax;
  200. op_oneaxmethodaddr(A_JMP);
  201. end
  202. { case 0 }
  203. else
  204. begin
  205. lab:=objectlibrary.newasmsymbol(procdef.mangledname);
  206. emit_sym(A_JMP,S_NO,lab);
  207. end;
  208. exprasmlist:=oldexprasmlist;
  209. end;
  210. initialization
  211. cclassheader:=ti386classheader;
  212. end.
  213. {
  214. $Log$
  215. Revision 1.19 2003-05-15 18:58:54 peter
  216. * removed selfpointer_offset, vmtpointer_offset
  217. * tvarsym.adjusted_address
  218. * address in localsymtable is now in the real direction
  219. * removed some obsolete globals
  220. Revision 1.18 2003/04/22 14:33:38 peter
  221. * removed some notes/hints
  222. Revision 1.17 2003/01/13 14:54:34 daniel
  223. * Further work to convert codegenerator register convention;
  224. internalerror bug fixed.
  225. Revision 1.16 2003/01/08 18:43:57 daniel
  226. * Tregister changed into a record
  227. Revision 1.15 2002/08/11 14:32:30 peter
  228. * renamed current_library to objectlibrary
  229. Revision 1.14 2002/08/11 13:24:17 peter
  230. * saving of asmsymbols in ppu supported
  231. * asmsymbollist global is removed and moved into a new class
  232. tasmlibrarydata that will hold the info of a .a file which
  233. corresponds with a single module. Added librarydata to tmodule
  234. to keep the library info stored for the module. In the future the
  235. objectfiles will also be stored to the tasmlibrarydata class
  236. * all getlabel/newasmsymbol and friends are moved to the new class
  237. Revision 1.13 2002/08/09 07:33:04 florian
  238. * a couple of interface related fixes
  239. Revision 1.12 2002/07/16 15:34:21 florian
  240. * exit is now a syssym instead of a keyword
  241. Revision 1.11 2002/07/01 18:46:33 peter
  242. * internal linker
  243. * reorganized aasm layer
  244. Revision 1.10 2002/05/18 13:34:25 peter
  245. * readded missing revisions
  246. Revision 1.9 2002/05/16 19:46:52 carl
  247. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  248. + try to fix temp allocation (still in ifdef)
  249. + generic constructor calls
  250. + start of tassembler / tmodulebase class cleanup
  251. Revision 1.7 2002/05/12 16:53:17 peter
  252. * moved entry and exitcode to ncgutil and cgobj
  253. * foreach gets extra argument for passing local data to the
  254. iterator function
  255. * -CR checks also class typecasts at runtime by changing them
  256. into as
  257. * fixed compiler to cycle with the -CR option
  258. * fixed stabs with elf writer, finally the global variables can
  259. be watched
  260. * removed a lot of routines from cga unit and replaced them by
  261. calls to cgobj
  262. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  263. u32bit then the other is typecasted also to u32bit without giving
  264. a rangecheck warning/error.
  265. * fixed pascal calling method with reversing also the high tree in
  266. the parast, detected by tcalcst3 test
  267. Revision 1.6 2002/04/02 17:11:36 peter
  268. * tlocation,treference update
  269. * LOC_CONSTANT added for better constant handling
  270. * secondadd splitted in multiple routines
  271. * location_force_reg added for loading a location to a register
  272. of a specified size
  273. * secondassignment parses now first the right and then the left node
  274. (this is compatible with Kylix). This saves a lot of push/pop especially
  275. with string operations
  276. * adapted some routines to use the new cg methods
  277. Revision 1.5 2002/03/31 20:26:39 jonas
  278. + a_loadfpu_* and a_loadmm_* methods in tcg
  279. * register allocation is now handled by a class and is mostly processor
  280. independent (+rgobj.pas and i386/rgcpu.pas)
  281. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  282. * some small improvements and fixes to the optimizer
  283. * some register allocation fixes
  284. * some fpuvaroffset fixes in the unary minus node
  285. * push/popusedregisters is now called rg.save/restoreusedregisters and
  286. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  287. also better optimizable)
  288. * fixed and optimized register saving/restoring for new/dispose nodes
  289. * LOC_FPU locations now also require their "register" field to be set to
  290. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  291. - list field removed of the tnode class because it's not used currently
  292. and can cause hard-to-find bugs
  293. }