n8086ld.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. {
  2. Copyright (c) 2002-2014 by Florian Klaempfl
  3. Generate i8086 assembler for load 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 n8086ld;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. symsym,symtype,
  23. node,ncgld,nx86ld,aasmbase;
  24. type
  25. { ti8086loadnode }
  26. ti8086loadnode = class(tx86loadnode)
  27. protected
  28. procedure generate_nested_access(vs: tsym); override;
  29. procedure generate_absaddr_access(vs: tabsolutevarsym); override;
  30. procedure generate_threadvar_access(gvs: tstaticvarsym); override;
  31. public
  32. procedure pass_generate_code;override;
  33. end;
  34. implementation
  35. uses
  36. globals,verbose,aasmdata,defutil,
  37. symconst,symdef,symtable,symcpu,
  38. nld,
  39. cgbase,cgobj,cgutils,
  40. hlcgobj,
  41. cpubase,cpuinfo,
  42. parabase,paramgr;
  43. {*****************************************************************************
  44. TI8086LOADNODE
  45. *****************************************************************************}
  46. procedure ti8086loadnode.generate_nested_access(vs: tsym);
  47. begin
  48. inherited;
  49. { the parentfp pointer is always a near pointer (this is turbo pascal
  50. compatible) regardless of memory model, so we need to set the segment
  51. manually.
  52. todo: once the far data memory models are fully implemented, the
  53. parentfp type should be changed to a near 'ss' pointer in all memory
  54. models and then this code can be removed. But this can only happen
  55. after:
  56. 1) all calls to a_loadaddr_ref_reg go through the high level code
  57. generator
  58. 2) a_loadaddr_ref_reg in the low level code generator stops using
  59. the presence of a segment in the source reference to determine the
  60. destination reg size
  61. 3) make_simple_ref is updated to remove unnecessary segment prefixes
  62. 4) hlcg.reference_reset_base is updated to set the segment on near_ss
  63. pointers }
  64. if (left.nodetype=loadparentfpn) and
  65. (current_settings.x86memorymodel in x86_far_data_models) then
  66. location.reference.segment:=NR_SS;
  67. end;
  68. procedure ti8086loadnode.generate_absaddr_access(vs: tabsolutevarsym);
  69. begin
  70. if tcpuabsolutevarsym(symtableentry).absseg then
  71. begin
  72. location.reference.segment:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  73. cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_16,aint(tcpuabsolutevarsym(symtableentry).addrsegment),location.reference.segment);
  74. end;
  75. inherited;
  76. end;
  77. procedure ti8086loadnode.generate_threadvar_access(gvs: tstaticvarsym);
  78. var
  79. segref: treference;
  80. segreg: TRegister;
  81. newsize: TCgSize;
  82. norelocatelab: TAsmLabel;
  83. endrelocatelab: TAsmLabel;
  84. pvd: tdef;
  85. paraloc1 : tcgpara;
  86. hregister: TRegister;
  87. href: treference;
  88. begin
  89. if current_settings.x86memorymodel=mm_huge then
  90. begin
  91. if (cs_compilesystem in current_settings.moduleswitches) then
  92. begin
  93. inherited generate_threadvar_access(gvs);
  94. exit;
  95. end;
  96. { we don't know the size of all arrays }
  97. newsize:=def_cgsize(resultdef);
  98. { alignment is overridden per case below }
  99. location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment,[]);
  100. {
  101. Thread var loading is optimized to first check if
  102. a relocate function is available. When the function
  103. is available it is called to retrieve the address.
  104. Otherwise the address is loaded with the symbol
  105. The code needs to be in the order to first handle the
  106. call and then the address load to be sure that the
  107. register that is used for returning is the same (PFV)
  108. }
  109. current_asmdata.getjumplabel(norelocatelab);
  110. current_asmdata.getjumplabel(endrelocatelab);
  111. { make sure hregister can't allocate the register necessary for the parameter }
  112. pvd:=search_system_type('TRELOCATETHREADVARHANDLER').typedef;
  113. if pvd.typ<>procvardef then
  114. internalerror(2012120901);
  115. paraloc1.init;
  116. paramanager.getintparaloc(current_asmdata.CurrAsmList,tprocvardef(pvd),1,paraloc1);
  117. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,pvd);
  118. segreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  119. reference_reset_symbol(segref,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE',AT_DATA),0,pvd.alignment,[]);
  120. segref.refaddr:=addr_seg;
  121. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,segref,segreg);
  122. reference_reset_symbol(href,current_asmdata.RefAsmSymbol('FPC_THREADVAR_RELOCATE',AT_DATA),0,pvd.alignment,[]);
  123. href.segment:=segreg;
  124. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,pvd,pvd,href,hregister);
  125. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,pvd,OC_EQ,0,hregister,norelocatelab);
  126. { don't save the allocated register else the result will be destroyed later }
  127. if not(vo_is_weak_external in gvs.varoptions) then
  128. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_DATA),0,2,[])
  129. else
  130. reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(gvs.mangledname,AT_DATA),0,2,[]);
  131. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,OS_16,href,paraloc1);
  132. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  133. paraloc1.done;
  134. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  135. cg.a_call_reg(current_asmdata.CurrAsmList,hregister);
  136. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  137. cg.getcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  138. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);
  139. hregister:=hlcg.getaddressregister(current_asmdata.CurrAsmList,voidpointertype);
  140. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_ADDR,NR_FUNCTION_RESULT_REG,hregister);
  141. cg.a_jmp_always(current_asmdata.CurrAsmList,endrelocatelab);
  142. cg.a_label(current_asmdata.CurrAsmList,norelocatelab);
  143. { no relocation needed, load the address of the variable only, the
  144. layout of a threadvar is (4 bytes pointer):
  145. 0 - Threadvar index
  146. 4 - Threadvar value in single threading }
  147. if not(vo_is_weak_external in gvs.varoptions) then
  148. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_DATA),sizeof(pint),2,[])
  149. else
  150. reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(gvs.mangledname,AT_DATA),sizeof(pint),2,[]);
  151. hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,resultdef,voidpointertype,href,hregister);
  152. cg.a_label(current_asmdata.CurrAsmList,endrelocatelab);
  153. hlcg.reference_reset_base(location.reference,voidpointertype,hregister,0,ctempposinvalid,location.reference.alignment,[]);
  154. end
  155. else
  156. inherited generate_threadvar_access(gvs);
  157. end;
  158. procedure ti8086loadnode.pass_generate_code;
  159. var
  160. gvs: tstaticvarsym;
  161. segref: treference;
  162. refsym: TAsmSymbol;
  163. segreg: TRegister;
  164. newsize: TCgSize;
  165. begin
  166. case symtableentry.typ of
  167. staticvarsym:
  168. begin
  169. gvs:=tstaticvarsym(symtableentry);
  170. if (vo_is_dll_var in gvs.varoptions) then
  171. { DLL variable }
  172. begin
  173. inherited pass_generate_code;
  174. exit;
  175. end
  176. { Thread variable }
  177. else if (vo_is_thread_var in gvs.varoptions) then
  178. begin
  179. { this will be handled in ti8086loadnode.generate_threadvar_access }
  180. inherited pass_generate_code;
  181. exit;
  182. end
  183. { Normal (or external) variable }
  184. else
  185. begin
  186. if ((current_settings.x86memorymodel<>mm_huge) and not (vo_is_far in gvs.varoptions)) or
  187. (not (vo_is_external in gvs.varoptions) and gvs.Owner.iscurrentunit) then
  188. begin
  189. inherited pass_generate_code;
  190. if (location.loc<>LOC_REFERENCE) and (location.loc<>LOC_CREFERENCE) then
  191. internalerror(2017121101);
  192. location.reference.segment:=NR_DS;
  193. exit;
  194. end;
  195. { we don't know the size of all arrays }
  196. newsize:=def_cgsize(resultdef);
  197. { alignment is overridden per case below }
  198. location_reset_ref(location,LOC_REFERENCE,newsize,resultdef.alignment,[]);
  199. if gvs.localloc.loc=LOC_INVALID then
  200. begin
  201. if not(vo_is_weak_external in gvs.varoptions) then
  202. refsym:=current_asmdata.RefAsmSymbol(gvs.mangledname,AT_DATA)
  203. else
  204. refsym:=current_asmdata.WeakRefAsmSymbol(gvs.mangledname,AT_DATA);
  205. segreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
  206. reference_reset_symbol(segref,refsym,0,0,[]);
  207. segref.refaddr:=addr_seg;
  208. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,segref,segreg);
  209. reference_reset_symbol(location.reference,refsym,0,location.reference.alignment,[]);
  210. location.reference.segment:=segreg;
  211. end
  212. else
  213. location:=gvs.localloc;
  214. end;
  215. { make const a LOC_CREFERENCE }
  216. if (gvs.varspez=vs_const) and
  217. (location.loc=LOC_REFERENCE) then
  218. location.loc:=LOC_CREFERENCE;
  219. end;
  220. procsym:
  221. begin
  222. inherited pass_generate_code;
  223. if current_settings.x86memorymodel in x86_near_code_models then
  224. begin
  225. if (location.loc=LOC_REFERENCE) or (location.loc=LOC_CREFERENCE) then
  226. location.reference.segment:=NR_CS;
  227. end;
  228. end;
  229. else
  230. inherited pass_generate_code;
  231. end;
  232. end;
  233. begin
  234. cloadnode:=ti8086loadnode;
  235. end.