system.pp 14 KB

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