1

私はかなり複雑ですが、さまざまな x86-32 および x86-64 ボックスで実行されている非常によくテストされたアセンブリ言語 x86-32 アプリケーションを持っています。これは言語コンパイラのランタイム システムであるため、別のコンパイル済みバイナリ プログラムである「オブジェクト コード」の実行をサポートします。

Windows SEH を使用して、さまざまな種類のトラップ (ゼロ除算、不正アクセスなど) をキャッチし、Windows によって提供されるコンテキスト情報を使用して、トラップ時のマシンの状態を示すレジスタ ダンプを出力します。(関数のバックトレースを出力したり、必要に応じてゼロ除算から回復したりするなど、質問に関係のない他の多くのことを行います)。これにより、「オブジェクト コード」の作成者は、自分のプログラムで何が問題になったのかを把握できます。

2 つの Windows 7-64 システムでは動作が異なりますが、これは多かれ少なかれ同一ですが、不正なメモリ アクセスであると思われます。具体的な問題は、「オブジェクト コード」(十分にテストされたランタイム システムではない) が愚かにも 0x82 を EIP にロードすることです。これは、アドレス空間のAFAIKに存在しないページです。SEH を介した Windows トラップが予想され、EIP=00000082 などのレジスタ ダンプが予想されます。

あるシステムでは、まさにそのレジスタ ダンプが得られます。ここで表示できますが、私の質問には何も追加されません。したがって、ランタイム システムの SEH がこれをキャッチして状況を表示できることは明らかです。このマシンには、MS 開発ツールが搭載されていません。

ランタイム システムとオブジェクト コードのまったく同じバイナリを使用するもう 1 つの (「謎」) システムでは、コマンド プロンプトしか表示されません。それ以上の出力はありません。FWIW、このマシンには MS Visual Studio 2010 が搭載されています。ミステリーマシンは他の目的で頻繁に使用されており、通常の使用では他のおかしな動作は見られません.

動作の違いは、どこかの Windows 構成、または Visual Studio が制御する何かによって引き起こされると思います。システム メニューの DEP 構成ではありません。どちらも「標準システムプロセスのDEP」として構成されています(バニラ)。また、ランタイム システムの実行可能ファイルには「いいえ (/NXCOMPAT:NO)」が構成されています。

どちらのマシンも i7 ですが、チップ、4 コア、大量のメモリ、マザーボードが異なります。これは関係ないと思います。確かに、これらの CPU は両方とも同じ方法でトラップを取得します。

ランタイム システムには、起動時に次の行が含まれます。

SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); // クラッシュ時の Windows ポップアップを停止します

これは最近、クラッシュが発生したときに「謎の」システムがポップアップ ウィンドウ「xxx.exe が動作を停止しました」を表示しないようにするために追加されました。ポップアップ ボックスの動作は最初のシステムでは発生しないため、「ミステリー」マシンの別のコーナーに問題を押し込むだけでした。

これを構成/制御する手がかりはありますか?

私が使用しているSEHコードをここに提供します。このコードで見られる明らかな状態に影響を与えないと私が主張する、かなりの量の健全性チェック コードを削除するように編集されています。

ランタイム システムのトップ レベルは、(CreateThread を使用して) 一連のワーカー スレッドを生成し、ASMGrabGranuleAndGo を実行するようにポイントします。各スレッドは独自の SEH を設定し、ワークスティーリング スケジューラである RunReadyGranule に分岐します。私の知る限りでは、その後 SEH は変更されていません。少なくとも、ランタイム システムと「オブジェクト コード」はこれを行いませんが、基礎となる (標準の「C」などの) ライブラリが何を行うかはわかりません。

さらに下に、トラップ ハンドラー TopLevelEHFilter を提供します。はい、レジスター印刷機自体が爆発し、2 番目の例外が発生する可能性があります。すぐにもう一度確認してみますが、IIRC で謎のマシンのデバッガーでこれをキャッチしようとした最後の試みでは、デバッガーに制御が渡されず、ポップアップ ウィンドウが表示されました。

public ASMGrabGranuleAndGo
ASSUME FS:NOTHING ; cancel any assumptions made for this register
ASMGrabGranuleAndGo:
;Purpose: Entry for threads as workers in PARLANSE runtime system.
;   Each thread initializes as necessary, just once,
;   It then goes and hunts for work in the GranulesQ
;   and start executing a granule whenever one becomes available

; install top level exception handler

; Install handler for hardware exceptions
cmp        gCompilerBreakpointSet, 0
jne        HardwareEHinstall_end ; if set, do not install handler
push       offset TopLevelEHFilter ; push new exception handler on Windows thread stack
mov        eax, [TIB_SEH]    ; expected to be empty
test       eax, eax
BREAKPOINTIF jne
push       eax               ; save link to old exception handler
mov        fs:[TIB_SEH], esp ; tell Windows that our exception handler is active for this thread
HardwareEHinstall_end:

;Initialize FPU to "empty"... all integer grains are configured like this   
finit
fldcw      RTSFPUStandardMode

lock sub   gUnreadyProcessorCount, 1  ; signal that this thread has completed its initialization

@@: push       0                           ; sleep for 0 ticks
call       MySleep                     ; give up CPU (lets other threads run if we don't have enuf CPUs)
lea        esp, [esp+4]                ; pop arguments
mov        eax, gUnreadyProcessorCount ; spin until all other threads have completed initialization
test       eax, eax
jne        @b

mov        gThreadIsAlive[ecx], TRUE ; signal to scheduler that this thread now officially exists
jmp        RunReadyGranule    
ASMGrabGranuleAndGo_end:

;-------------------------------------------------------------------------------

TopLevelEHFilter: ; catch Windows Structured Exception Handling "trap"
; Invocation:
;   call  TopLevelEHFilter(&ReportRecord,&RegistrationRecord,&ContextRecord,&DispatcherRecord)
;         The arguments are passed in the stack at an offset of 8 (<--NUMBER FROM MS DOCUMENT)
;   ESP here "in the stack" being used by the code that caused the exception
;   May be either grain stack or Windows thread stack
extern exit :proc
extern syscall @RTSC_PrintExceptionName@4:near ; FASTCALL

push       ebp                     ; act as if this is a function entry
mov        ebp, esp                ; note: Context block is at offset ContextOffset[ebp]

IF_USING_WINDOWS_THREAD_STACK_GOTO unknown_exception, esp ; don't care what it is, we're dead
    ; *** otherwise, we must be using PARLANSE function grain stack space
    ; Compiler has ensured there's enough room, if the problem is a floating point trap
    ; If the problem is illegal memory reference, etc,
    ; there is no guarantee there is enough room, unless the application is compiled 
    ; with -G ("large stacks to handle exception traps")

; check what kind of exception 
mov        eax, ExceptionRecordOffset[ebp]
mov        eax, ExceptionRecord.ExceptionCode[eax]
cmp        eax, _EXCEPTION_INTEGER_DIVIDE_BY_ZERO
je         div_by_zero_exception
cmp        eax, _EXCEPTION_FLOAT_DIVIDE_BY_ZERO
je         float_div_by_zero_exception
jmp        near ptr unknown_exception  

float_div_by_zero_exception:
mov        ebx, ContextOffset[ebp] ; ebx = context record
mov        Context.FltStatusWord[ebx], CLEAR_FLOAT_EXCEPTIONS    ; clear any floating point exceptions
mov        Context.FltTagWord[ebx], -1 ; Marks all registers as empty
div_by_zero_exception: ; since RTS itself doesn't do division (that traps),
; if we get *here*, then we must be running a granule and EBX for granule points to GCB
mov        ebx, ContextOffset[ebp] ; ebx = context record

mov        ebx, Context.Rebx[ebx] ; grain EBX has to be set for AR Allocation routines
ALLOCATE_2TOK_BYTES 5             ; 5*4=20 bytes needed for the exception structure
mov        ExceptionBufferT.cArgs[eax], 0
mov        ExceptionBufferT.pException[eax], offset RTSDivideByZeroException    ; copy ptr to exception

mov        ebx, ContextOffset[ebp] ; ebx = context record
mov        edx, Context.Reip[ebx]
mov        Context.Redi[ebx], eax  ; load exception into thread's edi

GET_GRANULE_TO ecx

; This is Windows SEH (Structured Exception Handler... see use of Context block below! 

mov        eax, edx
LOOKUP_EH_FROM_TABLE   ; protected by DelayAbort
TRUST_JMP_INDIRECT_OK eax
mov        Context.Reip[ebx], eax

mov        eax, ExceptionContinueExecution ; signal to Windows: "return to caller" (we've revised the PC to go to Exception handler)
leave
ret

TopLevelEHFilter_end:

unknown_exception:
<print registers, etc. here>
4

1 に答える 1

1

「標準システム プロセスの DEP」は役に立ちません。内部的には "OptIn" として知られています。必要なのは、IMAGE_DLLCHARACTERISTICS_NX_COMPAT.exe ファイルの PE ヘッダーに設定されたフラグです。またはSetProcessDEPPolicy、kernel32.dll の関数を呼び出しSetProcessMitigationPolicyます。これも良いでしょう...しかし、Windows 8 までは利用できません。

Ed Maurer のブログには、.NET がどのように DEP を使用するか (気にする必要はありません) と、システム ルール (使用すること) の両方について説明しているすばらしい説明があります。

BIOS 設定も、ハードウェア NX が使用可能かどうかに影響を与える可能性があります。

于 2014-09-11T21:41:37.547 に答える