2013-10-05 2 views
1

예를 들어 프로그램에서 foo() 함수를 호출했습니다. 컴파일러와 어셈블러는 결국 jmp someaddr을 이진 파일에 작성합니다. 나는 가상 메모리의 개념을 안다. 프로그램은 전체 메모리를 처분 할 수 있다고 생각하고 시작 위치는 0x000입니다. 이 방법으로 어셈블러는 foo()의 위치를 ​​계산할 수 있습니다.OS는 어떻게 가상 메모리에서 바이너리 파일을 실행합니까?

사실 이것은 런타임까지 올바르게 결정되지 않습니까? 프로그램을 어디에로드했는지 알기 위해 프로그램을 실행해야합니다. 따라서 주소는 jmp입니다. 그러나 프로그램이 실제로 실행될 때 OS가 어떻게 들어오고 jmp의 주소를 변경합니까? 이것들은 바로 직접 CPU 명령어입니까?

+0

http://en.wikipedia.org/wiki/Memory_management_unit – Thomas

+0

"상대적으로 점프"라는 개념을 이해하고 있습니까? – Floris

+2

프로그래밍 질문이 아닌 OS 디자인 질문처럼 들립니다. 응답은 주소 공간이 가상이기 때문에 프로그램이 원하는만큼 정확하게로드된다는 것을 알 수 있습니다. 가상 어드레싱의 마법입니다. –

답변

6

이 질문은 완전히 하드웨어 및 OS에 의존하기 때문에 일반적으로 대답 할 수 없습니다. 그러나 일반적인 대답은 처음에로드 된 프로그램을 컴파일 할 수 있다는 것입니다. VM 하드웨어가 각 프로그램에 자체 주소 공간을 제공하기 때문에 프로그램 링크시 모든 주소를 고정시킬 수 있습니다. 로드 할 때 주소를 다시 계산할 필요가 없습니다.

처음로드 된 동일한 프로그램에서 사용되는 두 개가 동일한 기본 주소로 컴파일되어 주소 공간이 겹치기 때문에 동적으로로드 된 라이브러리에서 더욱 흥미로운 점이 있습니다.

이 문제에 대한 한 가지 방법은 DLL에 위치 독립적 코드가 필요하다는 것입니다. 이러한 코드에서 모든 주소는 코드 자체와 관련됩니다. 점프는 일반적으로 PC와 관련이 있습니다 (코드 세그먼트 레지스터를 사용할 수도 있음). 데이터는 또한 일부 데이터 세그먼트 또는 기본 레지스터와 관련이 있습니다. 런타임 위치를 선택하려면 PIC 코드 자체가 변경 될 필요가 없습니다. 세그먼트 또는 기본 레지스터 만 모든 DLL 루틴의 서곡에서 설정해야합니다.

추가 주소 계산이 있고 PC 및/또는 기본 레지스터가 프로세서의 명령 파이프 라인에 병목을 일으킬 수 있기 때문에 PIC는 위치 종속 코드보다 약간 느려지는 경향이 있습니다.

그래서 다른 방법은 로더가 주소 공간 오버랩을 제거하기 위해 필요한 경우 DLL 코드를 리베이스하는 것입니다. 이를 위해 DLL에는 코드의 모든 절대 주소 테이블이 있어야합니다. 로더는 가정 된 코드와 실제 주소 사이의 오프셋을 계산하고 실제 값을 계산 한 다음 테이블을 탐색하여 프로그램이 VM에 복사 될 때 각 절대 주소에 오프셋을 더합니다.

DLL에는 호출 프로그램이 라이브러리 프로 ​​시저가 시작되는 위치를 알 수 있도록 진입 점 테이블이 있습니다. 또한 조정해야합니다.

리베이스는 성능면에서 좋지 않습니다. 로드 속도가 느려집니다. 또한, 그것은 DLL 코드의 공유를 패배시킵니다. 리베이스 오프셋 당 적어도 하나의 사본이 필요합니다.

이러한 이유로 Windows의 일부인 DLL은 중첩되지 않는 VM 주소 공간으로 고의적으로 컴파일됩니다. 로딩 속도가 빨라지고 공유가 가능합니다. C 런타임 라이브러리와 같은 MS DLL이 빠르게로드되는 반면 타사 DLL이 디스크를 크 런치하고 느리게로드되는 것을 확인한 경우 Windows에서 리베이스의 효과가 나타납니다.

이 항목에 대한 자세한 내용은 개체 파일 형식을 참조하십시오. Here is one example.

2

위치 독립적 코드은 임의의 주소에서 실행할 수있는 코드입니다. 위치 독립적 코드에 jmp 명령어가있는 경우에는 종종 상대 점프가되어 현재 위치에서 오프셋으로 이동합니다. 코드를 복사 할 때 코드 부분 사이의 오프셋은 변경되지 않으므로 여전히 작동합니다.

relocatable 코드은 임의의 주소에서 실행할 수있는 코드이지만 먼저 코드를 수정해야 할 수도 있습니다 (복사 할 수없는 경우도 있음). 코드에는 수정해야하는 방법을 알려주는 재배치 테이블이 있습니다.

재배치 불가능 코드은 특정 주소에로드해야하는 코드이거나 작동하지 않습니다.

각 프로그램은 프로그램이 작성된 방법, 컴파일러 설정 또는 기타 다양한 요소에 따라 다릅니다.

  • 공유 라이브러리는 보통 메모리에 여러 개를로드하지 않고, 동일한 라이브러리는 다른 공정에서 다른 위치에 장착 될 수 있도록 위치 독립 코드로 컴파일된다. 각 프로세스의 다른 주소에 있더라도 동일한 복사본을 프로세스간에 공유 할 수 있습니다.

  • 실행 파일은 대체 할 수 없지만 위치 독립적 일 수 있습니다. 가상 메모리는 각 프로그램이 전체 주소 공간 (약간의 오버 헤드를 뺀)을 가지고 있기 때문에 각 실행 파일은 다른 실행 파일과의 충돌을 걱정하지 않고로드 된 주소를 선택할 수 있습니다. 일부 실행 파일은 위치 독립적이므로 보안을 강화하는 데 사용할 수 있습니다 (ASLR).

  • 일반적으로 오브젝트 파일과 정적 라이브러리는 재배치 가능한 코드입니다. 링커는이를 결합하여 공유 라이브러리, 실행 파일 또는 다른 이미지를 만들 때 파일을 재배치합니다.

  • 부트 로더와 운영 체제 커널은 거의 항상 재배치가 불가능합니다.

0

예, 런타임시입니다. 운영 체제, 시작 및 전환 작업을 관리하는 부분은 이상적으로 다른 보호 수준에 있으며 더 많은 전력을 소비합니다. 사용중인 메모리를 알고 새 태스크에 할당합니다. 새 작업이 0에서 시작하는 가상 주소 공간을 갖거나 해당 운영 체제 및 프로세서에 대한 규칙이 무엇이든간에 mmu를 구성합니다. 시작 주소에서 사용자 모드로 들어가는 방법은 매우 프로세서에 따라 다릅니다.

예를 들어, 하드웨어가 인터럽트가 발생할 때 하드웨어가 주소뿐 아니라 모드 나 가상 ID 등의 일부 상태를 저장할 수도 있습니다. 그리고 그 프로세서에 의해 정의 된 인터럽트 명령으로부터의 복귀는 스택의 주소와 상태/모드를 취하고 그곳에서 스위치를 둡니다 (이전에 없었던 새로운 모드에 기반한 다음 페치에 대해 mmu가 반응하도록합니다). 그런 다음 작동하는 프로세서의 경우 스택에 올바른 항목을 배치하여 인터럽트 리턴을 가짜로 만들 수 있습니다. 따라서 인터럽트 리턴 명령을 실행하면 기본적으로 모드 전환 등의 추가 기능으로 점프를 수행합니다.

예를 들어 cortex-m이 아닌 ARM 계열에는 현재 실행중인 작업 (인터럽트 또는 서비스 호출의 경우)과 출처의 두 번째 상태 레지스터 인 프로세서 상태 레지스터가 있습니다 인터럽트가 발생하면 적절한 리턴을 할 때 주소를주고 다른 레지스터를 사용하여 해당 모드로 다시 전환합니다. 비 사용자 모드에서 해당 레지스터에 직접 액세스 할 수 있으므로 반환 상태를 조작 할 수 있습니다. 복귀 명령은 팔에 없으며 점프의 맛 (프로그램 카운터 수정)이므로 특별한 종류의 점프입니다.

짧은 대답은 가상 주소 공간의 응용 프로그램 모드에서 작업을 실행중인 작업으로 전환 한 후 처음으로 건너 뛰거나 돌아온 후 선택으로 돌아 오는 것의 선택이 프로세서와 매우 관련 있다는 것입니다. 직접 또는 간접적으로 프로세서 설명서에 이러한 모드와 변경 방법이 설명되어 있습니다. 명시 적으로 설명되지 않은 경우 지시 사항과 mmu 보호 및 작업 전환 방법과 같은 사항을 스스로 알아야합니다.

관련 문제