프로그램을 열 때 운영 체제가 자체 기계 코드를 삽입합니까?


32

CPU를 연구하고 있는데 메모리에서 프로그램을 읽고 명령을 실행하는 방법을 알고 있습니다. 또한 OS는 프로세스에서 프로그램을 분리 한 다음 각 프로그램을 너무 빨리 번갈아 실행하여 동시에 실행되고 있다고 생각하지만 실제로는 각 프로그램이 CPU에서 단독으로 실행됩니다. 그러나 OS가 CPU에서 실행되는 많은 코드 인 경우 프로세스를 어떻게 관리 할 수 ​​있습니까?

내가 생각하고 유일하게 생각할 수있는 설명은 : OS가 외부 메모리에서 RAM으로 프로그램을로드 할 때 원래 프로그램 명령의 중간에 자체 명령을 추가하므로 프로그램이 실행됩니다. OS를 호출하고 몇 가지 작업을 수행 할 수 있습니다. 나는 OS가 프로그램에 추가 할 것이라는 지시가 있다고 생각한다. 또한 OS가 프로그램을로드 할 때 메모리에 금지 된 주소로 이동하는 금지 된 명령이 있는지 확인한 다음 제거합니다.

나는 rigth를 생각하고 있는가? 저는 CS 학생이 아니라 실제로 수학 학생입니다. 가능한 경우, OS가 CPU에서 실행되는 많은 코드이고 OS에서 동일하게 실행될 수없는 경우 OS가 프로세스를 관리하는 방법을 설명하는 사람을 찾지 못했기 때문에 이에 관한 좋은 책을 원합니다. 프로그램 시간. 이 책은 OS가 사물을 관리 할 수 ​​있다고 말하지만 이제는 방법을 알려줍니다.


7
참조 : 컨텍스트 전환 OS는 앱에 대한 컨텍스트 전환을 수행합니다. 그런 다음 앱은 OS에 대한 컨텍스트를 수행하는 OS 서비스를 요청할 수 있습니다. 앱이 종료되면 컨텍스트가 다시 OS로 전환됩니다.
가이 코더

4
"syscall"도 참조하십시오.
라파엘


1
의견과 답변이 이해 나 만족도에 대한 귀하의 질문에 대한 답변이 아닌 경우, 의견으로 더 많은 정보를 요청하고 귀하가 생각하고 있거나 분실 한 곳 또는 구체적으로 필요한 것이 무엇인지 설명하십시오.
가이 코더

2
내 생각 인터럽트 , 접선 (인터럽트의) 하드웨어 타이머 (와 일정 -handling 후크) 및 페이징 (금지 된 메모리에 대한 당신의 발언에 대한 부분적인 대답은) 당신이 필요로하는 주요 키워드입니다. OS는 프로세서와 긴밀히 협력하여 필요할 때만 코드를 실행해야합니다. 따라서 대부분의 CPU 성능은 관리가 아닌 실제 계산에 사용될 수 있습니다.
Palec

답변:


35

아니요. 운영 체제는 새 코드를 삽입하는 프로그램 코드로 혼란스럽지 않습니다. 그것은 많은 단점이 있습니다.

  1. OS가 전체 실행 파일을 스캔하여 변경해야하므로 시간이 많이 걸립니다. 일반적으로 실행 파일의 일부는 필요한 경우에만로드됩니다. 또한 많은 양의 물건을 방해하지 않으면 서 삽입 비용이 많이 듭니다.

  2. 중지 문제의 결정 불가능 성으로 인해 "OS로 돌아 가기"명령을 삽입 할 위치를 알 수 없습니다. 예를 들어, 코드에와 같은 것이 포함 된 경우 while (true) {i++;}해당 루프 안에 후크를 삽입해야하지만 루프의 조건 ( true여기, 여기)은 임의로 복잡 할 수 있으므로 루프 기간을 결정할 수 없습니다. 반면에 모든 루프에 후크를 삽입하는 것은 매우 비효율적 입니다. 예를 들어, OS로 되돌아 가면 for (i=0; i<3; i++) {j=j+i;}프로세스 속도가 크게 느려집니다. 같은 이유로 짧은 루프를 감지하여 홀로 남겨 둘 수는 없습니다.

  3. 중지 문제의 결정 불가능으로 인해 코드 삽입으로 인해 프로그램의 의미가 바뀌 었는지 알 수 없습니다. 예를 들어, C 프로그램에서 함수 포인터를 사용한다고 가정하십시오. 새 코드를 삽입하면 함수의 위치가 이동하므로 포인터를 통해 호출하면 잘못된 위치로 이동합니다. 프로그래머가 계산 된 점프를 사용하기에 충분히 아프면 실패합니다.

  4. 바이러스 코드도 변경하고 모든 체크섬을 제거하기 때문에 모든 안티 바이러스 시스템에서 즐거운 시간을 보낼 수 있습니다.

고정 된 횟수 이상 실행되는 루프에 코드를 시뮬레이션하고 후크를 삽입하여 정지 문제를 해결할 수 있습니다. 그러나 실행하기 전에 전체 프로그램에 대해 매우 비싼 시뮬레이션이 필요합니다.

실제로 코드를 삽입하려면 컴파일러가 자연스럽게 처리해야합니다. 그렇게하면 한 번만 수행하면되지만 위의 두 번째 및 세 번째 이유로 여전히 작동하지 않습니다. (그리고 누군가는 따라 가지 않는 컴파일러를 작성할 수 있습니다.)

OS가 프로세스에서 제어권을 다시 얻는 방법에는 세 가지가 있습니다.

  1. 협력 적 (또는 비선 점적) 시스템 yield에는 프로세스가 호출하여 OS에 제어권을 부여 할 수 있는 기능이 있습니다. 물론 이것이 유일한 메커니즘이라면, 당신은 잘 동작하는 프로세스에 의존하고 있으며, 양보하지 않는 프로세스는 CPU가 종료 될 때까지 CPU를 낭비합니다.

  2. 이 문제를 피하기 위해 타이머 인터럽트가 사용됩니다. CPU를 통해 OS는 CPU가 구현하는 모든 다른 유형의 인터럽트에 대한 콜백을 등록 할 수 있습니다. OS는이 메커니즘을 사용하여 주기적으로 발생하는 타이머 인터럽트에 대한 콜백을 등록하여 자체 코드를 실행할 수 있습니다.

  3. 프로세스가 파일을 읽거나 다른 방식으로 하드웨어와 상호 작용할 때마다 OS가 파일을 처리하도록 요구합니다. OS가 프로세스에 의해 무언가를하도록 요청 받으면, 프로세스를 보류하고 다른 프로세스를 실행하기로 결정할 수 있습니다. 약간의 Machiavellian 소리가 들릴 수도 있지만, 옳은 일입니다. 디스크 I / O가 느리므로 프로세스 A가 회전하는 금속 덩어리가 올바른 위치로 이동하기를 기다리는 동안 프로세스 B가 실행되도록 할 수도 있습니다. 네트워크 I / O가 더 느립니다. 사람들이 기가 헤르츠가 아니기 때문에 키보드 I / O는 빙하입니다.


5
마지막 2. 포인트에서 더 많은 것을 개발할 수 있습니까? 이 질문이 궁금해서 여기 설명이 생략 된 것 같습니다. 문제는 "OS가 프로세스에서 CPU를 가져 오는 방법"이라는 질문과 같으며 대답은 "OS가 처리합니다"라고 말합니다. 그러나 어떻게? 첫 번째 예에서 무한 루프를 수행하십시오. 컴퓨터가 어떻게 정지되지 않습니까?
BiAiB

3
일부 OS는 대부분의 OS가 최소한 "링크"를 수행하기위한 코드로 혼란스러워 프로그램을 어떤 주소로든로드 할 수 있습니다
Ian Ringrose

1
@BiAiB 여기서 핵심은 "인터럽트"입니다. CPU는 주어진 명령 스트림을 처리하는 것이 아니라 별도의 소스에서 비동기식으로 인터럽트 할 수 있습니다. 가장 중요한 것은 우리에게 I / O 및 클럭 인터럽트입니다. 커널 공간 코드 만 인터럽트를 처리 할 수 ​​있기 때문에 Windows는 언제든지 실행중인 프로세스에서 작업을 "훔칠"수 있습니다. 인터럽트 핸들러는 "CPU의 레지스터를 어딘가에 저장하고 여기에서 (다른 스레드) 복원"을 포함하여 원하는 코드를 실행할 수 있습니다. 매우 단순화되었지만 컨텍스트 전환입니다.
Luaan

1
이 답변에 추가; 포인트 2와 3에서 언급 된 멀티 태스킹 스타일을 "선점 형 멀티 태스킹"이라고하며, 이름은 운영 체제가 실행중인 프로세스를 선점 할 수있는 능력을 나타냅니다. 협동 멀티 태스킹은 구형 운영 체제에서 자주 사용되었습니다. Windows에서는 최소한 선점 형 멀티 태스킹이 Windows 95까지 도입되지 않았습니다. 현재 실시간 협력 멀티 태스킹 동작에만 Windows 3.1을 사용하는 하나 이상의 산업 제어 시스템을 읽었습니다.
Jason C

3
@BiAiB 사실, 당신은 틀 렸습니다. 데스크탑 CPU는 i486 이후부터 순차적으로 동 기적으로 코드를 실행하지 않습니다. 그러나 이전 CPU조차도 여전히 비동기 입력-인터럽트가있었습니다. CPU 자체의 핀처럼 IRQ (하드웨어 인터럽트 요청)를 상상해보십시오. 1CPU가 수신되면 CPU가 수행중인 작업을 중지하고 인터럽트 처리를 시작합니다 (기본적으로 "상태 유지 및 메모리의 주소로 이동"을 의미 함). 인터럽트 처리 자체는 x86코드 가 아니 거나 코드에 관계없이 문자 그대로 고정되어 있습니다. 점프 후 다시 (임의의) x86코드를 실행 합니다. 스레드는 더 높은 추상화입니다.
Luaan

12

David Richerby의 대답은 좋은 것이지만 현대 운영 체제가 기존 프로그램을 중지시키는 방식에 대해서는 유약합니다. 제 답변은 x86 또는 x86_64 아키텍처에 대해 정확해야합니다. x86 또는 x86_64 아키텍처는 데스크톱 및 랩톱에서 일반적으로 사용되는 유일한 아키텍처입니다. 다른 아키텍처에서도 이와 비슷한 방법을 사용해야합니다.

운영 체제가 시작되면 인터럽트 테이블이 설정됩니다. 테이블의 각 항목은 운영 체제 내부의 약간의 코드를 가리 킵니다. CPU에 의해 제어되는 인터럽트가 발생하면이 테이블을보고 코드를 호출합니다. 0으로 나누기, 유효하지 않은 코드 및 일부 운영 체제 정의 인터럽트와 같은 다양한 인터럽트가 있습니다.

디스크에서 읽기 / 쓰기를 원하거나 운영 체제 커널이 제어하는 ​​다른 것과 같이 사용자 프로세스가 커널과 통신하는 방법입니다. 운영 체제는 또한 완료 될 때 인터럽트를 호출하는 타이머를 설정하므로 실행중인 코드는 사용자 프로그램에서 운영 체제 커널로 강제 변경되며 커널은 실행을 위해 다른 프로그램을 대기열에 넣는 것과 같은 다른 작업을 수행 할 수 있습니다.

메모리에서 이러한 상황이 발생하면 운영 체제 커널은 코드의 위치를 ​​저장해야하며 커널이 필요한 작업을 완료하면 프로그램의 이전 상태를 복원합니다. 따라서 프로그램은 중단되었음을 알지 못합니다.

프로세스는 두 가지 이유로 인터럽트 테이블을 변경할 수 없습니다. 첫 번째는 보호 환경에서 실행되고 있기 때문에 특정 보호 어셈블리 코드를 호출하려고하면 CPU가 다른 인터럽트를 트리거한다는 것입니다. 두 번째 이유는 가상 메모리입니다. 인터럽트 테이블의 위치는 실제 메모리에서 0x0 ~ 0x3FF이지만 사용자 프로세스에서는 일반적으로 해당 위치가 매핑되지 않으며 매핑되지 않은 메모리를 읽으려고하면 다른 인터럽트가 발생하므로 보호 된 기능과 실제 RAM에 쓸 수있는 기능이 없습니다. 사용자 프로세스는이를 변경할 수 없습니다.


4
인터럽트는 운영 체제에 의해 정의되지 않으며 하드웨어에 의해 제공됩니다. 그리고 대부분의 최신 아키텍처에는 운영 체제를 호출하기위한 특별한 지침이 있습니다. i386은이를 위해 (소프트웨어 생성) 인터럽트를 사용했지만 더 이상 후속 작업에서는 수행되지 않습니다.
vonbrand

2
인터럽트는 CPU에 의해 정의된다는 것을 알고 있지만 커널은 포인터를 설정합니다. 나는 아마 그것을 잘못 설명했다. 또한 리눅스가 int 9를 사용하여 커널과 계속 대화한다고 생각했지만 더 나은 방법이있을 수 있습니다.
Programmdude

선점 스케줄러가 타이머 인터럽트에 의해 구동된다는 개념은 정확하지만 이것은 오해의 소지가있는 답변입니다. 먼저 타이머가 하드웨어에 있다는 것을 주목할 가치가 있습니다. 또한 "저장 ... 복원"프로세스를 컨텍스트 스위치라고하며, 특히 모든 CPU 레지스터 (명령 포인터 포함)를 저장하는 것을 포함합니다. 또한 프로세스 인터럽트 테이블을 효과적으로 변경할 수 있습니다. 이를 "보호 모드"라고하며 가상 메모리도 정의하며 286 이후 인터럽트 테이블에 대한 포인터가 쓰기 가능한 레지스터에 저장됩니다.
Jason C

(또한 실제 모드 인터럽트 테이블도 8086 이후 메모리의 첫 페이지에 고정되지 않고 재배치 가능합니다.)
Jason C

1
이 답변에는 중요한 세부 사항이 없습니다. 인터럽트가 발생하면 CPU는 커널로 직접 전환되지 않습니다. 대신, 먼저 기존 레지스터를 저장 한 다음 다른 스택으로 전환 한 다음 커널 만 호출합니다. 임의의 프로그램에서 임의의 스택으로 커널을 호출하는 것은 다소 나쁜 생각입니다. 또한 마지막 부분은 오도의 소지가 있습니다. 매핑되지 않은 메모리를 읽기위한 "시도"인터럽트가 발생하지 않습니다. 단순히 불가능합니다. 가상 주소에서 읽고 매핑되지 않은 메모리에는 가상 주소가 없습니다.
MSalters

5

OS 커널은 프로세스에 코드를 삽입하지 않고 CPU 클록 인터럽트 핸들러로 인해 실행중인 프로세스에서 제어권을 다시 얻습니다.

인터럽트의 작동 방식과 OS 커널이 인터럽트 를 처리하고 다른 기능을 구현하는 방법에 대한 자세한 정보를 얻으려면 인터럽트 에 대해 읽어야 합니다.


클록 인터럽트뿐만 아니라 모든 인터럽트. 또한 모드 변경 지침.
Gilles 'SO- 악마 그만해'

3

있다 : 당신이 설명하는 것과 유사한 방법 협동 멀티 태스킹 . OS는 명령어를 삽입하지 않지만, 다른 협력 프로세스를 실행하도록 선택할 수있는 OS 기능을 호출하도록 각 프로그램을 작성해야합니다. 이것은 당신이 설명하는 단점이 있습니다 : 하나의 프로그램 충돌은 전체 시스템을 제거합니다. 3.0 이하의 Windows는 다음과 같이 작동했습니다. "보호 모드"이상의 3.0에서는 그렇지 않습니다.

선점 형 멀티 태스킹 (요즘 일반적인 종류)은 외부 인터럽트 소스에 의존합니다. 인터럽트는 일반적인 제어 흐름을 무시하고 일반적으로 레지스터를 어딘가에 저장하므로 CPU가 다른 작업을 수행 한 다음 프로그램을 투명하게 다시 시작할 수 있습니다. 물론 운영 체제는 "인터럽트를 다시 시작할 때"레지스터를 변경하여 다른 프로세스 내에서 다시 시작할 수 있습니다.

(일부 시스템 "thunking"이라고하는 프로그램로드시 제한된 방식으로 명령을 다시 작성하며 Transmeta 프로세서는 자체 명령 세트로 동적으로 재 컴파일됩니다)


AFAICR 3.1도 협력 적이었습니다. Win95는 선점 형 멀티 태스킹이 시작된 곳입니다. 보호 모드는 주로 주소 공간을 분리했습니다 (이는 안정성을 향상 시키지만 크게 관련이없는 이유로).
cHao

Thunking은 애플리케이션에 코드를 다시 쓰거나 삽입하지 않습니다. 수정 된 로더는 OS 기반이며 응용 프로그램의 제품이 아닙니다. JIT 컴파일러 사용과 같이 컴파일 된 해석 언어는 코드를 수정하지 않으며 코드에 어떤 것도 삽입하지 않습니다. 소스 코드를 실행 파일로 변환합니다. 다시 말하지만 이것은 응용 프로그램에 코드를 주입하는 것과 다릅니다.
Dave Gordon

Transmeta는 해석 언어가 아닌 x86 실행 코드를 소스로 사용했습니다. 그리고 코드 주입 되는 한 가지 경우를 생각했습니다 . 디버거에서 실행 중입니다. X86 시스템은 일반적으로 중단 점에서 명령어를 "INT 03"으로 덮어 쓰고 디버거에 갇 힙니다. 다시 시작하면 원래 opcode가 복원됩니다.
pjc50

디버깅은 누군가가 응용 프로그램을 실행하는 방식이 아닙니다. 응용 프로그램 개발자의 그것 이상으로. 그래서 나는 그것이 OP에 실제로 도움이되지 않는다고 생각합니다.
Dave Gordon

3

멀티 태스킹에는 코드 삽입과 같은 것이 필요하지 않습니다. Windows와 같은 운영 체제에는 스케줄러라고하는 운영 체제 코드의 구성 요소가 있으며, 이는 하드웨어 타이머에 의해 트리거 된 하드웨어 인터럽트에 의존합니다. 이것은 운영 체제에서 다른 프로그램과 그 자체로 전환하는 데 사용되므로 인간의 인식이 동시에 발생하는 것처럼 보입니다.

기본적으로 운영 체제는 하드웨어 타이머가 너무 자주 (초당 100 회) 꺼 지도록 프로그래밍합니다. 타이머가 꺼지면 하드웨어 인터럽트가 발생하여 CPU가 수행중인 작업을 중지하고 스택의 상태를 저장하며 모드를 더 특권이있는 것으로 변경하고 특별히 지정된 코드를 실행하도록 지시하는 신호 기억에 두십시오. 이 코드는 스케줄러의 일부로 발생하여 다음에 수행 할 작업을 결정합니다. 다른 프로세스를 재개해야 할 수도 있습니다.이 경우 "컨텍스트 스위치"라고하는 것을 수행해야합니다. 현재 상태 (가상 메모리 테이블 포함) 전체를 다른 프로세스의 상태로 바꿔야합니다. 프로세스로 돌아 가면 해당 프로세스의 모든 컨텍스트를 복원해야합니다.

메모리에서 "특별히 지정된"장소는 운영 체제 이외의 다른 것으로 알려질 필요가 없습니다. 구현은 다양하지만, 요점은 CPU가 테이블 조회를 수행하여 다양한 인터럽트에 응답한다는 것입니다. 테이블의 위치는 메모리의 특정 위치 (CPU의 하드웨어 설계에 의해 결정됨)에 있으며 테이블의 내용은 운영 체제에 의해 설정되며 (일반적으로 부팅시) 인터럽트의 "유형"에 따라 어떤 항목이 결정됩니다 표에서 "인터럽트 서비스 루틴"으로 사용됩니다.

이 중 어느 것도 "코드 삽입"과 관련이 없습니다. CPU 및 하드웨어의 하드웨어 기능과 함께 운영 체제에 포함 된 코드를 기반으로합니다.


2

필자가 설명하는 것과 가장 가까운 실제 사례는 VMware 에서 사용하는 기술 중 하나 인 바이너리 변환을 사용한 전체 가상화 라고 생각합니다 .

VMware는 동일한 하드웨어에서 하나 이상의 운영 체제를 동시에 실행하는 계층 역할을합니다.

(예를 들어 일반 응용 프로그램에서) 실행되는 대부분의 명령어는 하드웨어를 사용하여 가상화 할 수 있지만 OS 커널 자체는 가상화 할 수없는 명령어를 사용합니다. "는 VMware 호스트의 제어 권한입니다. 예를 들어 게스트 OS는 가장 권한이 높은 보호 링에서 실행하고 인터럽트 테이블을 설정해야합니다. 그렇게 할 수 있다면 VMware는 하드웨어에 대한 통제력을 상실했을 것입니다.

VMware는 명령을 실행하기 전에 OS 코드에서 해당 명령을 다시 작성하여 원하는 효과를 시뮬레이션하는 VMware 코드로 이동합니다.

따라서이 기술은 설명하는 것과 다소 유사합니다.


2

운영 체제가 프로그램에 "코드를 삽입"할 수있는 다양한 경우가 있습니다. Apple Macintosh 시스템의 68000 기반 버전은 모든 세그먼트 진입 점 테이블 (정적 전역 변수 IIRC 바로 앞에 위치)을 구성합니다. 프로그램이 시작되면 테이블의 각 항목은 트랩 명령과 세그먼트 번호 및 세그먼트로의 오프셋으로 구성됩니다. 트랩이 실행되면 시스템은 트랩 명령 다음에 나오는 단어를보고 필요한 세그먼트 및 오프셋을 확인하고 세그먼트를로드하고 (아직 그렇지 않은 경우) 세그먼트의 시작 주소를 오프셋에 추가합니다. 그런 다음 트랩을 새로 계산 된 주소로 이동하십시오.

구형 PC 소프트웨어에서는 "OS"에 의해 기술적으로 수행되지 않았지만 코 프로세서 수학 명령어 대신 트랩 명령어를 사용하여 코드를 작성하는 것이 일반적이었습니다. 수학 보조 프로세서가 설치되어 있지 않으면 트랩 처리기가이를 처리합니다. 보조 프로세서가 설치된 경우 트랩을 처음 가져 오면 처리기는 트랩 명령어를 보조 프로세서 명령어로 바꿉니다. 나중에 동일한 코드를 실행할 때는 보조 프로세서 명령어를 직접 사용합니다.


FP 방법은 ARM 프로세서에서 여전히 사용 중이며 x86 CPU와 달리 FP가없는 변형이 있습니다. 그러나 대부분의 ARM 사용이 전용 장치에서 사용되는 경우는 거의 없습니다. 이러한 환경에서는 일반적으로 CPU에 FP 기능이 있는지 여부가 알려져 있습니다.
MSalters

이 두 경우 모두 OS가 코드를 응용 프로그램에 삽입하지 않았습니다. OS가 코드를 삽입하려면 소프트웨어 공급 업체가 얻지 못한 응용 프로그램을 "수정"하려면 라이센스가 필요합니다. OS는 코드를 삽입하지 마십시오.
Dave Gordon

@DaveGordon 트랩 된 명령어는 애플리케이션에 OS 주입 코드라고 합리적으로 말할 수 있습니다.
Gilles 'SO- 악한 중지'

@MSalters 트랩 된 명령어는 가상 컴퓨터에서 일반적으로 발생합니다.
Gilles 'SO- 악한 중지'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.