system.pp 14 KB

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