13

선인장 스택을 사용하여 병렬 프로그램을 구현하는 MS Windows에서 언어 PARLANSE을 구현했습니다. 스택 청크는 함수 당 단위로 할당되며 은 단지이고 로컬 변수를 처리하는 데 적합한 크기이고 표현식 푸시/팝 및 라이브러리 호출 (라이브러리 루틴이 적용되는 스택 공간은 )을 포함합니다. 이러한 스택 프레임은 실제로 32 바이트로 작을 수 있으며 종종 그렇습니다. 코드가 멍청한 짓 수행하고 하드웨어 트랩 ... 윈도우는 "스택에"전체 86 기계 컨텍스트를 밀어 주장 에 나타나는 지점에서 발생하지 않는 한Windows : 스택에 전체 x86 컨텍스트를 밀어 넣지 마십시오.

이 모두 잘 작동합니다. FP/MMX/etc를 포함하면 500 바이트가 넘습니다. 레지스터, . 당연히 32 바이트 스택의 500 바이트 푸시 은 그렇지 않아야합니다. (하드웨어가 트랩에 이라는 단어를 푸시하지만 전체 컨텍스트는 푸시하지 않음).

[편집 2012년 11월 27일 : 참조 this for measured details on the rediculous amount of stack Windows actually pushes]

나는 윈도우 (예를 들어, 스레드에 특정 위치에) 다른 예외 상황에 맞는 블록 곳을 저장할받을 수 있습니까? 그런 다음 소프트웨어에서 예외 을 스레드에서 처리하고 작은 작은 스택 프레임을 오버플로하지 않고 처리 할 수 ​​있습니다.

나는 이것이 가능하다고 생각하지 않지만, 훨씬 더 큰 청중에게 물어볼 것이라고 생각했습니다. 이 문제가 발생할 수있는 OS 표준 호출/인터페이스 이 있습니까?

내 프로세스가 선택적으로 기본적으로 현재 기존 동작을 가능하게 초기화 컨텍스트 저장 위치 "contextp"를 정의시키기에 MS를 사기 수 있다면 운영 체제에서 할 사소한 것입니다. 그런 다음 interrrupt/트랩 벡터 codee 교체 : 등, ... somereg을 저장하는 데 필요한 명백한 변화

hardwareint: mov <somereg> contextp 
       test <somereg> 
       jnz $2 
       push context 
       mov contextp, esp 
       jmp $1 
     $2: store context @ somereg 
     $1: equ * 

로 ...

hardwareint: push context 
       mov contextp, esp 

[I는 어떤 기능을 수행 지금은 : 각 함수에 대해 생성 된 코드를 확인하십시오. 트랩 (예 : 0으로 나누기)을 생성 할 가능성이 있거나 디버깅 할 가능성이있는 경우 (잘못된 포인터 deref 등) 가능한 경우 을 FP 컨텍스트의 스택 프레임에 추가하십시오. 스택 프레임 은 이제 ~~ 500-1000 바이트의 크기로 끝나기 때문에 프로그램은 까지 회귀 할 수 없습니다. 이는 우리가 작성한 응용 프로그램의 실제 문제 일 때가 있습니다. 그래서 우리는 가능한 솔루션 을 가지고 있지만 그것은 디버깅]

편집 8월 25일 복잡 : 내가 알아 마이크로 소프트 내부 엔지니어 Apparantly 히 권한이 에이 이야기를 얻기 위해 관리 한 사람 MS의 수도 실제로 주의 . 해결책에 희미한 희망이있을 수 있습니다.

9 월 14 일 수정 : MS Kernal Group Architect는이 이야기를 듣고 공감 스럽습니다. 그는 MS가 (제안 된 것과 같은) 솔루션을 고려할 것이지만 서비스 팩에있을 가능성은 낮다고 말했다.다음 버전의 Windows를 기다려야 할 수도 있습니다. (한숨 ... 나이 먹을 수도 있습니다 ...)

편집 : 2010 년 9 월 13 일 (1 년 후). Microsoft 측에서 아무런 조치도 취하지 않았습니다. 내 최근의 악몽 : Windows X64에서 32 비트 프로세스를 실행하는 트랩을 수행하고 인터럽트 처리기가 32 비트 컨텍스트를 푸시하기 전에 스택에서 전체 X64 컨텍스트를 푸시합니까? 그것은 훨씬 더 클 것입니다 (두 배의 정수 레지스터를 두 배, SSE 레지스터의 두 배를 (?))?

편집 : 2012 년 2 월 25 일 : (1.5 년 간 ...) Microsoft 측에서 아무런 반응이 없습니다. 나는 그들이 내 종류의 병렬 처리에 신경 쓰지 않는다고 생각한다. 나는 이것이 지역 사회에 불만이라고 생각한다. 정상적인 상황에서 MS가 사용하는 "큰 스택 모델"은 막대한 양의 VM을 먹음으로써 어느 순간에도 살아갈 수있는 병렬 계산의 양을 제한합니다. PARLANSE 모델은 다양한 주행/대기 상태에서 백만 개의 "곡물"이있는 응용 프로그램을 갖게합니다. 이것은 실제로 1 억 개의 노드 그래프가 "병렬로"처리되는 일부 응용 프로그램에서 발생합니다. PARLANSE 체계는 약 1Gb의 RAM으로이를 수행 할 수 있습니다. MS 1Mb "큰 스택"을 사용하려고 시도한다면 스택 공간을 위해 단지 10^12 바이트의 VM이 필요하며 Windows는 100 만 개의 스레드를 관리 할 수 ​​없다고 확신합니다.

편집 : 2014 년 4 월 29 일 : (4 년 후). 나는 MS가 단지 그렇게 읽지 않는다고 생각한다. 필자는 PARLANSE에 충분한 엔지니어링 작업을 수행 했으므로 디버깅 중에 FP 작업이 진행될 때만 대형 스택 프레임 가격을 지불하므로이 작업을 수행하는 데있어 매우 실용적인 방법을 찾을 수있었습니다. MS는 계속 실망했다. 여러 버전의 Windows에서 스택에 푸시 된 항목의 양은 하드웨어 컨텍스트 만 필요로하는 것보다 훨씬 심각하게 달라질 수 있습니다. 이러한 변동성 중 일부는 예외 처리 체인에 코를 찔러 넣은 비 MS 제품 (예 : 바이러스 백신)이 붙어서 발생합니다. 왜 그들은 내 주소 공간 밖에서 그렇게 할 수 없습니까? 우리는 FP/디버그 트랩을위한 큰 슬롭 팩터를 추가하고 그 양을 초과하는 피할 수없는 MS 시스템을 현장에서 기다리는 것으로 모든 것을 처리합니다.

+0

ntdll.dll을 메모리에 패치하면 변경 내용은 현재 프로세스에만 표시됩니다 (copy-on-write). 나는 IAT가 아니라 직접 주소가 사용된다고 가정 하겠지만 JMP를 사용하여 처리기의 처음 몇 바이트를 자신의 코드로 덮어서 링 3으로 되돌릴 수 있습니다. Windows는 이러한 종류의 하지만 그럴 가치가있어. – zildjohn01

+0

이제 그건 생각입니다. IDT의 대상이 ntdll.dll에 있고 그걸 밟을 수 있다고 제안하고 있습니까? IDT가 어디서 가리키고 있는지 또는 ntdll.dll에 게시 된 엔트리 포인트인지 어떻게 알 수 있습니까? ntdll.dll의 구조에 대한 자세한 내용은 어디에서 확인할 수 있습니까? 방금 ​​들었던 문구를 에코하려면 "이것은 잠시 바쁘게 할 것입니다."감사합니다! –

+0

죄송합니다.나는 IDT를 사용했는데 요즘은 x86 아키텍처에서 호출하는 인터럽트 벡터 나 인터럽트를 의미합니다. (저는 x86 매뉴얼을 가지고 있습니다. 이것은 수사학적인 문장입니다 :-) –

답변

0

Windows 예외 처리를 SEH라고합니다. IIRC를 사용 중지 할 수 있지만 사용중인 언어의 런타임이이를 사용하지 못할 수 있습니다.

+0

나는 SEH에 대해 알고 있으며 우리는 예외 처리기를 가리 키도록 설정했다. 어떻게 그것을 비활성화하고 하드웨어 트랩은 어디로 이동합니까? 내가 사용하고있는 언어의 런타임은 완전히 나의 통제하에있다. 대부분의 병렬 언어 런타임은 C로 구현되지만 소프트웨어는 선인장 스타일 스택에서 표준 MS "큰"스택으로 스택을 스위치 식으로 전환합니다. 스택 오버 플로우 문제가 해결되면 예외 핸들러도 전환 할 수 있습니다. –

+1

SEH를 사용하지 않으면 앱이 0으로 나누기가 중단됩니다. 그리고 어떻게 든 예외를 비활성화 할 수 있다면 CPU가 0으로 나누기 ..... 트리플 폴트 (triple-fault)에서 무엇을 할 것으로 기대합니까? – zildjohn01

+0

SEH를 사용하지 않도록 설정하지 않았습니다. 단순히 처리기를 가리 키도록 설정했습니다. 내 처리기가 제어 할 때까지 Windows는 이미 전체 스택 프레임을 스택에 밀어 넣었습니다. –

1

Windows에서 x86 하드웨어를 사용하여 트랩 코드를 구현하는 경우 트랩에 사용할 게이트를 변경하려면 링 0 액세스 (드라이버 또는 API를 통해)가 필요합니다.

의 하나의 게이트 점의 86 개념 : 리턴 어드레스를 포함하여, 전체 레지스터 콘텍스트 상태라고

  • 인터럽트 어드레스 (코드 세그먼트 + 옵셋 포인터), 현재의 스택에 푸시 (= 전류 esp) 또는
  • 다른 작업으로 전환되는 작업 설명자 (하드웨어 지원 스레드로 간주 될 수 있음). 모든 관련 데이터가 대신 해당 작업의 스택 (esp)으로 푸시됩니다.

물론 후자가 필요합니다. 나는 Wine을 어떻게 구현했는지 보았을 것이고, 그것은 구글에게 묻는 것보다 더 효과적 일 것입니다.

내 생각 엔 안타깝게도 x86에서 작동하도록 드라이버를 구현해야하며, Wikipedia에 따르면 드라이버가 IA64 플랫폼에서 드라이버를 변경할 수 없다고 생각합니다. 두 번째로 좋은 옵션은 스택의 공간을 인터리브하는 것일 수 있습니다. 그래야 함정의 컨텍스트 푸시가 항상 맞습니까?

+0

Wine을 볼 수는 있지만 Windows와 관련하여 무엇을 배울 지 확신 할 수 없습니다. 첫째, Wine은 Linux에서 실행됩니다. OS 호출을 Windows 용으로 사용할 수 있다는 특별한 이유가 없습니다. 둘째, Windows에서 하드웨어 인터럽트 게이트 또는 작업 설명자를 제어 할 수 있다는 특별한 이유가 없습니다. (하지만, 기적이 일어날 지 모르지만, 나는 가서 ... 표준 MS API를 통해 액세스 할 수 있다고 말하고 있습니까? 어느 것입니까? 아니면 드라이버를 만들고 치트를 제안 하시겠습니까?) –

+0

완전한 컨텍스트가 int 핸들러로 푸시됩니다. 잘못된 것입니다. 스택에 놓여질 수있는 유일한 것은 errorCode (옵션), eip, codesegment selector, eflags, esp 및 스택 세그먼트 선택기 (이 순서대로)입니다. 이 동작은 CPU에 하드 배선되어 있기 때문에 변경할 수 없습니다. – newgre

+0

맞습니다. 하드웨어가 일부 * 컨텍스트를 밀어 넣어야합니다. 그리고이 겸손한 금액은 괜찮습니다, 그리고 항상 내 스택 프레임에 필요한 패딩에 포함시킬 수 있습니다. FP 컨텍스트를 저장하기위한 기계 명령어가 있습니다. 신중하게 수행 된 은 스택에 포함하여 충분히 큰 버퍼에 저장할 수 있습니다. 그러나 하드웨어가 스택에 FP 컨텍스트를 밀어 넣지 않습니다. * Windows *가 그렇게하는 것 같습니다. 제 견해로 볼 때, 하드웨어 또는 Windows가 그것을 수행하는지 여부는 중요하지 않습니다. 푸시되고 스택 프레임이 작 으면 중요합니다. 중요한 것은 에 FP 컨텍스트를 푸시하지 않아도되는지 여부입니다. –

4

기본적으로 많은 인터럽트 처리기를 다시 구현해야합니다. 즉, 인터럽트 설명자 테이블 (IDT)에 직접 연결해야합니다. 문제는 kernelmode -> usermode 콜백을 다시 구현해야한다는 것입니다 (SEH의 경우이 콜백은 ntdll.dll에 있으며 이름은 KiuserExceptionDispatcher이며 모든 SEH 논리를 트리거 함). 요점은, 시스템의 나머지 부분은 SEH가 지금 당장하는 방식대로 작동하는 것에 의존하며, 시스템 전반에 걸쳐 작업을 수행했기 때문에 솔루션이 손상 될 수 있다는 것입니다. 어쩌면 인터럽트 시점에 어떤 프로세스에 있는지 확인할 수 있습니다. 그러나 전반적인 개념은 오류가 발생하기 쉽고 시스템 안정성에 큰 영향을줍니다.
이들은 실제로 루트킷과 같은 기술입니다.

편집 :
좀 더 세부 정보 : 당신은 인터럽트 핸들러를 다시 구현해야하는 이유를, 예외 (0으로 예를 들어, 나누기) 기본적으로 소프트웨어 인터럽트하고 사람들은 항상 IDT 통과있다. 예외가 발생하면 커널은 컨텍스트를 수집하고 usermode에 예외를 알립니다 (ntdll의 앞에서 설명한 KiUserExceptionDispatcher를 통해). 이 시점에서 간섭해야하므로 사용자 모드로 돌아가려면 메커니즘을 제공해야합니다. (커널 모드에서 진입 점으로 사용되는 ntdll 함수가 있습니다. 이름은 기억하지 않지만 KiUserACP를 사용하면 .....)

+0

예, 꽤 급진적입니다. 나는 OS를 패치하려고하고 있는지 잘 모르겠다. –

+0

예, 예외 처리의 전체 프로세스가 커널 모드에서 트리거되기 때문에 원하는대로 달성 할 수있는 다른 방법은 없습니다. – SDD

+0

나는 MS가 내가 가지고있는 문제의 종류를 이해하기에 충분히 똑똑하기를 바랬다. (결국 그들은 미래의 Windows 기반을 제공하지 않는다 :-), 그래서 내가해야만하는 것이 올바른 API를 사용해야한다. 운이 없다는 소리. –

1

주석 상자에 공간이 부족합니다. ..

어쨌든 나는 벡터 점이 어디인지 모르겠다. 나는 SDD의 대답과 "KiUserExceptionDispatcher"에 대한 언급을 근거로하고 있었다. 추가 검색 (http://www.nynaeve.net/?p=201)을 제외하고는 너무 늦었 어.

SIDT이 링 3에서 실행될 수 있습니다 ... 이것은 인터럽트 테이블의 내용을 나타낼 것이므로 세그먼트를로드하고 적어도 테이블의 내용을 읽을 수 있습니다. 행운을 빌어 엔트리를 (예를 들어 벡터 0/0으로 나누기) 읽고 핸들러의 내용을 읽을 수 있습니다.

이 시점에서 시스템 파일과 코드를 일치시키기 위해 16 진수 바이트를 일치 시키려고했으나 코드가 속한 파일을 확인하는 더 좋은 방법이있을 수 있습니다 (DLL이 아니어도 win32k가 될 수 있음). . sys 또는 동적으로 생성 될 수 있습니다.) 사용자 모드에서 실제 메모리 레이아웃을 덤프하는 방법이 있는지 모르겠습니다.

모두 실패하면 커널 모드 디버거를 설정하거나 Windows (Bochs)를 에뮬레이트하여 인터럽트 테이블과 메모리 레이아웃을 직접 볼 수 있습니다. 그런 다음 CONTEXT가 푸시 될 때까지 추적 할 수 있으며, 그런 상황이 발생하기 전에 제어권을 얻을 수있는 기회를 찾으십시오.

+1

I * really * * 정말로 * 커널 코드를 패치하고 싶지 않습니다. 난 그냥 MS가 내가 제공하는 버퍼에 컨텍스트를 넣으라는 요청하게, 오히려 내 현재 스택의 목구멍을 방해. –

3

매개 변수/로컬 스택을 실제 매개 변수와 분리하는 것을 고려하십시오. 다른 레지스터 (예를 들어, EBP)를 유효 스택 포인터로 사용하고, Windows가 원하는 방식으로 ESP 기반 스택을 남겨 둡니다.

더 이상 PUSH/POP을 사용할 수 없습니다. PUSH 대신 SUB/MOV/MOV/MOV 콤보를 사용해야합니다. 하지만 헤이, 운영 체제 패치를 친다.

+0

예, 기술적으로 작동합니다. 코드 밀도가 많이 떨어집니다. 내가 부동 소수점 연산이있을 때 스택 프레임을 너무 크게 만드는 대가로, 그리고/또는 프로그램이 불법 메모리 참조에 함정에 걸릴 수 있고, 좋은 백 트레이스를 제공하려는 경우, 내가 가지고있는 체계가 효과적이다. 우리는 현재 다음과 같은 두 가지 모드로 컴파일합니다 : a) 최소한의 스택 프레임 (때로는 32 바이트 정도)을 갖는 생산 모드이지만 "program died @xxx"이외의 시스템 트랩에서 복구 할 수있는 능력 및 b) 디버그 모드 MS에 충분한 슬롭을 제공하면서 각 스택 프레임에 엄청난 양 (1500 바이트)을 추가합니다. –

+0

나는 당신이 메모리를 희생시키면서 속도를 최적화하기 위해 나섰다 고 생각했다. –

+0

사용하는 명령어 세트 (특히 푸시와 팝과 같은 기본적이고 고도로 최적화 된 명령어)를 제한하여 여러 가지 명령어로 시뮬레이션을 수행하여 효과를 대체하면 속도가 향상되지 않습니다. 당신은 맞습니다. 나는 프로세서가 명령어를 가져 오는 데 놀랍도록 훌륭하다고 생각하기 때문에 실제로 코드 밀도는 신경 쓰지 않습니다. 그러나 우리가 만든 타협은 우리가 명령 집합의 어떤 부분을 사용하는 능력을 희생하지 않는다는 것을 의미합니다. MS의 무분별한 스택 관리와 교차 방식을 의미합니다. (내 질문에 * 정말 * 간단한 해결책을 제안했지만 MS가 그 일을 할 수 있을지 의심 스럽다.) –

관련 문제