2
0

system.pp 17 KB

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