n386cal.pas 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. symdef,symsym,symcpu,
  41. cga,cgobj,cpuinfo;
  42. {*****************************************************************************
  43. TI386CALLNODE
  44. *****************************************************************************}
  45. procedure ti386callnode.do_syscall;
  46. var
  47. tmpref: treference;
  48. begin
  49. case target_info.system of
  50. system_i386_aros:
  51. begin
  52. // one syscall convention for AROS
  53. current_asmdata.CurrAsmList.concat(tai_comment.create(strpnew('AROS SysCall')));
  54. reference_reset(tmpref,sizeof(pint));
  55. { re-read the libbase pushed first on the stack, instead of just trusting the
  56. mangledname will work. this is important for example for threadvar libbases.
  57. and this way they also don't need to be resolved twice then. (KB) }
  58. tmpref.base:=NR_ESP;
  59. tmpref.offset:=pushedparasize-sizeof(pint);
  60. cg.getcpuregister(current_asmdata.CurrAsmList,NR_EAX);
  61. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpref,NR_EAX);
  62. reference_reset_base(tmpref,NR_EAX,-tprocdef(procdefinition).extnumber,sizeof(pint));
  63. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpref,NR_EAX);
  64. cg.a_call_reg(current_asmdata.CurrAsmList,NR_EAX);
  65. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
  66. end;
  67. else
  68. internalerror(2014081801);
  69. end;
  70. end;
  71. procedure ti386callnode.gen_syscall_para(para: tcallparanode);
  72. begin
  73. { lib parameter has no special type but proccalloptions must be a syscall }
  74. para.left:=cloadnode.create(tcpuprocdef(procdefinition).libsym,tcpuprocdef(procdefinition).libsym.owner);
  75. end;
  76. procedure ti386callnode.extra_interrupt_code;
  77. begin
  78. if not(target_info.system in [system_i386_darwin,system_i386_iphonesim,system_i386_android]) then
  79. begin
  80. emit_none(A_PUSHF,S_L);
  81. emit_reg(A_PUSH,S_L,NR_CS);
  82. end;
  83. end;
  84. procedure ti386callnode.pop_parasize(pop_size:longint);
  85. var
  86. hreg : tregister;
  87. begin
  88. if (paramanager.use_fixed_stack) then
  89. begin
  90. { very weird: in this case the callee does a "ret $4" and the }
  91. { caller immediately a "subl $4,%esp". Possibly this is for }
  92. { use_fixed_stack code to be able to transparently call }
  93. { old-style code (JM) }
  94. dec(pop_size,pushedparasize);
  95. if (pop_size < 0) then
  96. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_SUB,S_L,-pop_size,NR_ESP));
  97. exit;
  98. end;
  99. { on win32, the caller is responsible for removing the funcret }
  100. { pointer from the stack, unlike on Linux. Don't know about }
  101. { elsewhere (except Darwin, handled above), but since the default }
  102. { was "callee removes funcret pointer from stack" until now, we'll }
  103. { keep that default for everyone else (ncgcal decreases popsize by }
  104. { sizeof(aint) in case of ret_in_param()) }
  105. { This is only correct if the hidden funcret parameter
  106. is not passed as a register.
  107. As it is inserted in parast after all other hidden parameters,
  108. it is always the first parameter (apart from hidden parentfp,
  109. but this one is never put into a register (vs_nonregable set)
  110. so funcret is always in EAX for register calling }
  111. if ((target_info.system = system_i386_win32) and
  112. not (target_info.abi=abi_old_win32_gnu)) and
  113. paramanager.ret_in_param(procdefinition.returndef,procdefinition) and
  114. not ((procdefinition.proccalloption=pocall_register) or
  115. ((procdefinition.proccalloption=pocall_internproc) and
  116. (pocall_default=pocall_register))) then
  117. inc(pop_size,sizeof(aint));
  118. { better than an add on all processors }
  119. if pop_size=4 then
  120. begin
  121. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  122. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_POP,S_L,hreg));
  123. end
  124. { the pentium has two pipes and pop reg is pairable }
  125. { but the registers must be different! }
  126. else
  127. if (pop_size=8) and
  128. not(cs_opt_size in current_settings.optimizerswitches) and
  129. (current_settings.optimizecputype=cpu_Pentium) then
  130. begin
  131. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  132. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_POP,S_L,hreg));
  133. hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
  134. current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_POP,S_L,hreg));
  135. end
  136. else
  137. if pop_size<>0 then
  138. current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_ADD,S_L,pop_size,NR_ESP));
  139. end;
  140. begin
  141. ccallnode:=ti386callnode;
  142. end.