x86 메모리 세그멘테이션
x86 memory segmentationx86 메모리 세그멘테이션은 인텔 x86 컴퓨터 명령 세트 아키텍처에서의 메모리 세그멘테이션 구현을 의미합니다.세그먼트화는, 프로그램이 64 KB(65,536 바이트) 이상의 메모리를 주소 지정할 수 있도록 하는 방법으로, 1978년에 인텔 8086에 도입되었습니다.인텔 80286은 1982년에 가상 메모리와 메모리 보호를 지원하는 두 번째 버전의 세그멘테이션을 도입했습니다.이 시점에서 원래 모델의 이름은 real mode로 변경되었으며 새 버전은 protected mode로 지정되었습니다.2003년에 도입된 x86-64 아키텍처는 64비트 모드의 세그먼트화 지원을 거의 중단했습니다.
실제 모드와 보호 모드 모두에서 시스템은 16비트 세그먼트 레지스터를 사용하여 실제 메모리 주소를 도출합니다.리얼 모드에서는 CS, DS, SS 및 ES 포인트는 현재 사용되고 있는 프로그램코드 세그먼트(CS), 현재 데이터 세그먼트(DS), 현재 스택 세그먼트(SS) 및 프로그래머(ES)에 의해 결정된1개의 추가 세그먼트에 등록됩니다.1985년에 도입된 인텔 80386은 하드웨어에 의해 정의된 용도 없이 FS와 GS라는2개의 세그먼트 레지스터를 추가합니다.세그먼트 레지스터를 사용하는 방법은 두 [1]모드에 따라 다릅니다.
세그먼트의 선택은 일반적으로 실행 중인 기능에 따라 프로세서에 의해 기본 설정됩니다.명령은 항상 코드 세그먼트에서 가져옵니다.스택 푸시 또는 팝 또는 스택을 참조하는 모든 데이터 참조는 스택세그먼트를 사용합니다.데이터에 대한 다른 모든 참조는 데이터 세그먼트를 사용합니다.추가 세그먼트는 문자열 동작의 기본 수신처입니다(MOVS 나 CMPS 등).FS 및 GS는 하드웨어에 할당된 용도가 없습니다.명령 형식을 사용하면 원하는 [2]경우 선택한 명령의 기본 세그먼트를 재정의하는 데 사용할 수 있는 선택적 세그먼트 접두사 바이트를 사용할 수 있습니다.
리얼 모드
리얼 모드 또는 V86 모드에서는 세그먼트 크기가 1바이트에서 65,536바이트(16비트 오프셋 사용)까지 가능합니다.
세그먼트 레지스터의 16비트세그먼트 셀렉터는 세그먼트주소라고 불리는 선형 20비트주소의 최상위 16비트로 해석됩니다.그 중 나머지 4개의 최하위 비트는 모두0입니다.세그먼트 주소는 항상 이 모드의 물리 주소와 동일한 선형 주소를 생성하는 명령에서 16비트 오프셋에 추가됩니다.예를 들어 세그먼트 주소 06은EFh:1234h(여기서 접미사 "h"는 16진수를 의미함)의 세그먼트 셀렉터는 06EF0h로, 오프셋이 추가되어 선형 주소 06EF0h + 1234h = 08124h가 됩니다.
0000 0110 1110 1111 0000 | 세그먼트, | 16비트, 4비트 왼쪽으로 이동(또는 0x10으로 곱) |
+ 0001 0010 0011 0100 | 오프셋, | 16비트 |
| ||
0000 1000 0001 0010 0100 | 주소, | 20비트 |
세그먼트 주소와 오프셋이 추가되는 방식 때문에 단일 선형 주소를 최대 212 = 4096개의 개별 세그먼트:420 쌍에 매핑할 수 있습니다.예를 들어, 선형 주소 08124h는 세그먼트 주소 06을 가질 수 있습니다.EFh:1234h, 0812h:0004h, 0000h:8124h 등
이는 고유한 어드레싱 방식에 익숙한 프로그래머에게 혼란을 줄 수 있지만, 예를 들어 여러 개의 중첩된 데이터 구조를 어드레싱할 때 이점에 사용할 수도 있습니다.리얼 모드 세그먼트의 길이는 항상 64KB이지만 실제로는 세그먼트의 길이가 64KB를 넘지 않는 것이 아니라 세그먼트의 길이가 64KB를 넘지 않는 것이 효과적입니다.리얼 모드에서는 보호나 특권의 제한이 없기 때문에 세그먼트를 64KB 미만으로 정의할 수 있어도, 모든 프로그램이 항상 메모리에 액세스 할 수 있기 때문에(세그먼트광고를 변경하도록 세그먼트 셀렉터를 임의로 설정할 수 있기 때문에), 세그먼트의 범위내에서 조정하고 유지하는 것은 여전히 전적으로 프로그램에 달려 있습니다.감시가 전혀 없는 드레스).따라서 리얼 모드는 CPU에 의해 강제되지 않는1 ~ 65,536 바이트의 각 세그먼트의 가변 길이를 갖는 것과 마찬가지로 생각할 수 있습니다.
(선상 주소, 세그먼트주소, 세그먼트필드와 오프셋필드의 선두 0이 여기에 표시되어 알기 쉽게 알 수 있습니다.보통 생략됩니다).
리얼 모드의 유효 20비트주소 공간은, 주소 지정 가능한 메모리를 2 바이트(1 MB)로20 제한합니다.이는 인텔 8086(이후 밀접하게 관련된8088)의 하드웨어 설계에서 직접 도출된 것입니다.(두 제품 모두 40핀 DIP 패키지로 패키지되어 있습니다.주소 라인이 20개밖에 없어도 주소와 데이터 버스는 제한된 핀 수 내에서 모든 주소 라인과 데이터 라인에 맞게 다중화되었습니다.)
각 세그먼트는 선형(플랫) 주소 공간의 선두에서 16바이트의 배수(문단)로 시작합니다.즉, 16바이트 간격입니다.모든 세그먼트의 길이는 64KB이므로 세그먼트 간에 오버랩이 발생할 수 있는 방법과 선형 메모리 주소 공간 내의 모든 위치에 다수의 세그먼트: 오프셋 쌍으로 액세스할 수 있는 이유를 설명합니다.선형 주소 공간에서의 세그먼트 시작의 실제 위치는 세그먼트×16으로 계산할 수 있습니다.세그먼트 값이 0Ch(12)이면, 선형 주소 공간내의 C0h(192)의 선형 주소가 됩니다.그런 다음 주소 오프셋을 이 숫자에 추가할 수 있습니다.0Ch:0Fh(12:15)는 C0h+0Fh=가 됩니다.CFh(192+15=207), CFh(207)가 선형 주소입니다.이러한 주소 변환은 CPU의 세그멘테이션 유닛에 의해 실행됩니다.마지막 세그먼트인 FFFFh(65535)는 20비트주소 공간 종료 16바이트 전 선형주소 FFFF0h(1048560)에서 시작되므로 20비트 8088 주소 공간 종료 65,536바이트 전 최대 65,520(65536-16) 바이트의 오프셋으로 액세스할 수 있습니다.8088 에서는, 이러한 주소 액세스가 주소 공간의 선두까지 랩 되어 65535:16이 주소 0에 액세스 하고, 65533:1000이 리니어 주소 공간의 주소 952에 액세스 합니다.프로그래머가 이 기능을 사용함에 따라 이후 CPU 세대에서는 게이트 A20 호환성 문제가 발생하였습니다.이 경우 리니어 어드레스 공간은 20비트 이상으로 확장되었습니다.
16비트 리얼 모드에서는, 애플리케이션이 복수의 메모리 세그먼트를 사용할 수 있도록 하는 것(어느 64K 세그먼트보다 많은 메모리에 액세스 하기 위해서)은 매우 복잡하지만, 작은 툴(메모리를 적게 사용하는 것)을 제외한 모든 툴의 필요악으로 간주되고 있습니다.문제의 근원은 메모리 범위 전체의 플랫어드레싱에 적합한 적절한 주소 산술 명령어가 [citation needed]없다는 것입니다.플랫 어드레싱은, 복수의 순서를 적용하면 가능하기 때문에, 프로그램의 속도가 저하합니다.
메모리 모델 개념은 세그먼트 레지스터의 설정에서 파생됩니다.예를 들어, 작은 모델 CS=DS=SS에서는 프로그램의 코드, 데이터 및 스택이 모두 단일 64KB 세그먼트에 포함되어 있습니다.소형 메모리 모델 DS=SS에서는 데이터와 스택이 모두 동일한 세그먼트에 존재하며 CS는 최대 64KB의 다른 코드 세그먼트를 가리킵니다.
보호 모드
이 섹션은 확인을 위해 추가 인용문이 필요합니다.(2015년 8월 (이 및 ) |

80286 보호 모드
80286의 보호 모드에서는 프로세서의 주소 공간이 2바이트(16메가바이트)까지24 확장되지만 시프트 값을 조정하지는 않습니다.대신 16비트 세그먼트레지스터는 오프셋이 추가되는 24비트 기본 주소를 포함하는 세그먼트 기술자 테이블에 인덱스를 포함합니다.오래된 소프트웨어를 지원하기 위해 프로세서는 8086의 세그먼트 어드레싱 모델을 사용하는 모드인 "리얼 모드"로 기동합니다.다만, 약간의 차이가 있습니다.그 결과 생성되는 물리 주소는 20비트로 잘리지 않기 때문에, 리얼 모드 포인터(8086 포인터 제외)는 100000과16 10FEF16 사이의 주소를 참조할 수 있습니다.이 대략 64킬로바이트의 메모리 영역은 HMA(High Memory Area)로 알려져 있으며, 이후 버전의 DOS는 이를 사용하여 사용 가능한 "일반" 메모리를 늘릴 수 있습니다(즉, 처음 MB 이내).HMA를 추가하면 총 주소 공간은 약 1.06MB가 됩니다.80286에서는 리얼 모드주소를 20비트로 잘라내지 않지만 80286을 탑재한 시스템에서는 21번째 주소 행인 A20 회선을 게이트함으로써 프로세서의 외부 하드웨어로 잘라낼 수 있습니다.IBM PC AT는 (원래 IBM PC 및 PC/XT 모델용 소프트웨어와의 완전한 역호환성을 위해) 이를 위한 하드웨어를 제공했고, 이에 따라 이후의 모든 "AT급" PC 복제도 마찬가지였습니다.
286 protected 모드는 8086/88 머신을 사용하는 다수의 사용자를 배제하기 때문에 거의 사용되지 않았습니다.게다가 리얼 모드와 같이 메모리를 64k 세그먼트(segment)로 분할할 필요가 있었습니다.이 제한은 64k보다 큰 메모리포인터를 사용할 수 있는32비트 CPU로 회피할 수 있지만 [세그먼트 제한(Segment Limit)]필드의 길이는 24비트밖에 되지 않기 때문에 작성할 수 있는 최대 세그먼트사이즈는 16MB입니다(페이징을 사용하여 메모리를 추가할 수 있지만 개별 세그먼트는 16MB를 초과할 수 없습니다).이 방법은 Windows 3.x 어플리케이션에서 일반적으로 사용되어 메모리 공간이 평평하게 되었습니다.단, OS 자체는 아직 16비트이기 때문에 32비트 명령에서는 API 호출을 할 수 없었습니다.따라서 API 호출을 수행하는 모든 코드를 64k 세그먼트에 배치해야 했습니다.
일단 286 보호 모드가 호출되면 하드웨어 리셋을 실행하지 않으면 모드를 종료할 수 없습니다.IBM PC/AT 표준이 향상된 컴퓨터는 표준화된 키보드 컨트롤러를 통해 CPU로 리셋하는 척할 수 있지만, 이는 상당히 느렸습니다.Windows 3.x는 CPU의 인터럽트 처리 메커니즘에서 의도적으로 3중 장애를 트리거함으로써 이러한 문제를 회피하고 CPU를 거의 [3]즉시 리얼 모드로 되돌립니다.
세분화 단위 상세 워크플로우
논리 주소는 16비트세그먼트 셀렉터(13+1 주소 비트 제공)와 16비트 오프셋으로 구성됩니다.세그먼트 선택기는 세그먼트 레지스터 중 하나에 있어야 합니다.이 셀렉터는 2비트 Requested Privilege Level(RPL; 요구 특권 수준), 1비트 Table Indicator(TI; 테이블인디케이터) 및 13비트인덱스로 구성됩니다.
지정된 논리 주소의 주소 변환을 시도할 때 프로세서는 글로벌 기술자 테이블(TI=0) 또는 로컬 기술자 테이블(TI=1)에서 64비트 세그먼트 기술자 구조를 읽습니다.다음으로 특권 체크를 수행합니다.
- max(CPL, RPL) d DPL
여기서 CPL은 현재 특권 수준(CS 레지스터의 하위2비트에 표시), RPL은 세그먼트셀렉터에서 요청된 특권 수준, DPL은 세그먼트(디스크립터에 표시)의 디스크립터 특권 수준입니다.모든 특권 레벨은 0 ~3 범위의 정수입니다.여기서 가장 작은 숫자는 가장 큰 특권에 해당합니다.
부등식이 false일 경우 프로세서는 General Protection(GP; 일반 보호) 장애를 생성합니다.그렇지 않으면 주소 변환이 계속됩니다.그런 다음 프로세서가 32비트 또는 16비트 오프셋을 가져와 세그먼트 기술자에 지정된 세그먼트 제한과 비교합니다.더 크면 GP 장애가 생성됩니다.그렇지 않으면 프로세서는 디스크립터로 지정된 24비트 세그먼트 베이스를 오프셋에 추가하여 선형 물리적 주소를 만듭니다.
세그먼트 설명자는 세그먼트 [citation needed][1]레지스터의 숨겨진 부분에 캐시되기 때문에 세그먼트 레지스터가 로드될 때만 권한 검사가 수행됩니다.
80386 보호 모드
인텔 80386 이후에서는 보호 모드에서는 80286 보호 모드의 세그멘테이션 메커니즘이 유지되지만, 세그멘테이션 유닛과 물리 버스간의 주소 변환의 2번째 레이어로서 페이징 유닛이 추가되었습니다.또, 중요한 것은, 주소 오프셋은 32비트(16비트 대신)이며, 각 세그먼트 기술자의 세그먼트 베이스도 32비트(24비트 대신)입니다.분할 장치의 일반 작동은 변경되지 않습니다.페이징 유닛은 유효 또는 무효로 할 수 있습니다.비활성화 시 동작은 80286과 동일합니다.페이징 유닛이 유효하게 되어 있는 경우, 세그먼트내의 주소는, 80286 의 경우와 같이 물리 주소가 아니고, 가상 주소가 됩니다.즉, 세그먼트 시작 주소, 오프셋 및 분할 유닛을 추가하여 얻은 최종 32비트 주소는 페이징 유닛이 네이블일 때 모두 가상(또는 논리) 주소입니다.세그멘테이션 유닛이 이러한 32비트 가상 주소를 생성 및 검증하면, 유효하게 된 페이징 유닛은 최종적으로 이러한 가상 주소를 물리 주소로 변환합니다.물리 주소는 386에서는 32비트이지만 물리 주소 확장을 지원하는 새로운 프로세서에서는 더 커질 수 있습니다.
또한 80386에서는 4개의 세그먼트 레지스터(CS, DS, ES 및 SS)의 원래 세트에 2개의 범용 데이터 세그먼트 레지스터(FS 및 GS)가 추가되었습니다.
386 CPU는 CR0 제어 레지스터의 비트를 클리어함으로써 리얼 모드로 되돌릴 수 있지만 이는 보안과 견고성을 강화하기 위한 특권 조작입니다.참고로 286은 트리플 폴트 등의 이유로 프로세서를 강제로 리셋하거나 외부 하드웨어를 사용하는 경우에만 리얼 모드로 되돌릴 수 있습니다.
이후의 개발
x86-64 아키텍처에서는 롱 모드(64비트 모드)에서는 세그멘테이션을 사용하지 않습니다.세그먼트 레지스터의 4개(CS, SS, DS 및 ES)는, 베이스 주소 0, 제한은64 2 로 강제됩니다.세그먼트 레지스터 FS 및 GS는 여전히 0이 아닌 기본 주소를 가질 수 있습니다.이것에 의해, operating system은 이러한 세그먼트를 특별한 목적으로 사용할 수 있습니다.레거시 모드에서 사용되는 글로벌 기술자 테이블 메커니즘과 달리 이들 세그먼트의 기본 주소는 모델 고유의 레지스터에 저장됩니다.x86-64 아키텍처는 커널 모드와 사용자 모드 기본 주소를 스왑할 수 있는 특별한 SWAPGS 명령을 제공합니다.
예를 들어 x86-64에서 마이크로소프트 윈도우즈는 GS 세그먼트를 사용하여 예외 처리, 스레드 로컬 변수 및 기타 스레드별 상태에 대한 정보를 포함하는 각 스레드의 작은 데이터 구조인 스레드 환경 블록을 가리킵니다.마찬가지로 Linux 커널은 GS 세그먼트를 사용하여 CPU별 데이터를 저장합니다.
GS/FS는 gcc의 스레드 로컬 스토리지 및 카나리 기반 스택 프로텍터에도 사용됩니다.
프랙티스
논리 주소는 x86 어셈블리 언어로 명시적으로 지정할 수 있습니다(AT&T 구문).
movl $42, %fs:(%eax), RTL의 M[fs:eax]<-42)과 동등
또는 인텔 구문:
움직이다 워드 [fs:이액스], 42
그러나 세그먼트 레지스터는 일반적으로 암묵적으로 사용됩니다.
- 모든 CPU 명령은 CS 레지스터에 저장된 세그먼트셀렉터에 의해 지정된 코드세그먼트로부터 암묵적으로 취득됩니다.
- 대부분의 메모리 참조는 DS 레지스터에 저장된 세그먼트 셀렉터에 의해 지정된 데이터 세그먼트에서 가져옵니다.세그먼트 오버라이드 프리픽스가 메모리를 참조하는 명령보다 선행하는 경우, ES 레지스터에 보관 유지되는 세그먼트 셀렉터에 의해 지정된 추가 세그먼트에서 이러한 프레픽스가 나올 수도 있습니다.기본적으로 DS를 사용하는 대부분의 명령에서는 ES 덮어쓰기 프레픽스가 허용됩니다.
- 프로세서 스택 참조는 암묵적으로(예를 들어 푸시 및 팝 명령) 또는 명시적으로(E)SP 또는 (E)BP 레지스터를 사용한 메모리액세스) SS 레지스터에 보관 유지되는 세그먼트(segment selector)에 의해 지정된 스택세그먼트를 사용합니다.
- 문자열 명령(예: stos, mov)은 데이터 세그먼트와 함께 ES 레지스터에 저장된 세그먼트 선택기에서 지정한 추가 세그먼트도 사용합니다.
x86-32 프로세서에서는 세그먼트화를 끌 수 없습니다(이것은 64비트 모드에서도 마찬가지이지만 설명의 범위를 벗어납니다).많은 32비트 운영체제는 모든 세그먼트의 베이스를 0으로 설정하여 프로그램에 대한 세그먼트화를 중립으로 하는 플랫 메모리 모델을 시뮬레이트합니다.예를 들어 Linux 커널은 다음 4개의 범용 세그먼트만 설정합니다.
이름. | 묘사 | 기초 | 제한. | DPL |
---|---|---|---|---|
__KERNEL_CS | 커널 코드 세그먼트 | 0 | 4 GiB | 0 |
__KERNEL_DS | 커널 데이터 세그먼트 | 0 | 4 GiB | 0 |
__USER_CS | 사용자 코드 세그먼트 | 0 | 4 GiB | 3 |
__USER_DS | 사용자 데이터 세그먼트 | 0 | 4 GiB | 3 |
베이스는 모든 경우에 0, 제한 4 GiB로 설정되어 있기 때문에, 분할 유닛은, 프로그램의 문제가 페이징 유닛에 도착하기 전에 대처하는 것에 영향을 주지 않습니다.(이전의 x86 프로세서에는 페이징 유닛이 없기 때문에, 물론 80386 이후의 프로세서를 가리킵니다).
또한 현재 Linux는 GS를 사용하여 스레드 로컬 스토리지를 가리키고 있습니다.
세그먼트는 코드, 데이터 또는 시스템 세그먼트로 정의할 수 있습니다.세그먼트 읽기 전용, 읽기/쓰기, 실행 등을 위한 추가 권한 비트가 있습니다.
보호 모드에서는 코드는 CS(코드 세그먼트셀렉터)를 제외한 모든 세그먼트레지스터를 항상 변경할 수 있습니다.이는 프로세서의 현재 특권 수준(CPL)이 CS 레지스터의 하위2비트에 저장되기 때문입니다.프로세서 특권 레벨을 올리는 방법(및 CS를 새로고침하는 방법)은 lcall(원거리 콜) 및 int(인터럽트) 명령뿐입니다.마찬가지로 특권 수준을 낮추는 방법(및 CS를 새로고침하는 방법)은 lret(원거리 복귀) 및 iret(인터럽트 복귀) 명령뿐입니다.리얼 모드에서는, 코드가 원점프를 실시(또는 문서화되어 있지 않은 것을 사용)하는 것으로 CS 레지스터를 변경할 수도 있습니다.POP CS
(8086 또는 8088)[4]의 지침).물론 리얼 모드에서는 특권 레벨은 없습니다.모든 프로그램은 모든 메모리와 모든 CPU 명령에 대해 절대 체크되지 않은 액세스 권한을 가집니다.
세그먼트화의 상세한 것에 대하여는, AMD 또는 인텔의 Web 사이트에서 무료로 입수할 수 있는 IA-32 메뉴얼을 참조해 주세요.
주 및 참고 자료
- ^ a b 「Intel 64 and IA-32 Architectures Software Developer's Manual」, 제3권 「System Programming Guide」(시스템 프로그래밍 가이드), 2011년에 출판된 「Vol. 3A 3-11」페이지에서는, 다음과 같이 기술되어 있습니다.「모든 세그먼트 레지스터에는 「보이는」부분과 「숨겨진」부분이 있습니다(숨겨진부분은부분은부분은 「그림자」또는 「캐시」라고 불리기도 합니다).세그먼트 레지스터의 가시적인 부분에 삽입된 프로세서는 세그먼트 셀렉터가 가리키는 세그먼트 기술자에서 기본 주소, 세그먼트 제한 및 액세스 제어 정보를 사용하여 세그먼트 레지스터의 숨겨진 부분도 로드합니다. 세그먼트 레지스터에 캐시된 정보(가시 및 숨김)에 의해 프로세서는 추가 버스 사이클을 거치지 않고 주소를 변환하여 세그먼트 기술자로부터의 베이스 주소 및 제한을 읽을 수 있습니다.
- ^ Intel Corporation (2004). IA-32 Intel Architecture Software Developer's Manual Volume 1: Basic Architecture (PDF).
- ^ "DevBlogs".
- ^
POP CS
는 다음 명령을 가져오기 위해 명령 포인터에서 계산되는 유효 주소를 즉시 변경하기 때문에 매우 주의하여 사용해야 하며 유용성이 제한됩니다.일반적으로 멀리뛰기가 훨씬 더 유용하다.의 존재POP CS
8086 및 8088의 4개의 세그먼트 레지스터에 대한 PUSH 및 POP 명령 연산 코드 패턴을 따르기 때문에 사고일 가능성이 있습니다.