system.pp 14 KB

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