system.pp 13 KB

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