systlsdir.inc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2008 by Florian Klaempfl and Pavel Ozerski
  4. member of the Free Pascal development team.
  5. FPC Pascal system unit part shared by win32/win64.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  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.
  11. **********************************************************************}
  12. { TLS Directory code }
  13. {$ifdef FPC_USE_TLS_DIRECTORY}
  14. { Process TLS callback function }
  15. { This is only useful for executables
  16. for DLLs, DLL_Entry gets called. PM }
  17. {$ifdef FPC_INSSIDE_SYSINIT}
  18. {$ifdef win32}
  19. {$define FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  20. {$endif win32}
  21. Const
  22. DLL_PROCESS_ATTACH = 1;
  23. DLL_THREAD_ATTACH = 2;
  24. DLL_PROCESS_DETACH = 0;
  25. DLL_THREAD_DETACH = 3;
  26. var
  27. TlsKey : PDWord = @TlsKeyVar;
  28. type
  29. TTlsDirectory=packed record
  30. data_start, data_end : pointer;
  31. index_pointer, callbacks_pointer : pointer;
  32. zero_fill_size : dword;
  33. flags : dword;
  34. end;
  35. function TlsGetValue(dwTlsIndex : DWord) : pointer; stdcall;
  36. external 'kernel32' name 'TlsGetValue';
  37. procedure InitSystemThreads; external name '_FPC_InitSystemThreads';
  38. procedure SysAllocateThreadVars; external name '_FPC_SysAllocateThreadVars';
  39. procedure InitHeap; external name '_FPC_InitHeap';
  40. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  41. procedure SetupEntryInformation(constref info: TEntryInformation); external name '_FPC_SetupEntryInformation';
  42. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  43. {$endif FPC_INSSIDE_SYSINIT}
  44. procedure Exec_Tls_callback(Handle : pointer; reason : Dword; Reserved : pointer);
  45. stdcall; [public,alias:'_FPC_Tls_Callback'];
  46. begin
  47. if IsLibrary then
  48. Exit;
  49. case reason of
  50. { For executables, DLL_PROCESS_ATTACH is called *before* the entry point,
  51. and DLL_PROCESS_DETACH is called *after* RTL shuts down and calls ExitProcess.
  52. It isn't a good idea to handle resources of the main thread at these points.
  53. InitSystemThreads is necessary however, because if some statically loaded
  54. DLL creates a thread, it will invoke DLL_THREAD_ATTACH before anything else is
  55. initialized.
  56. TODO: The problem is that InitSystemThreads depends (in case of Win32)
  57. on EntryInformation which is not available at this point.
  58. Solving it properly needs to move this routine
  59. to sysinit unit or something like that.
  60. Exec_Tls_Callback is now part of sysinit unit for win32
  61. and the EntryInformation is a constant which sholud prevent troubles }
  62. DLL_PROCESS_ATTACH:
  63. begin
  64. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  65. { since this procedure is called before SetupEntryInformation and thus
  66. before EXE_Entry we need to setup the entry information here so that
  67. the threadvar handling can be correctly initialized }
  68. SetupEntryInformation(SysInitEntryInformation);
  69. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  70. InitHeap;
  71. InitSystemThreads;
  72. end;
  73. DLL_THREAD_ATTACH :
  74. begin
  75. { !!! SysInitMultithreading must NOT be called here. Windows guarantees that
  76. the main thread invokes PROCESS_ATTACH, not THREAD_ATTACH. So this always
  77. executes in non-main thread. SysInitMultithreading() here will cause
  78. initial threadvars to be copied to TLS of non-main thread, and threadvars
  79. of the main thread will be reinitialized upon the next access with zeroes,
  80. ending up in a delayed failure which is very hard to debug.
  81. Fortunately this nasty scenario can happen only when the first non-main thread
  82. was created outside of RTL (Sergei).
  83. }
  84. { Allocate Threadvars }
  85. SysAllocateThreadVars;
  86. { NS : no idea what is correct to pass here - pass dummy value for now }
  87. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  88. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  89. end;
  90. DLL_THREAD_DETACH :
  91. begin
  92. if TlsGetValue(TLSKey^)<>nil then
  93. DoneThread; { Assume everything is idempotent there }
  94. end;
  95. end;
  96. end;
  97. { Mingw tlssup.c source code has
  98. _CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0;
  99. _CRTALLOC(".CRT$XLZ") PIMAGE_TLS_CALLBACK __xl_z = 0;
  100. and the callback pointer is set to:
  101. (&__xl_a+1), (+1 meaning =+sizeof(pointer))
  102. I am not sure this can be compatible with
  103. }
  104. const
  105. FreePascal_TLS_callback : pointer = @Exec_Tls_callback;
  106. public name '__FPC_tls_callbacks' section '.CRT$XLFPC';
  107. FreePascal_end_of_TLS_callback : pointer = nil;
  108. public name '__FPC_end_of_tls_callbacks' section '.CRT$XLZZZ';
  109. var
  110. tls_callbacks : pointer; external name '___crt_xl_start__';
  111. tls_data_start : pointer; external name '___tls_start__';
  112. tls_data_end : pointer; external name '___tls_end__';
  113. _tls_index : dword; cvar; external;
  114. const
  115. _tls_used : TTlsDirectory = (
  116. data_start : @tls_data_start;
  117. data_end : @tls_data_end;
  118. index_pointer : @_tls_index;
  119. callbacks_pointer : @tls_callbacks;
  120. zero_fill_size : 0;
  121. flags : 0;
  122. ); cvar; public;
  123. {$ifdef win64}
  124. { This was a hack to support external linking.
  125. All released win64 versions of GNU binutils miss proper prefix handling
  126. when searching for _tls_used and expect two leading underscores.
  127. The issue has been fixed in binutils snapshots, but not released yet.
  128. Using alias allows to support both older and newer binutils.
  129. }
  130. alias = '__tls_used';
  131. {$endif win64}
  132. {$endif FPC_USE_TLS_DIRECTORY}