narmld.pas 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. {
  2. Copyright (c) 1998-2018 by Florian Klaempfl
  3. Generate arm 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 narmld;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. symsym,
  23. node,ncgld,pass_1,aasmbase;
  24. type
  25. tarmloadnode = class(tcgloadnode)
  26. procedure generate_threadvar_access(gvs : tstaticvarsym); override;
  27. end;
  28. implementation
  29. uses
  30. globals,verbose,
  31. cgbase,cgobj,cgutils,
  32. aasmdata,aasmcpu,
  33. systems,
  34. symcpu,symdef,
  35. nld,
  36. cpubase,
  37. parabase,
  38. procinfo;
  39. {*****************************************************************************
  40. TARMLOADNODE
  41. *****************************************************************************}
  42. procedure tarmloadnode.generate_threadvar_access(gvs: tstaticvarsym);
  43. var
  44. href: treference;
  45. hregister : tregister;
  46. handled: boolean;
  47. l : TAsmLabel;
  48. begin
  49. handled:=false;
  50. if tf_section_threadvars in target_info.flags then
  51. begin
  52. if target_info.system in [system_arm_linux] then
  53. begin
  54. if not(pi_uses_threadvar in current_procinfo.flags) then
  55. internalerror(2012012101);
  56. case current_settings.tlsmodel of
  57. tlsm_global_dynamic:
  58. begin
  59. {$ifdef use_tls_dialect_gnu}
  60. current_asmdata.getjumplabel(l);
  61. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_TLS),-8,sizeof(AInt),[]);
  62. href.refaddr:=addr_tlsgd;
  63. href.relsymbol:=l;
  64. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  65. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
  66. cg.a_label(current_asmdata.CurrAsmList,l);
  67. cg.getcpuregister(current_asmdata.CurrAsmList,NR_R0);
  68. cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,hregister,NR_PC,NR_R0);
  69. cg.g_call(current_asmdata.CurrAsmList,'__tls_get_addr');
  70. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_R0);
  71. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  72. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,NR_R0,hregister);
  73. reference_reset(location.reference,location.reference.alignment,location.reference.volatility);
  74. location.reference.base:=hregister;
  75. {$else use_tls_dialect_gnu}
  76. { On arm, we use the gnu2 tls dialect. It has the advantage that it can be relaxed (optimized) by the linker,
  77. this is not possible with the gnu tls dialect.
  78. gnu2 is proposed and documented in
  79. Glauber de Oliveira Costa, Alexandre Oliva: Speeding Up Thread-Local Storage Access in DynamicLibraries in the ARM platform, 2006.
  80. Link: https://www.fsfla.org/~lxoliva/writeups/TLS/paper-lk2006.pdf
  81. }
  82. current_asmdata.getjumplabel(l);
  83. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_TLS),0,sizeof(AInt),[]);
  84. href.refaddr:=addr_tlsdesc;
  85. href.relsymbol:=l;
  86. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  87. cg.getcpuregister(current_asmdata.CurrAsmList,NR_R0);
  88. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,NR_R0);
  89. cg.a_label(current_asmdata.CurrAsmList,l);
  90. { we have to go the ugly way so we can set addr_tlscall }
  91. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  92. cg.a_call_name(current_asmdata.CurrAsmList,gvs.mangledname,false);
  93. with taicpu(current_asmdata.CurrAsmList.Last) do
  94. begin
  95. if opcode<>A_BL then
  96. Internalerror(2019092902);
  97. oper[0]^.ref^.refaddr:=addr_tlscall;
  98. end;
  99. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  100. cg.getcpuregister(current_asmdata.CurrAsmList,NR_R0);
  101. cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_R0);
  102. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  103. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,NR_R0,hregister);
  104. reference_reset(location.reference,location.reference.alignment,location.reference.volatility);
  105. location.reference.base:=current_procinfo.tlsoffset;
  106. include(current_procinfo.flags,pi_needs_tls);
  107. location.reference.index:=hregister;
  108. {$endif use_tls_dialect_gnu}
  109. handled:=true;
  110. end;
  111. tlsm_initial_exec:
  112. begin
  113. current_asmdata.getjumplabel(l);
  114. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_TLS),-8,sizeof(AInt),[]);
  115. href.refaddr:=addr_tpoff;
  116. href.relsymbol:=l;
  117. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  118. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
  119. cg.a_label(current_asmdata.CurrAsmList,l);
  120. reference_reset(href,0,[]);
  121. href.base:=NR_PC;
  122. href.index:=hregister;
  123. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  124. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,hregister);
  125. location.reference.base:=current_procinfo.tlsoffset;
  126. include(current_procinfo.flags,pi_needs_tls);
  127. location.reference.index:=hregister;
  128. handled:=true;
  129. end;
  130. tlsm_local_exec:
  131. begin
  132. reference_reset_symbol(href,current_asmdata.RefAsmSymbol(gvs.mangledname,AT_TLS),0,sizeof(AInt),[]);
  133. href.refaddr:=addr_tpoff;
  134. hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
  135. cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
  136. reference_reset(href,0,[]);
  137. location.reference.base:=current_procinfo.tlsoffset;
  138. include(current_procinfo.flags,pi_needs_tls);
  139. location.reference.index:=hregister;
  140. handled:=true;
  141. end;
  142. else
  143. Internalerror(2019092802);
  144. end;
  145. end;
  146. end;
  147. if not handled then
  148. inherited;
  149. end;
  150. begin
  151. cloadnode:=tarmloadnode;
  152. end.