![Linux에서는 분할을 사용하지 않고 페이징만 사용합니까?](https://linux55.com/image/10851/Linux%EC%97%90%EC%84%9C%EB%8A%94%20%EB%B6%84%ED%95%A0%EC%9D%84%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%A7%80%20%EC%95%8A%EA%B3%A0%20%ED%8E%98%EC%9D%B4%EC%A7%95%EB%A7%8C%20%EC%82%AC%EC%9A%A9%ED%95%A9%EB%8B%88%EA%B9%8C%3F.png)
리눅스 프로그래밍 인터페이스프로세스의 가상 주소 공간 레이아웃을 표시합니다. 그래프의 모든 영역이 선분인가요?
~에서Linux 커널에 대해 알아보기,
MMU의 분할 단위가 세그먼트와 세그먼트 내의 오프셋을 가상 메모리 주소에 매핑한 다음 페이징 단위가 가상 메모리 주소를 물리적 메모리 주소에 매핑하는 것이 맞습니까?
메모리 관리 장치(MMU)는 분할 장치라고 하는 하드웨어 회로를 통해 논리 주소를 선형 주소로 변환하고, 이어서 페이징 장치라고 하는 두 번째 하드웨어 회로가 선형 주소를 물리 주소로 변환합니다(그림 2-1 참조).
그렇다면 Linux는 왜 분할을 사용하지 않고 페이징만 사용합니까?
프로그래머가 애플리케이션을 서브루틴이나 글로벌 및 로컬 데이터 영역과 같이 논리적으로 관련된 엔터티로 분할하도록 장려하기 위해 80x86 마이크로프로세서에 분할 기능이 포함되었습니다. 하지만, Linux는 매우 제한된 방식으로 분할을 사용합니다.실제로 분할과 페이징은 둘 다 프로세스의 물리적 주소 공간을 분리하는 데 사용될 수 있기 때문에 다소 중복됩니다. 분할은 각 프로세스에 서로 다른 선형 주소 공간을 할당할 수 있고 페이징은 동일한 선형 주소 공간을 서로 다른 물리적 주소 공간에 매핑할 수 있습니다. 주소 공간. Linux는 다음과 같은 이유로 분할보다 페이징을 선호합니다.
• 모든 프로세스가 동일한 세그먼트 레지스터 값을 사용할 때(즉, 동일한 선형 주소 집합을 공유할 때) 메모리 관리가 더 간단해집니다.
• Linux의 설계 목표 중 하나는 다양한 아키텍처로 이식하는 것입니다. 특히 RISC 아키텍처는 분할을 제한적으로 지원합니다.
Linux 2.6 버전은 80x86 아키텍처에서 필요한 경우에만 분할을 사용합니다.
답변1
x86-64 아키텍처는 긴 모드(64비트 모드)에서 분할을 사용하지 않습니다.
세그먼트 레지스터 중 4개(CS, SS, DS 및 ES)는 0으로 강제 설정되고 2^64로 제한됩니다.
https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_developments
운영 체제에서 사용 가능한 "선형 주소" 범위를 더 이상 제한할 수 없습니다. 따라서 메모리 보호를 위해 분할을 사용할 수 없으며 전적으로 페이징에 의존해야 합니다.
x86 CPU의 세부 사항에 대해 걱정하지 마십시오. 레거시 32비트 모드에서 실행될 때만 적용됩니다. Linux의 32비트 모드는 많이 사용되지 않습니다. 심지어 "수년 동안 양성 방치로 고통 받았다"고 간주될 수도 있습니다. 바라보다Fedora의 32비트 x86 지원[LWN.net, 2017].
(32비트 Linux에서도 분할을 사용하지 않는 경우가 있습니다. 하지만 제 말을 믿을 필요는 없습니다. 그냥 무시하셔도 됩니다. :-).
답변2
그래프의 모든 영역이 선분인가요?
아니요.
분할 시스템(x86의 32비트 보호 모드)은 별도의 코드, 데이터 및 스택 세그먼트를 지원하도록 설계되었지만 실제로는 모든 세그먼트가 동일한 메모리 영역으로 설정됩니다. 즉, 0부터 시작하여 메모리 끝 (*) 에서 끝납니다 . 이는 논리 주소와 선형 주소를 동일하게 만듭니다.
이를 "플랫" 메모리 모델이라고 하며 내부에 별도의 세그먼트와 포인터가 있는 모델보다 간단합니다. 특히, 분할된 모델의 경우 오프셋 포인터 외에 세그먼트 선택기가 포함되어야 하므로 더 긴 포인터가 필요합니다. (16비트 세그먼트 선택기 + 32비트 오프셋, 총 48비트 포인터, 32비트 평면 포인터만.)
64비트 긴 모드는 플랫 메모리 모델을 제외하고 실제로 분할을 지원하지 않습니다.
286에서 16비트 보호 모드로 프로그래밍하려면 주소 공간은 24비트이지만 포인터는 16비트에 불과하므로 더 많은 세그먼트가 필요합니다.
(* 32비트 Linux가 커널/사용자 공간 분리를 어떻게 처리하는지 기억이 나지 않는다는 점에 유의하십시오. 분할을 사용하면 커널 공간을 포함하지 않도록 사용자 공간 세그먼트 제한을 설정하여 이를 허용합니다. 페이징은 페이지별 보호를 제공하므로 이를 허용합니다. 수준).
그렇다면 Linux는 왜 분할을 사용하지 않고 페이징만 사용합니까?
x86에는 여전히 이러한 세그먼트가 있으므로 비활성화할 수 없습니다. 그들은 가능한 한 적게 사용됩니다. 32비트 보호 모드에서는 플랫 모델에 대해 세그먼트를 설정해야 하며 64비트 모드에서도 여전히 존재합니다.
답변3
x86에는 세그먼트가 있으므로 이를 사용하지 않을 수 없습니다. 그러나 cs
(코드 세그먼트) 및 ds
(데이터 세그먼트) 기본 주소가 모두 0으로 설정되어 있으므로 세그먼트가 실제로 사용되지 않습니다. 예외는 일반적으로 사용되지 않는 세그먼트 레지스터 중 하나가 가리키는 스레드 로컬 데이터입니다. 그러나 이는 주로 이 작업을 위해 범용 레지스터 중 하나를 예약하지 않기 위한 것입니다.
Linux가 x86에서 분할을 사용하지 않는다고 말하는 것은 불가능하기 때문입니다. 그 부분을 강조하셨네요.Linux는 매우 제한된 방식으로 분할을 사용합니다.. 두 번째 부분은Linux는 80x86 아키텍처에서 필요할 때만 분할을 사용합니다.
이미 그 이유를 언급했습니다. 페이지 매김이 더 쉽고 이식성이 뛰어납니다.
답변4
Linux x86/32는 모든 세그먼트를 동일한 선형 주소 및 제한으로 초기화하므로 분할을 사용하지 않습니다. x86 아키텍처에서는 프로그램에 세그먼트가 있어야 합니다. 코드는 코드 세그먼트에서만 실행될 수 있고, 스택은 스택 세그먼트에만 위치할 수 있으며, 데이터는 데이터 세그먼트 중 하나에서만 조작될 수 있습니다. Linux는 동일한 논리 주소가 모든 세그먼트에서 유효하도록 모든 세그먼트를 동일한 방식으로 설정하여(책에 언급되지 않은 예외는 제외) 이 메커니즘을 우회합니다. 이는 사실상 세그먼트가 전혀 없다는 의미입니다.