system.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2006 by Florian Klaempfl and Pavel Ozerski
  4. member of the Free Pascal development team.
  5. FPC Pascal system unit for the Win64 API.
  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. unit System;
  13. interface
  14. {$IFNDEF FPC_DISABLE_MONITOR}
  15. {$DEFINE SYSTEM_HAS_FEATURE_MONITOR}
  16. {$ENDIF}
  17. {$define FPC_IS_SYSTEM}
  18. { $define SYSTEMEXCEPTIONDEBUG}
  19. {$ifdef SYSTEMDEBUG}
  20. {$define SYSTEMEXCEPTIONDEBUG}
  21. {$endif SYSTEMDEBUG}
  22. {$define DISABLE_NO_THREAD_MANAGER}
  23. {$define HAS_WIDESTRINGMANAGER}
  24. {$define DISABLE_NO_DYNLIBS_MANAGER}
  25. {$define FPC_SYSTEM_HAS_SYSDLH}
  26. {$define FPC_HAS_SETCTRLBREAKHANDLER}
  27. {$if defined(FPC_USE_WIN64_SEH) or defined(CPUAARCH64)}
  28. {$define SYSTEM_USE_WIN_SEH}
  29. {$endif}
  30. {$ifdef SYSTEM_USE_WIN_SEH}
  31. {$define FPC_SYSTEM_HAS_RAISEEXCEPTION}
  32. {$define FPC_SYSTEM_HAS_RERAISE}
  33. {$define FPC_SYSTEM_HAS_CAPTUREBACKTRACE}
  34. {$endif SYSTEM_USE_WIN_SEH}
  35. { include system-independent routine headers }
  36. {$I systemh.inc}
  37. { include common windows headers }
  38. {$I syswinh.inc}
  39. var
  40. MainInstance : qword;
  41. implementation
  42. var
  43. FPCSysInstance : PQWord;public name '_FPC_SysInstance';
  44. {$define FPC_SYSTEM_HAS_OSSETUPENTRYINFORMATION}
  45. procedure OsSetupEntryInformation(constref info: TEntryInformation); forward;
  46. procedure SetupEntryInformation(constref info: TEntryInformation);forward;
  47. {$define FPC_SYSTEM_HAS_STACKTOP}
  48. function main_wrapper(arg: Pointer; proc: Pointer): ptrint; forward;
  49. { include system independent routines }
  50. {$I system.inc}
  51. {$I cpuwin.inc}
  52. {*****************************************************************************
  53. System Dependent Exit code
  54. *****************************************************************************}
  55. {$ifndef SYSTEM_USE_WIN_SEH}
  56. procedure install_exception_handlers;forward;
  57. {$endif SYSTEM_USE_WIN_SEH}
  58. { include code common with win32 }
  59. {$I syswin.inc}
  60. procedure OsSetupEntryInformation(constref info: TEntryInformation);
  61. begin
  62. TlsKey := info.OS.TlsKeyAddr;
  63. FPCSysInstance := info.OS.SysInstance;
  64. WStrInitTablesTable := info.OS.WideInitTables;
  65. end;
  66. Procedure system_exit;
  67. begin
  68. { see comments in win32/system.pp about this logic }
  69. if IsLibrary then
  70. begin
  71. if DllInitState in [DLL_PROCESS_ATTACH,DLL_PROCESS_DETACH] then
  72. LongJmp(DLLBuf,1)
  73. else
  74. MainThreadIDWin32:=0;
  75. end;
  76. if not IsConsole then
  77. begin
  78. Close(stderr);
  79. Close(stdout);
  80. Close(erroutput);
  81. Close(Input);
  82. Close(Output);
  83. { what about Input and Output ?? PM }
  84. { now handled, FPK }
  85. end;
  86. if Ole32Dll <> 0 then
  87. begin
  88. WinFreeLibrary(Ole32Dll); { Careful, FreeLibrary should not be called from DllMain. }
  89. Ole32Dll := 0;
  90. end;
  91. if OleAut32Dll <> 0 then
  92. begin
  93. WinFreeLibrary(OleAut32Dll);
  94. OleAut32Dll := 0;
  95. end;
  96. { call exitprocess, with cleanup as required }
  97. ExitProcess(exitcode);
  98. end;
  99. //
  100. // Hardware exception handling
  101. //
  102. {$I seh64.inc}
  103. type
  104. TVectoredExceptionHandler = function (excep : PExceptionPointers) : Longint;
  105. function AddVectoredExceptionHandler(FirstHandler : DWORD;VectoredHandler : TVectoredExceptionHandler) : longint;
  106. external 'kernel32' name 'AddVectoredExceptionHandler';
  107. {$ifndef SYSTEM_USE_WIN_SEH}
  108. const
  109. MaxExceptionLevel = 16;
  110. exceptLevel : Byte = 0;
  111. var
  112. exceptRip : array[0..MaxExceptionLevel-1] of Int64;
  113. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  114. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  115. {$ifdef SYSTEMEXCEPTIONDEBUG}
  116. procedure DebugHandleErrorAddrFrame(error : longint; addr, frame : pointer);
  117. begin
  118. if IsConsole then
  119. begin
  120. write(stderr,'HandleErrorAddrFrame(error=',error);
  121. write(stderr,',addr=',hexstr(int64(addr),16));
  122. writeln(stderr,',frame=',hexstr(int64(frame),16),')');
  123. end;
  124. HandleErrorAddrFrame(error,addr,frame);
  125. end;
  126. {$endif SYSTEMEXCEPTIONDEBUG}
  127. procedure JumpToHandleErrorFrame;
  128. var
  129. rip, rbp : int64;
  130. error : longint;
  131. begin
  132. // save ebp
  133. {$ifdef CPUX86_64}
  134. asm
  135. movq (%rbp),%rax
  136. movq %rax,rbp
  137. end;
  138. {$endif}
  139. if exceptLevel>0 then
  140. dec(exceptLevel);
  141. rip:=exceptRip[exceptLevel];
  142. error:=exceptError[exceptLevel];
  143. {$ifdef SYSTEMEXCEPTIONDEBUG}
  144. if IsConsole then
  145. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  146. {$endif SYSTEMEXCEPTIONDEBUG}
  147. if resetFPU[exceptLevel] then
  148. SysResetFPU;
  149. { build a fake stack }
  150. {$ifdef CPUX86_64}
  151. asm
  152. movq rbp,%r8
  153. movq rip,%rdx
  154. movl error,%ecx
  155. pushq rip
  156. movq rbp,%rbp // Change frame pointer
  157. {$ifdef SYSTEMEXCEPTIONDEBUG}
  158. jmpl DebugHandleErrorAddrFrame
  159. {$else not SYSTEMEXCEPTIONDEBUG}
  160. jmpl HandleErrorAddrFrame
  161. {$endif SYSTEMEXCEPTIONDEBUG}
  162. end;
  163. {$endif}
  164. end;
  165. function syswin64_x86_64_exception_handler(excep : PExceptionPointers) : Longint;public;
  166. var
  167. res: longint;
  168. err: byte;
  169. must_reset_fpu: boolean;
  170. begin
  171. res:=EXCEPTION_CONTINUE_SEARCH;
  172. {$ifdef SYSTEMEXCEPTIONDEBUG}
  173. if IsConsole then
  174. Writeln(stderr,'syswin64_x86_64_exception_handler called');
  175. {$endif SYSTEMEXCEPTIONDEBUG}
  176. if excep^.ContextRecord^.SegSs=_SS then
  177. begin
  178. err := 0;
  179. must_reset_fpu := true;
  180. {$ifdef SYSTEMEXCEPTIONDEBUG}
  181. if IsConsole then Writeln(stderr,'Exception ',
  182. hexstr(excep^.ExceptionRecord^.ExceptionCode,8));
  183. {$endif SYSTEMEXCEPTIONDEBUG}
  184. case cardinal(excep^.ExceptionRecord^.ExceptionCode) of
  185. STATUS_INTEGER_DIVIDE_BY_ZERO,
  186. STATUS_FLOAT_DIVIDE_BY_ZERO :
  187. err := 208;
  188. STATUS_ARRAY_BOUNDS_EXCEEDED :
  189. begin
  190. err := 201;
  191. must_reset_fpu := false;
  192. end;
  193. STATUS_STACK_OVERFLOW :
  194. begin
  195. err := 202;
  196. must_reset_fpu := false;
  197. end;
  198. STATUS_FLOAT_OVERFLOW :
  199. err := 205;
  200. STATUS_FLOAT_DENORMAL_OPERAND,
  201. STATUS_FLOAT_UNDERFLOW :
  202. err := 206;
  203. { excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  204. STATUS_FLOAT_INEXACT_RESULT,
  205. STATUS_FLOAT_INVALID_OPERATION,
  206. STATUS_FLOAT_STACK_CHECK :
  207. err := 207;
  208. STATUS_INTEGER_OVERFLOW :
  209. begin
  210. err := 215;
  211. must_reset_fpu := false;
  212. end;
  213. STATUS_ILLEGAL_INSTRUCTION:
  214. err := 216;
  215. STATUS_ACCESS_VIOLATION:
  216. { Athlon prefetch bug? }
  217. if is_prefetch(pointer(excep^.ContextRecord^.rip)) then
  218. begin
  219. { if yes, then retry }
  220. excep^.ExceptionRecord^.ExceptionCode := 0;
  221. res:=EXCEPTION_CONTINUE_EXECUTION;
  222. end
  223. else
  224. err := 216;
  225. STATUS_CONTROL_C_EXIT:
  226. err := 217;
  227. STATUS_PRIVILEGED_INSTRUCTION:
  228. begin
  229. err := 218;
  230. must_reset_fpu := false;
  231. end;
  232. else
  233. begin
  234. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  235. err := 217
  236. else
  237. { pass through exceptions which aren't an error. The problem is that vectored handlers
  238. always are called before structured ones so we see also internal exceptions of libraries.
  239. I wonder if there is a better solution (FK)
  240. }
  241. res:=EXCEPTION_CONTINUE_SEARCH;
  242. end;
  243. end;
  244. if (err <> 0) and (exceptLevel < MaxExceptionLevel) then
  245. begin
  246. exceptRip[exceptLevel] := excep^.ContextRecord^.Rip;
  247. exceptError[exceptLevel] := err;
  248. resetFPU[exceptLevel] := must_reset_fpu;
  249. inc(exceptLevel);
  250. excep^.ContextRecord^.Rip := Int64(@JumpToHandleErrorFrame);
  251. excep^.ExceptionRecord^.ExceptionCode := 0;
  252. res := EXCEPTION_CONTINUE_EXECUTION;
  253. {$ifdef SYSTEMEXCEPTIONDEBUG}
  254. if IsConsole then begin
  255. writeln(stderr,'Exception Continue Exception set at ',
  256. hexstr(exceptRip[exceptLevel-1],16));
  257. writeln(stderr,'Rip changed to ',
  258. hexstr(int64(@JumpToHandleErrorFrame),16), ' error=', err);
  259. end;
  260. {$endif SYSTEMEXCEPTIONDEBUG}
  261. end;
  262. end;
  263. syswin64_x86_64_exception_handler := res;
  264. end;
  265. procedure install_exception_handlers;
  266. begin
  267. AddVectoredExceptionHandler(1,@syswin64_x86_64_exception_handler);
  268. end;
  269. {$endif ndef SYSTEM_USE_WIN_SEH}
  270. {$ifdef FPC_SECTION_THREADVARS}
  271. function fpc_tls_add(addr: pointer): pointer; assembler; nostackframe;
  272. [public,alias: 'FPC_TLS_ADD']; compilerproc;
  273. asm
  274. sub $56,%rsp { 32 spill area + 16 local vars + 8 misalignment }
  275. .seh_stackalloc 56
  276. .seh_endprologue
  277. lea tls_data_start(%rip),%rax
  278. sub %rax,%rcx
  279. cmpb $0,IsLibrary(%rip)
  280. mov _tls_index(%rip),%eax
  281. jnz .L1
  282. mov %gs:(88),%rdx
  283. add (%rdx,%rax,8),%rcx
  284. mov %rcx,%rax
  285. jmp .L3
  286. .L1:
  287. mov %rcx,32(%rsp)
  288. call GetLastError
  289. mov %rax,40(%rsp) { save LastError }
  290. mov _tls_index(%rip),%ecx
  291. call TlsGetValue
  292. test %rax,%rax
  293. jnz .L2
  294. { This can happen when a thread existed before DLL was loaded,
  295. or if DisableThreadLibraryCalls was called. }
  296. call SysAllocateThreadVars
  297. mov $0x1000000,%rcx
  298. call InitThread
  299. mov _tls_index(%rip),%ecx
  300. call TlsGetValue
  301. .L2:
  302. add %rax,32(%rsp)
  303. mov 40(%rsp),%rcx
  304. call SetLastError
  305. mov 32(%rsp),%rax
  306. .L3:
  307. add $56,%rsp
  308. end;
  309. {$endif FPC_SECTION_THREADVARS}
  310. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  311. type
  312. tdosheader = packed record
  313. e_magic : word;
  314. e_cblp : word;
  315. e_cp : word;
  316. e_crlc : word;
  317. e_cparhdr : word;
  318. e_minalloc : word;
  319. e_maxalloc : word;
  320. e_ss : word;
  321. e_sp : word;
  322. e_csum : word;
  323. e_ip : word;
  324. e_cs : word;
  325. e_lfarlc : word;
  326. e_ovno : word;
  327. e_res : array[0..3] of word;
  328. e_oemid : word;
  329. e_oeminfo : word;
  330. e_res2 : array[0..9] of word;
  331. e_lfanew : longint;
  332. end;
  333. tpeheader = packed record
  334. PEMagic : longint;
  335. Machine : word;
  336. NumberOfSections : word;
  337. TimeDateStamp : longint;
  338. PointerToSymbolTable : longint;
  339. NumberOfSymbols : longint;
  340. SizeOfOptionalHeader : word;
  341. Characteristics : word;
  342. Magic : word;
  343. MajorLinkerVersion : byte;
  344. MinorLinkerVersion : byte;
  345. SizeOfCode : longint;
  346. SizeOfInitializedData : longint;
  347. SizeOfUninitializedData : longint;
  348. AddressOfEntryPoint : longint;
  349. BaseOfCode : longint;
  350. {$ifdef win32}
  351. BaseOfData : longint;
  352. {$endif win32}
  353. ImageBase : PtrInt;
  354. SectionAlignment : longint;
  355. FileAlignment : longint;
  356. MajorOperatingSystemVersion : word;
  357. MinorOperatingSystemVersion : word;
  358. MajorImageVersion : word;
  359. MinorImageVersion : word;
  360. MajorSubsystemVersion : word;
  361. MinorSubsystemVersion : word;
  362. Reserved1 : longint;
  363. SizeOfImage : longint;
  364. SizeOfHeaders : longint;
  365. CheckSum : longint;
  366. Subsystem : word;
  367. DllCharacteristics : word;
  368. SizeOfStackReserve : PtrInt;
  369. SizeOfStackCommit : PtrInt;
  370. SizeOfHeapReserve : PtrInt;
  371. SizeOfHeapCommit : PtrInt;
  372. LoaderFlags : longint;
  373. NumberOfRvaAndSizes : longint;
  374. DataDirectory : array[1..$80] of byte;
  375. end;
  376. begin
  377. result:=tpeheader((pointer(getmodulehandle(nil))+(tdosheader(pointer(getmodulehandle(nil))^).e_lfanew))^).SizeOfStackReserve;
  378. end;
  379. initialization
  380. { pass dummy value }
  381. StackLength := CheckInitialStkLen($1000000);
  382. StackBottom := StackTop - StackLength;
  383. SetThreadStackGuaranteeTo(StackMargin);
  384. { get some helpful informations }
  385. GetStartupInfo(@startupinfo);
  386. { some misc Win32 stuff }
  387. if not IsLibrary then
  388. FPCSysInstance^:=getmodulehandle(nil);
  389. MainInstance:=FPCSysInstance^;
  390. cmdshow:=startupinfo.wshowwindow;
  391. { Setup heap and threading, these may be already initialized from TLS callback }
  392. if not Assigned(CurrentTM.BeginThread) then
  393. begin
  394. InitHeap;
  395. InitSystemThreads;
  396. end;
  397. SysInitExceptions;
  398. initunicodestringmanager;
  399. InitWin32Widestrings;
  400. SysInitStdIO;
  401. { Arguments }
  402. setup_arguments;
  403. InitSystemDynLibs;
  404. { Reset IO Error }
  405. InOutRes:=0;
  406. DispCallByIDProc:=@DoDispCallByIDError;
  407. finalization
  408. WinFinalizeSystem;
  409. end.