n386cal.pas 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate i386 assembler for in call nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit n386cal;
  18. {$i fpcdefs.inc}
  19. interface
  20. { $define AnsiStrRef}
  21. uses
  22. nx86cal,ncal;
  23. type
  24. ti386callnode = class(tx86callnode)
  25. protected
  26. procedure gen_syscall_para(para: tcallparanode); override;
  27. procedure pop_parasize(pop_size:longint);override;
  28. procedure extra_interrupt_code;override;
  29. public
  30. procedure do_syscall;override;
  31. end;
  32. implementation
  33. uses
  34. globtype,systems,
  35. cutils,verbose,globals,
  36. cgbase,cgutils,
  37. cpubase,paramgr,
  38. aasmtai,aasmdata,aasmcpu,
  39. nbas,nmem,nld,ncnv,
  40. parabase,
  41. symdef,symsym,symcpu,symconst,
  42. cga,cgobj,cpuinfo;
  43. {*****************************************************************************
  44. TI386CALLNODE
  45. *****************************************************************************}
  46. procedure ti386callnode.do_syscall;
  47. var
  48. tmpref: treference;
  49. libparaloc: pcgparalocation;
  50. begin
  51. case target_info.system of
  52. system_i386_aros:
  53. begin
  54. if (po_syscall_baselast in tprocdef(procdefinition).procoptions) then
  55. begin
  56. current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('AROS SysCall - BaseLast on Stack')));
  57. { re-read the libbase pushed first on the stack, instead of just trusting the
  58. mangledname will work. this is important for example for threadvar libbases.
  59. and this way they also don't need to be resolved twice then. (KB) }
  60. libparaloc:=paralocs[procdefinition.paras.count-1]^.location;
  61. if libparaloc^.loc <> LOC_REFERENCE then
  62. internalerror(2016090203);
  63. reference_reset_base(tmpref,libparaloc^.reference.index,libparaloc^.reference.offset,sizeof(pint),[]);
  64. cg.getcpuregister(current_asmdata.CurrAsmList,NR_EAX);
  65. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpref,NR_EAX);
  66. reference_reset_base(tmpref,NR_EAX,-tprocdef(procdefinition).extnumber,sizeof(pint),[]);
  67. current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_CALL,S_NO,tmpref));
  68. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
  69. exit;
  70. end;
  71. if (po_syscall_basereg in tprocdef(procdefinition).procoptions) then
  72. begin
  73. current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('AROS SysCall - RegBase in EAX')));
  74. { libbase must be in EAX already, so just piggyback that, and dereference it }
  75. reference_reset_base(tmpref,NR_EAX,-tprocdef(procdefinition).extnumber,sizeof(pint),[]);
  76. current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_CALL,S_NO,tmpref));
  77. exit;
  78. end;
  79. internalerror(2016090104);
  80. end;
  81. else
  82. internalerror(2014081801);
  83. end;
  84. end;
  85. procedure ti386callnode.gen_syscall_para(para: tcallparanode);
  86. begin
  87. { lib parameter has no special type but proccalloptions must be a syscall }
  88. para.left:=cloadnode.create(tcpuprocdef(procdefinition).libsym,tcpuprocdef(procdefinition).libsym.owner);
  89. end;
  90. procedure ti386callnode.extra_interrupt_code;
  91. begin
  92. if not(target_info.system in [system_i386_darwin,system_i386_iphonesim,system_i386_android]) then
  93. begin
  94. emit_none(A_PUSHF,S_L);
  95. emit_reg(A_PUSH,S_L,NR_CS);
  96. end;
  97. end;
  98. procedure ti386callnode.pop_parasize(pop_size:longint);
  99. var
  100. hreg : tregister;
  101. begin
  102. if (paramanager.use_fixed_stack) then
  103. begin
  104. { very weird: in this case the callee does a "ret $4" and the }
  105. { caller immediately a "subl $4,%esp". Possibly this is for }
  106. { use_fixed_stack code to be able to transparently call }
  107. { old-style code (JM) }
  108. dec(pop_size,pushedparasize);
  109. if (pop_size < 0) then
  110. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_SUB,S_L,-pop_size,NR_ESP));
  111. exit;
  112. end;
  113. { on win32, the caller is responsible for removing the funcret }
  114. { pointer from the stack, unlike on Linux. Don't know about }
  115. { elsewhere (except Darwin, handled above), but since the default }
  116. { was "callee removes funcret pointer from stack" until now, we'll }
  117. { keep that default for everyone else (ncgcal decreases popsize by }
  118. { sizeof(aint) in case of ret_in_param()) }
  119. { This is only correct if the hidden funcret parameter
  120. is not passed as a register.
  121. As it is inserted in parast after all other hidden parameters,
  122. it is always the first parameter (apart from hidden parentfp,
  123. but this one is never put into a register (vs_nonregable set)
  124. so funcret is always in EAX for register calling }
  125. if ((target_info.system = system_i386_win32) and
  126. not (target_info.abi=abi_old_win32_gnu)) and
  127. paramanager.ret_in_param(procdefinition.returndef,procdefinition) and
  128. not ((procdefinition.proccalloption=pocall_register) or
  129. ((procdefinition.proccalloption=pocall_internproc) and
  130. (pocall_default=pocall_register))) then
  131. inc(pop_size,sizeof(aint));
  132. { better than an add on all processors }
  133. if pop_size=4 then
  134. begin
  135. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  136. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_POP,S_L,hreg));
  137. end
  138. { the pentium has two pipes and pop reg is pairable }
  139. { but the registers must be different! }
  140. else
  141. if (pop_size=8) and
  142. not(cs_opt_size in current_settings.optimizerswitches) and
  143. (current_settings.optimizecputype=cpu_Pentium) then
  144. begin
  145. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  146. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_POP,S_L,hreg));
  147. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  148. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_POP,S_L,hreg));
  149. end
  150. else
  151. if pop_size<>0 then
  152. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_ADD,S_L,pop_size,NR_ESP));
  153. end;
  154. begin
  155. ccallnode:=ti386callnode;
  156. end.