목차


소개

Amazon Macie는 Amazon S4 버킷에서 데이터를 검색할 때 사용하는 기능이다. 이를 특정 문자나 정규표현식을 사용하여 찾는다. 설명에는 기계학습을 사용하여 개인정보(PII)나 민감한 데이터를 식별할 수 있다고 소개한다.

활용

이제 Macie를 이용해 검색하기 위해 패턴을 생성한다. 패턴은 우측 패널에 설정에서 사용자 지정 데이터 식별자를 선택한다.

민감 정보를 찾기 위한 패턴 설정 1

민감한 데이터인 폰 번호를 검색하는 정규표현식을 간단히 작성한다. 단순 문자열도 최대 50개까지 지정할 수 있고, 예외처리도 10개 까지 가능하다.

민감 정보를 찾기 위한 패턴 설정 2

이제 검색은 검색 대상이 되는 S3 버킷을 선택한다. 버킷 선택은 우측 패널의 S3 버킷에서 선택 가능하며 여러 버킷을 지정하여 한번에 검색도 가능하다.

Macie 스캐닝 대상이 되는 S3 버킷 설정

다음과 같이 간단한 S3 버킷의 정보를 보여주고, 우측에는 Macie의 요금 정보도 간략하게 보여준다.

Macie 스캐닝 하기 앞서 선택한 S3 버킷 정보

상세한 Macie의 요금은 요금 | Amazon Macie | Amazon Web Services(AWS)에서 확인 가능하다. Macie를 활성화 한 것만으로도 버킷 갯수당 0.10 달러가 소비된다. 그 이유는 검색 속도를 높이기 위해 인덱싱하는 것 때문으로 추측된다. 다음 버튼을 누르면 작업 방식을 선택할 수 있다. 지속적으로 반복작업을 할 것인가? 반복 작업을 한다면 기존 객체를 포함할 것인가? 이번 한번만 작업할 것인가? 등 설정할 수 있다. 기업의 경우 개인정보보호법에 의거해 데이터가 암호화되어 저장되어 있더라고 Pulic 버킷에 대해서는 지속적으로 Macie를 이용해 스캐닝하고, 최초로 진행할 땐 기존 객체를 포함을, 그렇지 않은 경우 기존 객체를 미포함으로 선택하여 비용을 줄일 수 있어 보인다. 반면 S3 버킷에서 탐지한 민감한 데이터를 조치를 하고 다시 스캔하여 결과를 확인할 수도 있다.

Macie를 이용한 민감한 정보 스캐닝 스케줄링 설정

다음으로 넘어가면 어떤 것을 검색할 것인지 미리 생성한 패턴을 선택한다.

Macie를 이용한 민감한 정보 스캐닝 탐지 패턴 설정

결과를 식별할 수 있게 Macie 작업 이름을 지정한다.

Macie를 이용한 민감한 정보 스캐닝 이름 설정

마지막을 설정한 작업을 검토하고 문제 없으면 제출을 클릭하여 스캐닝을 진행한다.

Macie를 이용한 민감한 정보 스캐닝 작업 최종 검토

스캐닝 결과는 우측 패널의 결과에서 확인할 수 있다. 결과는 모든 탐지 결과를 보여주며, 버킷별, 유형별, 작업별로 구분하여 볼 수 있다.

Macie를 이용한 민감한 정보 스캐닝 결과

각 결과를 선택하면 상세한 정보를 볼 수 있다. 중요한 것은 무엇이 탐지되었는가를 Macie에서 확인할 수 없다. 따라서 상세 결과의 개요에 리소스 부분의 링크를 선택하여 직접 S3 버킷에 방문하고, 탐지된 파일을 다운로드하여 분석할 수 있다.

Macie를 이용한 민감한 정보 스캐닝 상세 결과

간단하게 Macie를 구성하고 스캐닝도 해봤다. S3 버킷별로 암호화가 되어 있는 경우 처리하는 방법도 살펴볼 필요가 있고, 기업마다 개인정보의 유형이 다르기 때문에 패턴 생성에도 심혈을 기울여야 할 것 같다.

참고

 

What is Amazon Macie? - Amazon Macie

What is Amazon Macie? Amazon Macie is a fully managed data security and data privacy service that uses machine learning and pattern matching to discover, monitor, and help you protect your sensitive data in Amazon Simple Storage Service (Amazon S3). Macie

docs.aws.amazon.com

 

'Information Technology > Cloud' 카테고리의 다른 글

Amazon Macie (2/2) - 활용편  (0) 2020.09.13
Amazon Macie (1/2) - 구축편  (0) 2020.09.13

목차


소개

Amazon Macie는 Amazon S4 버킷에서 데이터를 검색할 때 사용하는 기능이다. 이를 특정 문자나 정규표현식을 사용하여 찾는다. 설명에는 기계학습을 사용하여 개인정보(PII)나 민감한 데이터를 식별할 수 있다고 소개한다.

구축

처음 Macie에 들어가면 기능 활성화를 진행할 수 있다. 첫 활성화 땐 30일 무료 평가판으로 자동 등록되어 무료로 사용할 수 있다.

Macie 활성화 시작 화면

최초 활성화를 하면 목적에 맞게 현재의 권한으로 접근할 수 있는 S3 버킷의 상태를 살펴볼 수 있다.

Macie의 대시보드

제일 먼저 설정해야 할 부분은 검색 결과이다. 민감한 데이터를 검색하고 찾아낸 결과를 새로운 S3 버킷에 저장한다. 본 포스트에서는 테스트를 위해서 오레온 데이터 센터를선택했지만, 보안 분야에서 찾아낼 민감한 데이터란 개인정보가 주류를 이루기에 개인정보보호법상 서울로 데이터센터로 변경해 진행하는 것을 추천한다.

Macie 전용 S3 버킷 설정 시작 화면

말 그대로 민감한 데이터이기에 필수로 암호화 기능을 이용해야 한다. 새로운 S3에서 직접 만들때 기본 암호화에서 AWS-KMS 기능을 활성화하고 키와 연동하여 생성하고, Macie에서 해당 버킷과 암호키를 선택하여 구성할 수 있다. 아니면 간단하게 Macie를 생성할 때 새로운 S3 버킷과 암호키 지정하여 새로운 S3 버킷을 생성할 수 있다. 이 포스트에서는 새로운 버킷과 새로운 암호화키를 생성하는 방식으로 진행한다. 다음과 같이 버킷 생성을 선택하고 버킷 이름을 지정한다.

버킷 생성으로 설정 시 화면

자동으로 KMS 암호화가 활성화 되는데, 우측 상단의 새 KMS 키 생성을 선택하여 새로운 암호키를 생성한다. 키는 대칭키로,

Macie가 사용할 키 유형 설정

키 이름을 지정하고

Macie가 사용할 키 별칭 설정

IAM 롤 설정이 없고 1인 사용자이기에 키 관리자는 선택하지 않고 굳이 개인 사용자가 마스터 키를 가질 필요도 없으니 CMK(Customer Master Key)는 선택 없이 넘긴다. (참고로 키 관리를 AWS에 맡기면 비용이 발생한다.)

Macie가 사용할 S3 버킷의 키 관리 정의
Macie가 사용할 S3 버킷의 키 사용 권한 정의

마지막으로 키 정책 검토인데, 생성한 키를 Macie가 사용할 수 있도록 정책을 편집한다. 삽입할 정책은 다음과 같으며, Json 구조에 맞게 잘 삽입한다.

{ 
    "Sid": "Allow Macie to use the key", 
    "Effect": "Allow", 
    "Principal": { "Service": "macie.amazonaws.com" }, 
    "Action": [ "kms:GenerateDataKey", "kms:Encrypt" ], 
    "Resource": "*" 
}

Storing and retaining sensitive data discovery results with Amazon Macie에서 Macie의 정책을 키에 삽입하는 방법을 참고할 수 있다. 키를 생성했다면 다시 Macie로 돌아와서 KMS 키 별칭 끝의 Refresh 아이콘을 클릭하고 새로 생성한 키를 선택한다.

Macie 저장소 설정 완료 단계

설정이 잘 되었다면 저장을 눌렀을 때 다음과 같은 화면이 보여진다.

Amazon Macie 결과 저장소 생성 완료

삽질

Macie를 이용해 S3 버킷을 즉흥적으로 생성할 때 Macie가 암호키를 사용할 수 있도록 권한을 부여하지 않은채 생성 버튼을 누른다면, S3 버킷은 생성되고 암호키는 사용하지 못한채 "권한이 없다"는 에러메시지가 출력된다.

'Information Technology > Cloud' 카테고리의 다른 글

Amazon Macie (2/2) - 활용편  (0) 2020.09.13
Amazon Macie (1/2) - 구축편  (0) 2020.09.13

목차

3. 기본 실행 환경(Basic Execution Environment)

3.1. 작동 방식(Modes of Operation)

3.1.1. Intel® 64 아키텍처(Intel® 64 Architecture)

3.2. 기본 실행 환경의 개요(Overview of the Basic Execution Environment)

3.2.1. 64비트 모드 실행 환경(64-Bit Mode Execution Environment)

3.3. 메모리 조직(Memory Organization)

3.3.1. IA-32 메모리 모델(IA-32 Memory Models)

3.3.2. 페이징과 가상 메모리(Paging and Virtual Memory)

3.3.3. 64비트 모드의 메모리 조직(Memory Organization in 64-Bit Mode)

3.3.4. 동작 모드 vs 메모리 모델(Modes of Operation vs. Memory Model)

3.3.5. 32비트 및 16비트 주소와 피연산자 크기(32-Bit and 16-Bit Address and Operand Sizes)

3.3.6. 보호 모드에서 확장된 물리적 주소 배정(Extended Physical Addressing in Protected Mode)

3.3.7. 64 비트 모드에서 주소 계산(Address Calculations in 64-Bit Mode)

3.3.7.1. 표준 주소 배정(Canonical Addressing)

3.4. 기본 프로그램 실행 레지스터(Basic Program Execution Registers)

3.4.1. 범용 레지스터(General-Purpose Registers)

3.4.1.1. 64비트 모드에서 범용 레지스터(General-Purpose Registers in 64-Bit Mode)

3.4.2. 세그먼트 레지스터(Segment Registers)

3.4.2.1. 64 비트 모드에서 세그먼트 레지스터(Segment Registers in 64-Bit Mode)

3.4.3. EFLAGS 레지스터(EFLAGS Register)

3.4.3.1. 상태 플래그(Status Flags)

3.4.3.2. DF 플래스(DF Flag)

3.4.3.3. 시스템 플래그와 IOPL 필드(System Flags and IOPL Field)

3.4.3.4. 64 비트 모드에서 RFLAGS 레지스터(RFLAGS Register in 64-Bit Mode)

3.5. 명령 포인터(Instruction Pointer)

3.5.1. 64 비트 모드에서 명령 포인터(Instruction Pointer in 64-Bit Mode)

3.6. 피연산자 크기와 주소 크기 속성(Operand-Size And Address-Size Attributes)

3.6.1. 64비트 모드의 피연산자 크기와 주소 크기(Operand Size and Address Size in 64-Bit Mode)

3.7. 피연산자 주소 배정(OPERAND ADDRESSING)

3.7.1. 직접 피연산자(Immediate Operands)

3.7.2. 레지스터 피연산자(Register Operands)

3.7.2.1. 64-비트 모드에서 레지스터 피연산자(Register Operands in 64-Bit Mode)

3.7.3. 메모리 피연산자(Memory Operands)

3.7.3.1. 64 비트에서 메모리 피연산자(Memory Operands in 64-Bit Mode)

3.7.4. 세그먼트 셀렉터 지정(Specifying a Segment Selector)

3.7.4.1. 64-비트 모드에서 세그먼테이션(Segmentation in 64-Bit Mode)

3.7.5. 오프셋 지정(Specifying an Offset)

3.7.5.1. 64-비트 모드에서 오프셋 지정(Specifying an Offset in 64-Bit Mode)

3.7.6. 어셈블러와 컴파일러 주소 배정 모드(Assembler and Compiler Addressing Modes)

3.7.7. I/O 포트 주소 배정(I/O Port Addressing)


3. 기본 실행 환경(Basic Execution Environment)

이 장에서는 어셈블리 프로그래머가 볼 수 있는 Intel 64나 IA-32 프로세서의 기본 실행 환경을 설명한다. 프로세서가 명령어를 실행하는 방법과 데이터를 저장하고 조작하는 방법을 설명한다. 여기서 설명하는 실행 환경은 메모리 (주소 공간), 범용 데이터 레지스터, 세그먼트 레지스터, 플래그 레지스터 그리고 명령 포인터 레지스터다.

3.1. 작동 방식(Modes of Operation)

IA-32 아키텍처는 보호 모드, 실제 주소 모드 그리고 시스템 관리 모드라는 세 가지 기본 작동 모드를 지원한다. 운영 모드는 접근할 수 있는 명령어와 아키텍처 기능을 결정한다.

  • 보호 모드(Protected Mode) - 이 모드는 프로세서의 기본 상태(native state)다. 보호 모드의 기능에는 다중 작업 환경에서 "실제 주소 모드" 8086 소프트웨어를 직접 실행할 수 있는 기능이 있다. 이 기능은 Virtual-8086 모드로 불리는데, 실제 프로세서 모드는 아니다. Virtual-8086 모드는 모든 작업을 활성화 할 수 있는 보호 모드 속성이다.
  • 실제 주소 모드(Real-address Mode) - 이 모드는 확장 기능(보호되거나 시스템 관리 모드로 전환하는 기능)이 있는 Intel 8086 프로세서의 프로그래밍 환경을 구현한다. 프로세서는 전원을 켜거나 재부팅 후 실제 주소 모드에 위치한다.
  • 시스템 관리 모드(SMM, System Management Mode) -  이 모드는 전력관리나 시스템 보안과 같은 플랫폼의 특정 기능을 구현하기 위해 투명한 메커니즘을 운영체제나 executive에게 제공한다. 외부 SSM 인터럽트 핀 (SMI#)이 활성화되거나 고급 프로그래밍이 가능한 인터럽트 제어기(APIC, Advanced Programmable Interrupt Controller)에서 SMI를 수신하면 프로세서는 SMM으로 진입한다.
    SMM에서 프로세서는 현재 실행중인 프로그램이나 작업의 기본 문맥을 저장하는 동안 별도의 주소 공간으로 전환한다. 그래야 SMM 관련 코드를 투명하게 실행할 수 있다. SMM에서 복귀할 때, 프로세서는 시스템 관리 인터럽트 이전 상태로 돌아간다. SMM은 Intel386™SL과 Intel486™SL 프로세서와 함께 소개되었고, 펜티엄 프로세서 제품군의 표준 IA-32로 자리잡았다.

3.1.1. Intel® 64 아키텍처(Intel® 64 Architecture)

인텔 64 아키텍처는 IA-32e 모드를 추가한다. IA-32e 모드에는 두 가지 하위 모드가 있는데 이는 다음과 같다.

  • 호환 모드(Compatibility Mode) / IA-32e 모드의 하위 모드 - 호환 모드는 64비트 운영체제에서 오래된 16비트와 32비트 응용프로그램을 다시 컴파일하지 않고 실행할 수 있다. 단순하게, 호환성 하위 모드를 IA-32 아키텍처에서 호환 모드라고 부른다. 호환 모드의 실행 환경은 3.2절에서 설명한 것과 동일하다. 호환 모드는 64비트와 보호 모드에서 지원하는 모든 권한 레벨을 지원한다. Virtual-8086 모드에서 실행되거나 하드웨어 작업 관리를 사용하는 오래된 응용프로그램은 이 모드에서 작동하지 않는다.
    호환 모드는 코드 세그먼트 단위로 운영체제에서 사용할 수 있다. 이는 단일 64비트 OS가 64비트 모드에서 실행되는 64비트 응용프로그램을 지원하고, 오래된 32비트 응용프로그램(64비트 용으로 다시 컴파일하지 않고)을 지원할 수 있음을 의미한다.
    호환 모드는 32비트 보호 모드와 유사하다. 응용프로그램은 처음 4GB 선형 주소 공간에만 접근한다. 호환 모드는 16비트와 32비트 주소 그래고 피연산자 크기를 사용한다. 보호 모드처럼 이 모드에서 응용프로그램이 물리 메모리 확장(PAE, Physical Address Extensions)를 사용하여 4GB가 넘는 실제 메모리에 접근할 수 있다.
  • 64비트 모드 / IA-32e 모드의 하위 모드 - 이 모드는 64비트 운영체제가 64비트 선형 주소 공간에 접근하여 작성된 응용프로그램을 실행할 수 있게 한다. 단순하게, 64비트 하위 모드는 IA-32 아키텍처에서 64비트 모드라고 부른다.
    64비트 모드는 범용 레지스터와 SIMD 확장 레지스터의 수를 8에서 16으로 확장한다. 범용 레지스터는 64비트로 확장된다. 또한 모드는 레지스터 확장에 액세스하는 새로운 opcode 접두어 (REX)를 도입한다. 자세한 설명은 3.2.1 절을 참조한다.
    64비트 모드는 코드 세그먼트 단위로 운영체제에서 사용할 수 있다. 기본 주소 크기는 64비트고 기본 연산자 크기는 32비트다. 기본 피연산자 크기는 피연산자 크기만큼 덮어쓰는 접두어와 함께 REX opcode 접두어를사용하여 명령별로 재정의할 수 있다.
    REX 접두어를 허용하면 64비트 모드에서 작동할 때 64비트 피연산자를 지정할 수 있다. 이 메커니즘을 이용하여 64비트 레지스터와 64비트 주소를 사용할 수 있도록 기존의 많은 명령이 승격된다.

3.2. 기본 실행 환경의 개요(Overview of the Basic Execution Environment)

Intel 64 프로세서는 IA-32 프로세서의 기본 실행 환경을 지원하며, 64비트 프로그램(64비트 하위 모드)와 32비트 프로그램(호환 하위 모드) 실행할 수 있는 IA-32e 모드와 유사한 환경을 지원한다.

IA-32 프로세서에서 실행되는 모든 프로그램이나 작업은 명령을 실행하고 코드, 데이터 그리고 상태 정보를 저장하기 위한 자원의 집합을 제공한다. 이러한 자원은 (그림 3-1에서 볼 수 있고 다음 단락에서 간략하게 설명 함) IA-32 프로세서의 기본 실행 환경을 구성한다.

기본 실행 환경은 응용프로그램과 운영체제나 executive이 실행한 프로세서가 공동으로 사용한다.

  • 주소 공간(Address Space) - IA-32 프로세서에서 실행되는 모든 프로그램이나 작업은 최대 4GB (232 바이트) 선형 주소 공간과 최대 64GB (236 바이트) 물리 주소 공간을 주소로 쓸 수 있다. 4GB 보다 큰 주소 공간을 주소로 쓸 수 있는 자세한 정보는 3.3.6 절 "Extended Physical Addressing in Protected Mode"를 참조한다.
  • 기본 프로그램 실행 레지스터(Basic Program Execution Registers) - 8개의 범용 레지스터, 6개의 세그먼트 레지스터, EFLAGS 레지스터 그리고 EIP (명령 포인터) 레지스터는 범용적인 명령의 집합을 실행하는 기본 실행 환경을 구성한다. 이러한 명령은 바이트, 워드, 더블워드 정수에 대한 기본 산술 연산, 프로그램 흐름 제어를 처리, 비트와 바이트 문자열을 처리, 메모리 주소를 지정하는 수행한다. 이러한 레지스터에 대한 자세한 정보는 3.4 절 "Basic Program Execution Registers"를 참조한다.
  • x87 FPU 레지스터 - 8개의 x87 FPU 데이터 레지스터, x87 FPU 제어 레지스터, 상태 레지스터, x87 FPU 명령 포인터 레지스터, x87 FPU 피연산자 (데이터) 포인터 레지스터, x87 FPU 태그 레지스터 그리고 x87 FPU opcode 레지스터는 단정밀도(single-precision), 배정밀도(double-precision) 그리고 확장된 배정밀도(double extended-precision)를 통한 부동소수점 값, 워드 정수, 더블 워드 정수, 쿼드 워드 정수 그리고 BCD(Binary Coded Decimal) 값을 포함한 실행 환경을 제공한다.
  • MMX 레지스터 - 8 개의 MMX 레지스터는 64비트로 포장 된 바이트, 워드 그리고 더블 워드 정수에 대한 단일 명령, 다중 데이터(SIMD) 연산을 실행하도록 지원한다. 이 레지스터에 대한 자세한 내용은 9.2 절 "The MMX Technology Programming Environment"을 참조한다.
  • XMM 레지스터 - 8개의 XMM 데이터 레지스터와 MXCSR 레지스터는 128비트로 포장킹된 바이트, 워드, 더블 워드 그리고 쿼드 워드 정수와 128비트로 포장된 단정밀도와 배정밀도 부동소수점 값을 SIMD 연산으로 지원한다. 이 레지스터에 대한 자세한 내용은 10.2 절 "SSE Programming Environment"을 참조한다.
  • YMM 레지스터 - YMM 데이터 레지스터는 256비트로 포장된 단정밀도와 배정밀도 부동소수점 값과 256비트로 포장된 바이트, 워드, 더블워드 그리고 쿼드 워드 정수를 256비트 SIMD 연산으로 지원한다.
  • 바운드 레지스터(Bounds registers) - BND0-BND3 레지스터 각각은 메모리 버퍼에 대한 포인터를 지지하는 하위 및 상위 바운드(bounds) (각각 64비트)를 저장한다. 인텔 MPX 명령의 실행을 지원한다.
  • BNDCFGU와 BNDSTATUS - BNDCFGU는 경계(Bound) 검사시 사용자 모드 MPX 작업을 구성한다. BNDSTATUS는 MPX 작업으로 인한 #BR의 추가 정보를 제공한다.

  • 스택(Stack) - 프로 시저나 서브 루틴 호출 그리고 프로 시저나 서브 루틴 사이의 매개 변수 전달을 지원하기 위해 스택과 스택 권리 리소스는 실행 환경에 포함된다. 스택 (그림 3-1에 표시하지 않음)은 메모리에 위치한다. 스택 구조에 대한 자세한 정보는 6.2 절 "Stacks"를 참조한다.

기본 실행 환경에서 제공되는 자원 외에도 IA-32 아키텍처는 시스템 레벨 아키텍처의 일부로 다음과 같은 자원을 제공한다. 이들은 운영체제와 시스템 개발 소프트웨어에 대한 광범위하게 지원한다. I/O 포트를 제외하고 시스템 자원은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volumes 3A & 3B에 자세히 설명되어 있다.

  • I/O 포트 - IA-32 아키텍처는 입력/출력 (I/O) 포트와 데이터 전송을 지원한다. 자세한 내용은 18 장 "Input/Output"을 참조한다.
  • 제어 레지스터(Control Registers) - 5 개의 제어 레지스터 (CR0부터 CR4)는 프로세서의 작동 모드와 현재 실행중인 작업의 특성을 결정한다. 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 2장 "System Architecture Overview"를 참조한다.
  • 메모리 관리 레지스터(Memory Management Registers) - GDTR, IDTR, 작업 레지스터 그리고 LDTR은 보호 모드 메모리 관리에 사용되는 데이터 구조의 위치를 지정한다. 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 2장 "System Architecture Overview"를 참조한다.
  • 디버그 레지스터(Debug Registers) - 디버그 레지스터 (DR0부터 DR7)는 프로세서의 디버깅 작업을 제어하고 모니터링을 허용한다. 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3B를 참조한다.
  • 메모리 유형 범위 레지스터(MTRRs, Memory Type Range Registers) - MTRRs는 메모리 유형을 메모리 영역에 할당하기 위해 사용한다. 자세한 정보는 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volumes 3A & 3B의 MTRRs 절을 참조한다.
  • 기계 고유 레지스터(MSRs, Machine Specific Registers) - 프로세서는 프로세서 성능을 제어하고 보고하는데 사용되는 다양한 기계 고유 레지스터를 제공한다. 가실상 모든 MSRs는 시스템 관련 기능을 처리하며 응용프로그램에서 접근할 수 없다. 이 규칙의 한 가지 예외는 타임 스탬프 카운터다. MSR은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3C의 35장 "Model-Specific Registers (MSRs)"에 설명되어 있다.
  • 기계 점검 레지스터(Machine Check Registers) - 기계 점검 레지스터는 하드웨어 (기계) 오류를 감지하고 보고하는데 사용되는 일련의 제어, 상태 그리고 오류 보고 MSR로 구성된다. 자세한 정보는 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 15장 "Machine Check Architecture"를 참고한다.
  • 성능 모니터링 카운터(Performance Monitoring Counters) - 성능 모니터링 카운터를 사용하여 프로세서 성능 이벤트를 모니터링 할 수 있다. 자세한 정보는 Intel® 64 and IA-32 Architectures Software developer’s Manual, Volume 3B의 18장 "Performance Monitoring"을 참고한다.

이 장의 나머지 부분에서는 메모리와 주소 공간의 구성, 기본 프로그램 실행 레지스터 그리고 주소 배정 모드를 설명을 한다. 그림 3-1에 표시된 다른 프로그램 실행 자원에 대한 설명은 이 볼륨의 다음 장을 참조한다.

  • x87 FPU 레지스터 - 8장, "Programming with the x87 FPU"를 참조
  • MMX 레지스터 - 9장, "Programming with Intel® MMX™ Technology"를 참조
  • XMM 레지스터 - 10장, "Programming with Intel® Streaming SIMD Extensions (Intel® SSE)" 11장, "Programming with Intel® Streaming SIMD Extensions 2 (Intel® SSE2)" 그리고 12장, "Programming with Intel® SSE3, SSSE3, Intel® SSE4 and Intel® AESNI"을 참조
  • YMM 레지스터 - 14장, "Programming with AVX, FMA and AVX2"을 참조
  • BND 레지스터, BNDCFGU, BNDSTATUS - 13장, "Managing State Using the XSAVE Feature Set" 그리고 17장, "Intel® MPX"을 참조
  • 스택 구현 및 프로 시저 호출 - 6장, "Procedure Calls, Interrupts, and Exceptions"를 참조

3.2.1. 64비트 모드 실행 환경(64-Bit Mode Execution Environment)

64비트 모드를 위한 실행 환경은 3.2 절에서 설명한 것과 유사하다. 다음 단락에서 적용되는 차이점을 설명한다.

  • 주소 공간(Address Space) - IA-32 프로세서에서 64비트 모드로 실행되는 작업이나 프로그램은 최대 264 바이트(3.3.7.1 절에 설명된 표준  주소 배정 요구 사항에 적용 받음)의 선형 주소 공간과 최대 246 바이트의 물리 주소 공간을 처리할 수 있다. 소프트웨어는 프로세서에 의해 지원받는 물리 주소 크기에 대해 CPUID를 쿼리할 수 있다.
  • 기본 프로그램 실행 레지스터(Basic Program Execution Registers) - 사용할 수 있는 범용 레지스터 (GPRs)는 16개다. GPRs는 64비트 폭이며 바이트, 워드, 더블 워드, 쿼드 워드 정수에 대한 연산을 지원한다. 바이트 레지스터에 접근하는 것은 가장 낮은 8비트로 균일하게 수행된다. 명령 포인터 레지스터는 64비트다. EFLAGS 레지스터는 64비트 폭으로 확장되면 RFLAGS 레지스터로 바꿔 부른다. RFLAGS의 상위 32비트는 예약된 영역이다. RFLAGS의 하위 32비트는 EFLAGS와 동일하다. 그림 3-2를 참조하자.
  • XMM 레지스터 - SIMD 연산을 위한 16개의 XMM 레지스터가 있다. 이러한 레지스터에 대한 자세한 내용은 10.2 절 "SSE Programming Environment"를 참조한다.
  • YMM 레지스터 - SIMD 연산을 위한 16개의 YMM 데이터 레지스터가 있다. 이러한 레지스터에 대한 자세한 내용은 14장 "Programming with AVX, FMA and AVX2"을 참조한다.
  • BND 레지스터, BNDCFGU, BNDSTATUS - 13장 "Managing State Using the XSAVE Feature Set" 와 17장 "Intel® MPX"을 참조한다.
  • 스택 - 스택 포인터 크기는 64비트다. 스택 크기는 SS 디스크립터(비 64비트 모드이기 때문에) 의 비트에 의해 제어되거나 포인터의 크기가 명령 접두사에 의해 무시되지 않는다.
  • 제어 레지스터(Control registers) - 제어 레지스터는 64비트로 확장된다. 새로운 제어 레지스터 (작업 우선 순위 레지스터: CR8 또는 TPR)가 추가되었다. 자세한 정보는 2장 "Intel® 64 and IA-32 Architectures"을 참고한다.
  • 디버그 레지스터(Debug registers) - 디버그 레지스터는 64비트로 확장된다. 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 17장 "Debug, Branch Profile, TSC, and Quality of Service"을 참고한다.
  • 디스크립터 테이블 레지스터(Descriptor table registers) - 글로벌 디스크립터 테이블 레지스터 (GDTR, Global Descriptor Table Register)과 인터럽트 디스크립터 테이블 레지스터 (IDTR, Interrupt Descriptor Table Register)은 10자이르토 확장되어 완전한 64비트 기반 주소를 유지할 수 있다. 로컬 디스크립터 테이블 레지스터 (LDTR, Local Descriptor Table Register)와 작업 레지스터(TR, Task Register)도 확장되어 전체 64비트 기반 주소를 보유한다.

3.3. 메모리 조직(Memory Organization)

프로세서그 버스에서 주소를 지정하는 메모리를 물리 메모리라고 부른다. 물리 메모리는 일련의 8비트 바이트로 구성된다. 각 바이트에는 물리적 주소라는 고유 주소가 할당된다. 프로세서가 Intel 64 아키텍처가 지원하지 않는 경우 물리 주소 공간의 범위는 0에서 최대 236 - 1 (64GB)이다. Intel 64 아키텍처는 물리와 선형 주소 공간을 변경을 소개한다. 이는 3.3.3절, 3.3.4절 그리고 3.3.7절에서 설명되어 있다.

실제로 IA-32나 Intel 64 프로세서와 함께 작동하도록 설계된 운영체제나 executive는 프로세서의 메모리 관리 기능을 사용하여 메모리에 접근한다. 이러한 기능은 메모리를 효율적이고 안정적으로 관리할 수 있는 세그먼테이션과 페이징 같은 기능을 제공한다. 메모리 관리에 대한 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 3장 "Protected-Mode Memory Management"를 참조한다. 다음 단락에서는 메모리 관리를 사용할 때 메모리 주소를 지정하는 기본적인 방법을 설명한다.

3.3.1. IA-32 메모리 모델(IA-32 Memory Models)

프로세서의 메모리 관리 기능을 사용하면, 프로그램은 물리 메모리를 직접 처리하지 못한다. 대신 세 가지 메모리 모델 중 하나를 사용 하여 메모리에 접근하는데 이는 평면(Flat), 분할(Segmented) 그리고 실제 주소 모드(Real Address Mode)다.

  • 평면 메모리 모델(Flat Memory Model) - 메모리는 하나의 프로그램을 연속적인 주소 공간(그림 3-3)으로 표현한다. 이 공간을 선형 주소 공간(Linear Address Space)이라고 부른다. 코드, 데이터 그리고 스택은 모두 이 주소 공간에 포함된다. 선형 주소 공간은 바이트 크기만큼 주소 배정이 가능하며, 주소는 0에서 232 - 1(64비트 모드가 아닌 경우)까지 연속적으로 실행된다. 선형 주소 공간에서 모든 바이트를 위한 주소를 선형 주소라 부른다.
  • 분할된 메모리 모델(Segmented Memory Model) - 메모리는 프로그램에 세그먼트라고 불리는 독립적인 주소 공간의 그룹으로 나타낸다. 코드, 데이터 그리고 스택은 일반적으로 별도의 세그먼트에 포함된다. 세그먼트의 바이트 주소를 지정하기 위해 프로그램은 논리적 주소를 발행한다. 이 논리적 주소는 세그먼트 셀렉터와 오프셋 (논리적 주소는 종종 원거리 포인터라고 함)으로 구성된다. 세그먼트 셀렉터는 접근할 세그먼트를 식별하고 오프셋은 세그먼트의 주소 공간에서 바이트를 식별한다. IA-32 프로세서에서 실행되는 프로그램은 크기와 유형이 다른 최대 16,383개의 세그먼트를 처리할 수 있으며, 각 세그먼트는 232 바이트로 클 수 있다.
    내부적으로, 시스템에 정의된 모든 세그먼트는 프로세서의 선형 주소 공간에 매핑된다. 메모리 위치에 접근하기 위해서 프로세서는 각 논리 주소를 선형 주소로 변환한다. 이 변환은 응용프로그램에 있어 투명하다.
    분할된 메모리를 사용하는 주된 이유는 프로그램과 시스템의 신뢰성을 높이는데 있다. 예를 들어 프로그램의 스택을 별도의 세그먼트로 배치하면 스택이 코드나 데이터 공간으로 확장되거나 명령이나 데이터를 덮어쓰지 못하게 된다.
  • 실제 주소 모드 메모리 모델(Real-Address Mode Memory Model) - 이것은 Intel 8086 프로세서의 메모리 모델이다. Intel 8086 프로세서에서 실행되도록 작성된 기존의 응용프로그램과의 호환성을 지원한다. 실제 주소 모드는 분할된 메모리의 특정 구현을 사용하는데, 여기서 선형 주소 공간에 프로그램과 운영체제/executive는 각각 최대 64 KB 크기의 세그먼트의 배열로 구성된다.
    자세한 정보는 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3B의 20장 "8086 Emulation"를 참조한다.

3.3.2. 페이징과 가상 메모리(Paging and Virtual Memory)

평면 또는 분할된 메모리 모델을 사용하면 선형 주소 공간은 직접 또는 페이징을 통해 프로세서의 물리적 주소 공간으로 매핑된다. 직접 매핑(페이징 비활성화)을 사용할 때, 각 선형 주소는 물리적 주소와 일대일로 대응한다. 선형 주소는 변환하지 않고 프로세서의 주소 행에 전달된다.

IA-32 아키턱처의 페이징 메커니즘 (페이징 활성화)를 사용할 때 선형 주소 공간은 가상 메모리에 매핑되는 페이지로 구분된다. 가상 메모리의 페이지는 필요에 따라 물리 메모리에 매핑된다. 운영체제나 executive이 페이징을 사용할 때, 페이징 메커니즘은 응용프로그램에 투명하다. 모든 응용프로그램이 보는 모든 것은 선형 주소 공간이다.

또한, IA-32 아키턱처의 페이징 메커니즘에는 다음을 지원하도록 확장된다.

  • 물리 주소 확장 (PAE, Physical Address Extensions)을 사용하여 4GB 보다 큰 물리 주소 공간을 처리한다.
  • 페이지 크기 확장(PSE, Page Size Extensions)을 사용하여 선형 주소를 4메가 바이트 페이지 물리 주소에 매핑한다.

자세한 정보는 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 3장 "Protected-Mode Memory Management"를 참조한다.

3.3.3. 64비트 모드의 메모리 조직(Memory Organization in 64-Bit Mode)

Intel 64 아키텍처는 64GB보다 큰 물리적 주소 공간을 지원한다. IA-32 프로세서의 실제 물리 주소 공간은 구현에 따라 다르다. 64비트 모드 아키텍처는 64비트 선형 주소 공간을 지원한다. 하지만 Intel 64 아키텍처를 지원하는 프로세서는 64비트보다 작게 구현할 수 있다. (3.3.7.1절 참조) 선형 주소 공간은 PAE 페이징 메커니즘을 통해 프로세서 물리 메모리 공간에 매핑된다.

3.3.4. 동작 모드 vs 메모리 모델(Modes of Operation vs. Memory Model)

IA-32나 Intel 64 프로세서 용 코드를 작성할 때, 프로그래머는 사용중인 코드와 메모리 모델을 작동시킬 때 프로세서가 작동 할 운영 모드를 알아야한다. 동작 모드와 메모리 모델간의 관계는 다음과 같다.

  • 보호 모드(Protected Mode) - 보호 모드에 있을 때, 프로세서는 이 절에서 설명하는 메모리 모델 중 하나를 사용할 수 있다. (실제 주소 배정 모드 메모리 모델은 일반적으로 프로세서가 virtual-8086 모드에 있을 때만 사용) 사용되는 메모리 모델은 운영 시스템이나 executive의 설계에 따라 다르다. 멀티 태스킹이 구현되면, 개별 작업은 다른 메모리 모델을 사용할 수 있다.
  • 시스템 관리 모드(System Management Mode) - SMM에서 프로세서는 시스템 관리 RAM (SMRAM)이라고 하는 별도의 주소 공간으로 전환한다. 이 주소 공간에서 바이트를 주소로 지정하는데 사용되는 메모리 모델은 실제 주소 모드 모델과 유사하다. 더 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3C의 34장 "System Management Mode"을 참조한다.
  • 호환 모드(Compatibility Mode) - 호환성 모드에서 실행할 필요가 있는 소프트웨어는 32비트 보호 모드에서 실행되도록 지정된 메모리 모델과 동일한 메모리 모델을 준수한다. 세그먼트화의 효과는 32비트 보호 모드 의미와 동일하다.
  • 64비트 모드(64-bit Mode) - 세그먼트화는 일반적으로 (하지만 완전하지 않게) 비활성화 되고, 평면 64비트 선형 주소 공간에 생성한다. 구체적으로, 프로세서는 64비트 모드에서 CS, DS, ES 그리고 SS의 세그먼트 기준을 0으로 처리한다. (이로 인해 선형 주소가 유효한 주소와 같게 만든다) 64비트 모드에서 분할 및 실제 주소 모드를 사용할 수 없다.

3.3.5. 32비트 및 16비트 주소와 피연산자 크기(32-Bit and 16-Bit Address and Operand Sizes)

보호 모드에서 IA-32 프로세서는 32비트 또는 16비트 주소와 피연산자 크기로 구성 된다. 32비트 주소와 피연산자 크기에서 최대 선형 주소나 세그먼트 오프셋은 FFFFFFFFH (232 -1)을 가진다. 피연산자 크기는 일반적으로 8비트 이거나 32비트다. 16비트 주소와 피연산자 크기에서 최대 선형 주소나 세그먼트 오프셋은 FFFFH (216 - 1)을 가진다. 피연산자 크기는 일반적으로 8비트 이거나 16비트다.

32비트 주소로 배정할 때, 논리 주소 (또는 원거리 포인터)는 16비트 세그먼트 셀렉터와 32비트 오프셋으로 구성된다. 16비트 주소 배정을 사용할 때, 주소는 16비트 세그먼트 셀렉터와 16비트 오프셋으로 구성된다.

명령 접두사를 사용하면 프로그램 내에 기본 주소 및/또는 피연산자 크기를 임시로 대체하도록 허용한다.

보호 모드에서 동작할 때, 현재 실행중인 코드 세그먼트를 위한 세그먼트 디스크립터가 기본 주소와 피연산자 크기를 정의한다. 세그먼트 디스크립터는 응용 프로그램 코드에서 일반적으로 볼 수 없는 데이터 구조다. 어셈블러 지시문을 사용하면 프로그램에서 기본 주소 배정과 피연산자 크기를 선택하도록 허용한다. 어셈블러와 다른 도구는 코드 세그먼트에 대한 세그먼트 디스크립터를 적절하게 설정한다.

실제 주소 모드에서 동작할 때 기본 주소 배정과 피연산자 크기는 16비트다. 32비트 주소 배정을 사용하려면 실제 주소 모드에서 주소 크기만큼 대체하여 사용할 수 있다. 그러나 최대로 허용되는 32비트 선형 주소는 여전히 000FFFFFH (220 - 1)이다.

3.3.6. 보호 모드에서 확장된 물리적 주소 배정(Extended Physical Addressing in Protected Mode)

P6 제품군 프로세서부터 시작한 IA-32 아키텍처는 최대 64GB(236 바이트)의 물리 메모리 주소 배정을 지원한다. 프로그램이나 작업이 주소 공간에 직접적으로 배정할 수 없다. 대신, 가상 메모리 관리 메커니즘을 통해 64GB 물리적 주소 공간에 매핑되는 최대 4GB 개별 선형 주소 공간으로 처리한다. 이 메커니즘을 사용하면 운영 체제는 프로그램이 64GB 물리 주소 공간 안에 4GB 선형 주소 공간 전환이 가능하다.

확장된 물리 주소 배정을 사용하려면 프로세서가 보호 모드에서 작동해야하며, 운영 체제는 가상 메모리 관리 시스템을 제공한다. 더 자세한 정보는 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 3장 "36-Bit Physical Addressing Using the PAE Paging Mechanism"과 "Protected-Mode Memory Management"를 살펴본다.

3.3.7. 64 비트 모드에서 주소 계산(Address Calculations in 64-Bit Mode)

대부분의 경우, 64비트 모드는 코드, 데이터 그리고 스택을 위해 평면 데이터 주소를 사용한다. 64비트 모드(주소 크기만큼 대체하지 않는 경우), 유효하게 주소를 계산한 크기는 64비트다. 유효한 주소 계산은 64비트 기반 및 인덱스 레지스터를 사용하고, 변위를 64비트로 부호 확장한다.

64비트 모드의 평면 주소 공간에서, 선형 주소는 기본 주소가 0이기 때문에 유효 주소와 같다. FS나 GS 세그먼트가 0 기반이 아닌 형태와 함께 사용되는 경우 규칙은 적용되지 않는다. 64비트 모드에서 유효 주소 구성 요소가 추가되고 전체 64비트 세그먼트 기반을 추가하기 전에 유효 주소가 절단(명령어 LEA를 참조)된다. 64비트 모드에서 주소 배당 모드에 관계없이 기본은 절대로 절단되지 않는다.

명령 포인터는 64비트 코드 오프셋을 지원하기 위해 64비트로 확장된다. 64비트 명령 포인터는 RIP로 불린다. 표 3-1은 RIP, EIP 그리고 IP 사이의 관계를 보여준다.

일반적으로, 64비트에서 변위적이고 즉각적인 것은 64비트로 확장되지 않는다. 유효 주소 계산 중에는 여전히 32비트와 부호 확장으로 제한된다. 하지만 64비트 모드에서는 MOV 명령의 변위적이고 즉각적인 64비트를 위한 형태를 제공하여 지원한다.

모든 16비트와 32비트 주소 계산은 IA-32e 모드에서 제로 베이스로 확장되어 64비트 주소를 형성한다. 주소 계산은 현재 모드의 유효 주소 크기(64비트 모드나 호환 모드)로 잘려지며, 모든 주소 크기 접두사에 의해 덮어쓰인다. 그 결과 전체 64비트 주소 폭으로 제로 기반으로 확장된다. 이 때문에 호환 모드에서 16비트와 32비트 응용 프로그램 실행은 64비트 모드 유효 주소의 하위 4GB에서만 접근할 수 있다. 마찬가지로, 64비트 모드에서 생성된 32비트 주소는 64비트 모드 유효 주소의 하위 4GB에만 접근할 수 있다.

3.3.7.1. 표준 주소 배정(Canonical Addressing)

64 비트 모드에서 주소는 마이크로 아기텍처에 의해 63 비트 내지 최상위로 구현된 비트가 모두 1 또는 0으로 설정되면 정식 형식으로 간주한다.

Intel 64 아키텍처는 64 비트 선형 주소를 정의한다. 구현은 더 작은 비트를 지원할 수 있다. Intel 64 아키텍처를 사용하는 IA-32 프로세서의 첫 번째 구현은 48 비트 선형 주소를 지원한다. 다시 말해서, 표준 주소는 64에서 48 비트를 0 또는 1로 설정해야 한다. (비트 47이 0인지 1인지에 따라 다름)

구현은 64 비트의 선형 주소를 모두 사용할 수 없지만, 최상위 구현 비트를 통해 63 비트를 검사하여 주소가 표준 형식인지 확인한다. 선형 메모리 참조가 표준 형식이 아닌 경우, 구현시 예외를 생성한다. 대부분의 경우 일반 보호 예외(#GP)가 생성된다. 그러나 명시적이거나 묵시적 스택 참조의 경우, 스택 오류 (#SS)가 생성된다.

묵시적인 스택 참조하는 명령은 기본적으로 SS 세그먼트 레지스터를 사용한다. 여기에는 PUSH/POP 관련 명령과 RSP/RBP를 사용하는 명령을 포함한다. 이 경우 표준 오류는 #SS다.

명령어가 기본 레지스터 RSP/RBP를 사용하고 세그먼트 재지정 접두사를 사용하여 비-SS 세그먼트를 지정하는 경우 표준 오류로 (#SS 대신) #GP를 생성한다. 64 비트 모드에서 FS와 GS 세그먼트 재지정만 이 상황에서 적용된다. 다른 세그먼트 재지정 접두사 (CS, DS, ES 그리고 SS)는 무시된다. 이 또한 "비-스택" 레지스터 참조에 적용된 SS 세그먼트 재정의가 무시된다는 것을 의미한다. 이러한 시퀀스는 여전히 표준 오류 (#SS가 아닌) #GP를 생성한다.

3.4. 기본 프로그램 실행 레지스터(Basic Program Execution Registers)

아키텍처는 일반 시스템과 애플리케이션 프로그래밍에서 사용하기 위해 16개의 기본 프로그램 실행 레지스터를 제공한다. 이 레지스터는 다음과 같이 그룹화 할 수 있다.

  • 범용 레지스터(General-purpose registers) - 이 8개의 레지스터는 피연산자의 포인터를 저장하는데 사용한다.
  • 세그먼트 레지스터(Segment registers) - 이 레지스터는 최대 6개의 세그먼트 셀렉터를 보유한다.
  • EFLAGS (프로그램 상태 및 제어) - 레지스터 EFLAGS 레지스터는 실행된 프로그램의 상태를 보고하고 프로세서의 제한된 (응용 프로그램 레벨) 제어를 허용한다.
  • EIP (명령 포인터) - 레지스터 EIP 레지스터는 실행될 다음 명령에 대한 위치를 32비트 포인터의 크기만큼 가진다.

3.4.1. 범용 레지스터(General-Purpose Registers)

32 비트 범용 레지스터 EAX, EBX, ECX, EDX, ESI, EDI, EBP, 그리고 ESP는 다음 항목의 기능을 제공한다.

  • 논리 및 산술 연산자 용 피연산자
  • 주소 계산을 위한 피연산자
  • 메모리 포인터

이러한 모든 레지스터는 피연산자, 결과(result) 그리고 포인터의 일반적인 저장에 사용할 수 있으며, ESP 레지스터를 참조할 때는 주의해야한다. ESP 레지스터는 스택 포인터를 가지고 있으며, 일반적으로 다른 목적으로 사용해서는 안된다.

많은 명령이 특정 레지스터에 할당하여 피연산자를 보유한다. 예를 들어, 문자열 명령은 ECX, ESI 그리고 EDI 레지스터의 내용을 피연산자로 사용한다. 분할된 메모리 모델을 사용할 때 일부 명령은 어떤 레지스터의 포인터가 특정 세그먼트와 관련있다고 가정한다. 예를 들어, 일부 명렁은 EBX 레지스터의 포인터가 DS 세그먼트의 메모리 위치를 가리키는 것으로 가정한다.

명령으로 범용 레지스터를 특수하게 사용하는 방법은 5장 "Instruction Set Summary"을 참고한다. 또한 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volumes 2A, 2B & 2C의 3장, 4장, 5장을 참조한다. 다음은 특수 용도에 대한 요약이다.

  • EAX - 피연산자와 결과 데이터 누산기
  • EBX - DS 세그먼트의 데이터에 대한 포인터
  • ECX - 문자열 및 반복 연산을 위한 카운터
  • EDX - I/O 포인터
  • ESI - DS 레지스터가 가리키는 세그먼트의 데이터에 대한 포인터. 문자열 연산을 위한 소스 포인터
  • EDI - ES 레지스터가 가리키는 세그먼트의 데이터 (또는 대상)에 대한 포인터. 문자열 연산을 위한 대상 포인터
  • ESP - 스택 포인터 (SS 세그먼트에서)
  • EBP - 스택의 데이터에 대한 포인터 (SS 세그먼트에서)

그림 3-5에서 보듯이 범용 레지스터의 하위 16 비트는 8086과 인텔 286 프로세서에 있는 레지스터 집합에 직접적으로 매핑되며 AX, BX, CX, DX, BP, SI, DI 그리고 SP 이름으로 참조될 수 있다. EAX, EBX, ECX 그리고 EDX 레지스터의 각각의 하위 2 바이트는 AH, BH, CH, DH (상위 바이트)와 AL, BL, CL, DL (하위 바이트) 이름으로 참조된다.

3.4.1.1. 64비트 모드에서 범용 레지스터(General-Purpose Registers in 64-Bit Mode)

64비트 모드에서, 16 개의 범용 레지스터가 있고, 기본 피연산자 크기는 32비트다. 그러나, 범용 레지스터는 32비트나 64비트 피연산자로 작업할 수 있다. 피연산자 크기가 32비트로 지정된 경우 EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP, R8D - R15D를 사용할 수 있다. 피연산자 크기가 64비트로 지정된 경우 RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8-R15를 사용할 수 있다. R8D-R15D/R8-R15는 새로운 범용 레지스터를 나타낸다. 이 모든 레지스터는 바이트, 워드, d워드 그리고 q워드 수준에서 접근할 수 있다. REX 접두어는 피연산자 크기를 64비트로 생성하거나 레지스터 R8-R15를 참조하는데 사용된다.

64비트 모드(R8-R15와 XMM8-XMM15)에서만 사용 가능한 레지스터는 64비트 모드에서 호환 모드로 전환 한 후 64비트 모드로 다시 전환되는 동안 보존된다. 그러나, R8-R15와 XMM8-XMM15의 값은 64비트 모드에서 옛날의 호환 모드나 실제 모드로 전환한 후에나 호환 모드를 통해 64비트 모드로 돌아가면 정의되지 않는다.

64비트 모드에서 바이트 레지스터 접근하는 것을 제한한다. 명령은 예전의 상위 바이트(예, AH, BH, CH, DH)와 새 바이트 레지스터 중 하나를 동시에 참조할 수 없다. (예, RAX 레지스터의 하위 바이트) 하지만, 명령은 예전의 하위 바이트(예, AL, BL, CL 또는 DL)와 새로운 바이트 레지스터(예, R8 레지스터의 하위 바이트나 RBP)를 동시에 참조 할 수 있다. 아키텍처는 접두사 REX를 사용하는 명령에 대해 상위 바이트(AH, BH, CH, DH) 참조를 하위 바이트(BPL, SPL, DIL, SIL: RBP, RSP, RDI 그리고 RSI의 하위 8비트) 참조로 변경함으로써 제한적으로 적용한다.

64비트 모드에서 피연산자 크기는 대상(destination) 범용 레지스터의 유효 비트수를 결정한다.

  • 64비트 피연산자는 대상 범용 레지스터에서 64비트 결과를 생성한다.
  • 32비트 피연산자는 대상 범용 레지스터에서 64비트 결과로 제로 기반으로 확장된 32비트 결과를 생성한다.
  • 8비트와 16비트 피연산자는 8비트와 16비트 결과를 생성한다. 대상 범용 레지스터의 48비트나 56비트 이상은 연산에 의해 수정되지 않는다. 8비트나 16비트 연산의 결과가 64비트 주소 계산을 위해 예정된 경우 명시적으로 레지스터를 전체 64비트로 부호 확장한다.

64비트 범용 레지스터의 상위 32비트는 32비트 모드에서 정의되지 않았으므로 64비트 모드에서 32비트 모드로 전환 할때 범용 레지스터의 상위 32비트는 모존되지 않는다. (보호 모드 또는 호환 모드) 64비트에서 32비트 모드로 전환한 후에는 소프트웨어가 이 비트에 의존해서는 안된다.

3.4.2. 세그먼트 레지스터(Segment Registers)

세그먼트 레지스터 (CS, DS, SS, ES, FS 그리고 GS)는 16 비트 세그먼트 셀렉터를 보유한다. 세그먼트 셀렉터는 메모리의 세그먼트를 식별하는 특수 포인터다. 메모리의 특정 세그먼트에 접근하는 것은, 해당 세그먼트의 세그먼트 셀렉터가 세그먼트 레지스터에 있어야 한다.

응용프로그램 코드를 작성할 때, 프로그래머는 일반적으로 어셈블러 지시문과 심볼을 사용하여 세그먼트 선택기를 만든다.어셈블러와 기타 도구는 이러한 지시문과 심볼과 관련된 실제 세그먼트 셀렉터 값을 만든다. 시스템 코드를 작성하는 경우, 프로그래머는 세그먼트 셀렉터를 직접 작성해야 할 수 있다. 자세한 정보는 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 3장 "Protected-Mode Memory Management"를 참조한다.

세그먼트 레지스터를 사용하는 방법은 운영체제나 executive가 사용하는 메모리 관리 모델 유형에 따라 다르다. 평면(비분할) 메모리 모델을 사용할 때, 세그먼트 레지스터는 중첩 세그먼트를 가리키는 세그먼트 셀렉터를 로드하며, 각 세그먼트는 선형 주소 공간의 주소 0에서 시작한다. (그림 3-6) 이러한 중첩 세그먼트는 프로그램의 선형 주소 공간을 구성한다. 일반적으로 두 개의 중첩 세그먼트는 정의된다. 하나는 코드고 다른 하나는 데이터와 스택이다. CS 세그먼트 레지스터 포인터는 코드 세그먼트를 가리키고, 모든 다른 세그먼트 레지스터 포인터는 데이터와 스택 세그먼트를 가리킨다.

분할된 메모리 모델을 사용할 때, 각 세그먼트 레지스터는 일반적으로 다른 세그먼트 셀렉터로 로드되어 각 세그먼트 레지스터는 선형 주소 공간 안에 다른 세그먼트를 가리킨다. (그림 3-7을 참조) 따라서 프로그램은 언제든지 선형 주소 공간에서 최대 6 개의 세그먼트에 접근할 수 있다. 세그먼트 레지스터 중 하나를 가리키고 있지 않은 세그먼트에 접근하는 것은, 프로그램이 먼저 접근할 세그먼트의 세그먼트 셀렉터를 세그먼트 레지스터에 로드해야 한다.

각 세그먼트 레지스터는 코드, 데이터 또는 스택의 세 가지 유형 중 하나와 연결된다. 예를 들어, CS 레지스터에는 실행되었거나 저장된 코드 세그먼트에 대한 세그먼트 셀렉터가 포함된다. EIP 레지스터에는 실행 될 다음 명령어의 코드 세그먼트 안에 오프셋이 포함된다. CS 레지스터는 응용프로그램에 의해 명시적으로 로드될 수 없다. 대신, 프로그램 제어(예, 프로시저 호출, 인터럽트 처리 또는 작업전환)를 변경하는 내부 프로세서 동작이나 명령에 의해 암시적으로 로드된다.

DS, ES, FS 그리고 GS 레지스터는 네 개의 데이터 세그먼트를 가리킨다. 네 개의 데이터 세그먼트를 사용할 수 있으므로, 서로 다른 유형의 데이터 구조에 효율적이고 안전하게 접근할 수 있다. 예를 들어, 네 개의 개별 데이터 세그먼트가 생성될 수 있다. 하나는 현재 모듈의 데이터 구조, 다른 하나는 상위 모듈에서 보낸 데이터, 또 다른 하나는 동적으로 생성된 데이터 구조, 마지막 네번째는 다른 프로그램과 함께 공유된 데이터다. 추가 데이터 세그먼트에 접근하는 것은 응용프로그램이 필요에 따라 이러한 세그먼트에 대한 세그먼트 셀렉터를 DS, ES, FS 그리고 GS 레지스터에 로드해야 한다.

SS 레지스터에는 현재 실행중인 프로그램, 작업이나 처리기에 대한 프로시저 스택이 저장되는 스택 세그먼트에 대한 세그먼트 셀렉터가 포함된다. 모든 스택 연산은 SS 레지스터를 사용하여 스택 세그먼트를 찾는다. CS 레지스터와 달리 SS 레지스터는 명시적으로 로드할 수 있으므로, 응용 프로그램이 여러 스택과 이들 사이를 전환하도록 설정할 수 있다.

세그먼트 레지스터가 실제 주소 모드에서 사용되는 방법에 대한 내용은 3.3 절 "Memory Organization"을 참조한다.

4 개의 세그먼트 레지스터 CS, DS, SS 그리고 ES는 Intel 8086과 Intel 286 프로세서에 있는 세그먼트 레지스터와 동일하며, FS와 GS 레지스터는 Intel 386™ 프로세서 제품군의 IA-32 아키텍처에 도입되었다.

3.4.2.1. 64 비트 모드에서 세그먼트 레지스터(Segment Registers in 64-Bit Mode)

64비트 모드에서 CS, DS, ES, SS는 연관된 세그먼트 디스크립트 기준의 값과 관계없이 각 세그먼트 기준이 0인것 처럼 처리된다. 이렇게 하면 코드, 데이터, 스택에 대한 평면 주소 공간이 만들어진다. FS와 GS는 예외다. 두 세그먼트 레지스터는 선형 주소 계산(로컬 데이터와 특정 운영 체제 데이터 구조의 주소 배정)에서 추가 기본 레지스터로 사용될 수 있다.

분활화가 일반적으로 불가능 하더라도, 세그먼트 레지스터로 인해 프로세서가 세그먼트 접근을 돕도록 수행할 수 있다. 이러한 작업을 수행하는 동안 활성화된 프로세서는 로드된 값에 대한 기존(legacy) 검사를 지속적으로 대부분 수행한다. (검사가 64 비트 모드에서 적용되지 않은 경우에도) 64 비트 모드에서 로드된 세그먼트 레지스터가 호환 모드에서 실행되는 응용프로그램에서 사용될 수 있기에 이러한 검사가 필요하다

64비트 모드에서 CD, DS, ES, SS, FS 그리고 GS의 검사 한계가 비활성화 된다.

3.4.3. EFLAGS 레지스터(EFLAGS Register)

32비트 EFLAGS 레지스터는 상태 플래그, 제어 플래그, 그리고 시스템의 그룹 플래그를 포함한다. 그림 3-8은 이 레지스터 안의 플래그를 정의한다. 프로세서 초기화 (RESET 핀 또는 INIT 핀을 주장함(asserting)으로써) 후 EFLAGS 레지스터의 상태는 00000002H다. 이 레지스터 비트는 1, 3, 5, 15 그리고 22 부터 31은 예약되어 있다. 소프트웨어는 이러한 비트의 상태를 사용하거나 종속해서는 안된다.

EFLAGS 레지스터의 일부 플래그는 특수 목적 명령(다음 절에서 설명)을 사용하여 직접 수정할 수 있다. 전체 레지스터를 직접 검토하거나 수정할 수 있는 명령은 없다. LAHF, SAHF, PUSHF, PUSHFD, POPF 그리고 POPFD 명령은 절차(procedure) 스택이나 EAX 레지스터에서 플래그의 그룹을 옮기는데 사용할 수 있다. EFLAGS 레지스터의 내용이 절차(procedure) 스택이나 EAX 레지스터로 부터 전송 받은 후 플래그는 프로세서의 비트 조작 명령 (BT, BTS, BTR 그리고 BTC0를 사용하여 검사하고 수정할 수 있다.

작업을 일시 중단 할 때 (프로세서의 멀티 태스킹 기능 사용), 프로세서는 일시 중단되는 작업에 대한 EFLAGS 레지스터의 상태를 작업 상태 세그먼트(TSS)에 자동으로 저장한다. 새로운 작업에 자체적으로 바인딩 할 때, 프로세서는 새로운 작업의 TSS로부터 데이터와 함께 EFLAGS 레지스터를 로드한다.

인터럽트 또는 예외 처리기 프로시저에 대한 호출이 발생하면, 프로세서는 EFLAGS 레지스터의 상태를 프로시저 스택에 자동 저장한다. 인터럽트나 예외를 태스크 스위치와 함께 처리될 때, EFLAGS 레지스터의 상태는 일시 중단된 작업을 위해 TSS에 저장된다.

IA-32 아키텍처가 발전함에 따라, 플래그가 EFLAGS 레지스터에 추가되었지만, 기존 플래그의 기능과 배치는 IA-32 프로세서 제품군에서 다음 버전으로 동일하게 유지되었다. 결과적으로, IA-32 프로세서의 한 패밀리에 대해 이러한 플래그에 접근하거나 수정하는 코드는 나중에 프로세서의 제품군에서 실행될 때 예상대로 동작한다.

3.4.3.1. 상태 플래그(Status Flags)

EFLAGS 레지스터의 상태 플래그 (비트 0, 2, 4, 6, 7 그리고 11)은 ADD, SUB, MUL 그리고 DIV 명령과 같은 산술 명령의 결과를 나타낸다. 상태 플래그 기능은 다음과 같다.

CF (bit 0) / 캐리 플래그 (Carry Flag) - 산술 연산이 결과의 최상위 비트에서 carry나 borrow를 생성하는 경우 set되며 그렇지 않으면 clear 된다. 이 플래그는 부호 없는 정수 연산의 오버플로우 조건을 나타낸다. 또한 다중 정밀도 산술에도 사용된다.

PF (bit 2) / 패리티 플래그(Parity Flag) - 결과의 최하위 바이트가 1 비트의 짝수를 포함하면 set되며 그렇지 않으면 clear된다.

AF (bit 4) / 보조 캐리 플래그(Auxiliary Carry Flag) - 산술 연산이 결과의 비트 3에서 carry나 borrow를 생성하는 경우 set되며 그렇지 않으면 clear된다. 이 플래그는 이진화 십진법(BCD, Binary-Coded Decimal) 산술에 사용된다.

ZF (bit 6) / 제로 플래그(Zero Flag) - 결과가 0인 경우 set되며 그렇지 않으면 clear된다.

SF (bit 7) / 사인 플래그(Sign Flag) - 부호있는 정수의 부호 비트인 결과의 최상위 비트와 동일하게 set한다. (0은 양수이고 1은 음수다.)

OF (bit 11) / 오버플로우 플래그(Overflow Flag) - 정수 결과가 대상 피연산자에 맞도록 양수가 너무 크거나 음수가 너무 작으면 (부호 비트 제외) set한고 그렇지 않으면 clear한다. 이 플래그는 부호 있는 정수 (2의 보수) 산술에 대한 오버플로우 조건을 나타낸다.

이 상태 플래그 중에서 STC, CLC 그리고 CMC 명령을 사용하여 CF 플래그만 직접 수정할 수 있다. 또한 비트 명령 (BT, BTS, BTR 그리고 BTC)는 지정된 비트를 CF 플래그에 복사한다.

상태 플래그는 단일 산술 연산이 부호 없는 정수, 부호 있는 정수 그리고 BCD 정수 세 가지 다른 데이터 유형에 대한 결과를 생성할 수 있다. 산술 연산의 결과가 부호 없는 정수로 처리되면, CF 플래그는 범위를 벗어난 조건(carry나 borrow)을 나타낸다. 부호 있는 정수 (2의 보수)로 취급 될 경우, F 플래그는 carry 또는 borrow를 나타낸다. 그리고 BCD 자리로 처리되면 AF 플래그는 carry 또는 borrow를 나타낸다. SF 플래그는 부호 있는 정수의 부호를 나타낸다. ZF 플래그는 부호가 있거나 부호가 없는 정수 0을 나타낸다.

정수에 대해 다중 정밀도 산술 연산을 수행할 때, CF 플래그는 carry를 추가(ADC)와 borrow 제거(SBB) 명령과 함께 사용되어 하나의 계산에서 다음 계산으로 carry 또는 borrow를 전달한다.

조건 명령 Jcc (jump on condition code cc), SETcc (byte set on condition cod ecc), LOOPcc 그리고 CMOVcc (conditional move)는 하나 이상의 상태 플래그를 조건 코드로 사용하여 분기(branch), 셋바이트(setbyte) 또는 엔드 루프 조건(end-loop conditions)를 테스트한다.

3.4.3.2. DF 플래스(DF Flag)

방향 플래그(Direction Flag) (DF, EFLAGS 레지스터의 비트 10에 위치)는 문자열 명령(MOVS, CMPS, SCAS, LODS 그리고 STOS)을 제어한다. DF 플래그를 set하면 문자열 명령이 자동으로 감소한다. (높은 주소에서 낮은 주소로 문자열을 처리하기 위해) DF 플래그를 clear하면 문자열 명령이 자동으로 증가한다. (낮은 주소에서 높은 주소로 문자열을 처리)

STD와 CLD 명령은 각 DF 플래그를 set하고 clear한다.

3.4.3.3. 시스템 플래그와 IOPL 필드(System Flags and IOPL Field)

EFLAGS 레지스터의 시스템 플래그와 IOPL 필드는 운영체제나 executive operations을 제어한다. 응용 프로그램에 의해 수정되어서는 안된다. 시스템 플래그의 기능은 다음과 같다.

TF (bit 8) / 트랩 플래그 - 디버깅을 위한 단일 단계 모드를 활성화하기 위해서 set되고 그렇지 않으면 clear한다.

IF (bit 9) / 인터럽트 활성 플래그 - 마스킹 가능한 인터럽트 요청에 대한 프로세서의 응답을 제어한다. 마스킹이 가능한 인터럽트에 응답하려면 set하고, 그렇지 않으면 clear한다.

IOPL (bits 12 and 13) / I/O 권한 레벨 필드 - 현재 실행중인 프로그램이나 작업의 I/O 권한 레벨을 나타낸다. 현재 실행중인 프로그램이나 작업의 현재 권한 레벨(CPL, Current Privilege Level)은 I/O 주소 공간에 접근하기 위해 I/O 권한 레벨보다 작거나 같아야한다. POPF와 IRET 명령은 CPL이 0일 때만 필드를 수정할 수 있다.

NT (bit 14) / 중첩 작업 플래그 - 중단 및 호출된 작업의 연결을 제어한다. 현재 작업이 이전에 실행된 작업에 연결될 때 set된다. 연결되어 있지 않으면 clear된다.

RF (bit 16) / 재시작 플래그 - 디버그 예외에 대한 프로세서의 응답을 제어한다.

VM (bit 17) / Virtual-8086 모드 플래그 - virtual-8086 모드 활성화하면 set하고 virtual-8086 모드의 의미없이 보호 모드로 돌아가려면 clear한다.

AC (bit 18) / 계열 점검 (또는 접근 제어) 플래그 - AM 비트가 CR0 레지스터에 set되면 플래그가 1인 경우에만 사용자 모드 데이터 접근의 계열 검사가 활성화된다.

SMAP 비트가 CR4 레지스터에 설정된 경우 비트가 1이면 사용자 모드 페이지에 대한 명시적 감독 모드(supervisor-mode)의 데이터 접근이 허용된다. 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 4.6절 "Access Rights"를 참고한다.

VIF (bit 19) / 가상 인터럽트 플래그 - IF 플래그의 가상 이미지다. VIP 플래그와 함께 사용된다. (이 플래그와 VIP 플래그를 사용하려면 제어 레지스터 CR4의 VME 플래그를 설정하여 가상 모드 확장을 사용할 수 있다.)

VIP (bit 20) / 가상 인터럽트 보류 플래그 - 인터럽트가 보류중임을 나타낼때 set하고 아닐땐 clear한다. (소프트웨어는 이 플래그를 set과 clear하고 프로세서는 읽을 수만 있다.) VIF 플래그와 함께 사용된다.

ID (bit 21) / 식별 플래그 - 이 플래그를 설정하거나 지울 수 있는 프로그램의 기능은 CPUID 명령에 대한 지원을 나타낸다.

이러한 플래그의 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A의 3장 "Protected-Mode Memory Management"을 참조한다.

3.4.3.4. 64 비트 모드에서 RFLAGS 레지스터(RFLAGS Register in 64-Bit Mode)

64 비트 모드에서 EFLAGS는 64 비트로 확장되어 RFLAGS로 불린다. RFLAGS 레지스터의 상위 32 비트는 예약되어 있다. RFLAGS의 하위 32 비트는 EFLAGS와 동일하다.

3.5. 명령 포인터(Instruction Pointer)

명령 포인터(EIP) 레지스터는 실행될 다음 명령에 대한 현재 코드 세그먼트의 오프셋을 포함한다. JMP, Jcc, CALL, RET 그리고 IRET 명령을 실행할 때 하나의 명령 경계에서 다음 직선 코드로 진행되거나 여러 명령어로 앞뒤로 이동한다.

EIP 레지스터는 소프트웨어로 직접 접근할 수 없다. 제어 전달 명령, 인터럽트 그리고 예외에 대해 묵시적으로 제어된다. EIP 레지스터를 읽는 유일한 방법은 CALL 명령을 실행한 다음 프로시저 스택에서 반환 명령 포인터의 값을 읽는 것이다. EIP 레지스터는 프로시저 스택의 반환 명령 포인터 값을 수정하고 반환 명령 (RET나 IRET)를 실행하여 간접적으로 로드할 수 있다. 자세한 정보는 6.2.5.2 절 "Returen Instruction Pointer"를 참조한다.

모든 IA-32 프로세서는 명령을 프리페치(prefetch)한다. 명령 프리페치로 인해 명령을 로드하는 동안 버스로 부터 읽은 명령 주소가 EIP 레지스터의 값과 일치하지 않는다. 다른 프로세서 세대가 다른 프리페치 메커니즘을 사용하더라도 프로그램 흐름을 지시하는 EIP 레지스터의 기능은 IA-32 프로세서에서 실행되도록 작성된 모든 소프트웨어와 완벽하게 호환된다.

3.5.1. 64 비트 모드에서 명령 포인터(Instruction Pointer in 64-Bit Mode)

64 비트 모드에서 RIP 레지스터가 명령 포인터다. 이 레지스터는 실행된 다음 명령의 64 비트 오프셋을 유지한다. 64 비트 모드는 RIP 상대 주소 배정이라는 기술도 지원한다. 이 기술을 사용하면, 유표 주소는 다음 명령의 RIP에 변위를 추가하도록 결정된다.

3.6. 피연산자 크기와 주소 크기 속성(Operand-Size And Address-Size Attributes)

프로세서가 보호 모드에서 실행할 때 모든 코드 세그먼트는 주소 크기 속성과 피연산자 크기 속성이 있다. 이러한 속성은 코드 세그먼트를 위한 세그먼트 디스크립터의 D (기본 크기)플래그로 선택된다. (자세한 내용은 Intel® 64 and IA-32 Architectures  Software Developer’s Manual, Volume 3A의 3장 "Protected-Mode Memory Management"를 참조한다. D 플래그가 set되면 32 비트 피연산자 크기와 주소 크기 속성이 선택된다. 플래그가 clear할 때, 16 비트 크기 속성은 선택된다. 프로세서가 실제 주소 모드, virtual-8086 모드 또는 SMM에서 실행할 때, 기본 피연산자 크기와 주소 크기 속성은 항상 16 비트로 구성된다.

피연산자 크기 속성은 피연산자의 크기를 선택한다.16 비트 피연산자 크기 속성으로 적용할 때, 피연산자는 일반적으로 8 비트나 16 비트일 수 있으며, 32 비트 피연산자 크기 속성으로 적용한 경우, 피연산자는 일반적으로 8 비트 또는 32 비트가 될 수 있다.

주소 크기 속성은 메모리 주소 배정에 사용되는 주소의 크기 16비트나 32비트를 선택한다. 16 비트 주소 크기 속성으로 적용할 때, 세그먼트 오프셋과 변위는 16비트다. 이 제한 사항은 세그먼트의 크기를 64KB로 제한한다. 32 비트 주소 크기 속성으로 적용될 때 세그먼트 오프셋과 변위는 32 비트이므로 최대 4GB를 처리할 수 있다.

기본 피연산자 크기 속성과 또는 주소 크기 속성은 명령에 피연산자 크기 속성과 주소 크기 속성 접두사를 추가하여 특정 명령을 무시할 수 있다. 자세한 내용은 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 2A의 2장 "Instruction Format"을 참조한다. 이 접두어의 효과는 대상 명령에만 적용된다.

표 3-4는 D 플래그와 피연산자 크기 그리고 주소 크기 접두어의 설정에 따라 유효한 피연산자 크기와 주소 크기(보호 모드나 호환 모드에서 실행한 경우)를 보여준다.

3.6.1. 64비트 모드의 피연산자 크기와 주소 크기(Operand Size and Address Size in 64-Bit Mode)

64 비트 모드에서 기본 주소 크기는 64 비트고 기본 피연산자 크기는 32 비트다. 접두사를 사용하여 기본값을 무시할 수 있다. 주소 크기와 피연산자 크기 접두사를 사용하면 명령별 32/64 비트 데이터와 32/64 비트 주소를 혼합할 수 있다. 표 3-4는 64 비트 모드에서 피연산자 크기를 무시하는데 사용할 수 있는 66H 명령 접두어와 REX.W 접두어 유효한 조합을 보여준다. 64 비트 모드에서 16 비트 주소는 지원하지 않는다.

REX 접두어는 16개의 다른 값으로 구성하는 4비트 필드로 구성된다. REX 접두어에서 W 비트 필드는 REX.W로 부른다. REX.W 필드가 올바르게 set한 경우, 접두사는 64 비트의 피연산자 크기를 무시하도록 지정한다. 소프트웨어는 여전히 피연산자 크기 66H 접두어를 사용하여 16 비트 피연산자 크기로 껏다 켰다할 수 있다. 그러나 REX.W를 설정하면 피연산자 크기 접두사 (66H)보다 우선한다.

SSE/SSE2/SSE3/SSSE3 SIMD 명령의 경우, 66H, F2H, F3H 접두사는 opcode 확장에 필수다. 이 경우 유효한 REX.W 접두어와 66H opcode 확장 접두사 사이에 상호작용은 존재하지 않는다.

자세한 정보는 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 2A의 2장 "Instruction Format"을 참조한다.

3.7. 피연산자 주소 배정(OPERAND ADDRESSING)

IA-32 기계 명령은 0개 이상의 피연산자에서 동작한다. 일부 피연산자는 명시적으로 지정되고, 다른 피연산자는 묵시적으로 지정된다. 근원지(Source) 피연산자에 대한 데이터는 다음 위치에 있다.

  • 명령 자체 (즉시 피연산자)
  • 레지스터
  • 메모리 위치
  • I/O 포트

명령에 대한 목적지(Destination) 피연산자에 데이터를 반환할 때, 다음과 같이 반환될 수 있다.

  • 레지스터
  • 레모리 위치
  • I/O 포트

3.7.1. 직접 피연산자(Immediate Operands)

일부 명령은 명령 자체에서 인코딩된 데이터를 근원지(Source) 피연산자로 사용한다. 이러한 피연산자는 직접 피연산자(또는 단순히 즉각 연산(immediates))로 불린다. 예를 들어 다음 ADD 명령은 EAX 레지스터의 내용에 즉시 값 14를 추가한다.

ADD EAX, 14

모든 산술 명령 (DIV와 IDIV 명령은 제외)은 근원지(Source) 피연산자는 즉시 해당 값을 연산하도록 허용한다. 직접 피연산자에 허용되는 최대 값은 명령에 따다 다르지만 절대 부호 없는 더블 워드 정수(232)의 최대 값보다 클 수 없다.

3.7.2. 레지스터 피연산자(Register Operands)

근원지(Source)와 목적지(Destination) 피연산자는 실행중인 명령에 따라 다음 레지스터 중 하나가 될 수 있다.

  • 32-비트 범용 레지스터 (EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP)
  • 16-비트 범용 레지스터 (AX, BX, CX, DX, SI, DI, SP, BP)
  • 8-비트 범용 레지스터 (AH, BH, CH, DH, AL, BL, CL, DL)
  • 세그먼트 레지스터 (CS, DS, SS, ES, FS, GS)
  • EFLAGS 레지스터
  • x87 FPU 레지스터 (ST0부터 ST7, status word, control word, tag word, data operand pointer, and instruction pointer)
  • MMX 레지스터 (MM0부터 MM7)
  • XMM 레지스터 (XMM0부터 XMM7)와 the MXCSR 레지스터
  • 제어 레지스터 (CR0, CR2, CR3, CR4)와 시스템 테이블 포인터 레지스터(GDTR, LDTR, IDTR, 작업 레지스터)
  • 디버그 레지스터 (DR0, DR1, DR2, DR3, DR6, and DR7)
  • MSR 레지스터

일부 명령은 한쌍의 32 비트 레지스터에 포함된 쿼드워드 피연산자를 사용한다. 레지스터 쌍은 이를 구분하기 위해 콜론으로 표시된다. 예를 들어, 레지스터 쌍 EDX:EAX에서 쿼드워드 피연산자의 EDX는 상위 명령 비트를 포함하고, EAX는 하위 명령 비트를 포함한다.

EFLAGS 레지스터의 내용을 로드하고 저장하거나 레지스터의 개별 플래그를 set하거나 clear하는데 필요한 몇 가지 명령(PUSHFD와 POPFD 명령 같은)이 제공된다. 다른 명령(Jcc 명령과 같은)은 분기 또는 기타 의사 결정 작업을 위한 조건 코드로 EFLAGS 레지스터에서 상태 플래그의 상태를 사용한다.

프로세서는 메모리 관리, 인터럽트와 예외 처리, 작업 관리, 프로세서 관리 그리고 디버깅 활동을 제어하는데 사용되는 시스템 레지스터의 집합을 포함한다. 이러한 시스템 레지스터의 일부는 시스텀 명령의 집합을 통해 응용프로그램, 운영 체제 또는 executive가 접근할 수 있다. 시스템 명령과 함께 시스템 레지스터에 접근할 때, 레지스터는 일반적으로 명령의 묵시적인 피연산자다.

3.7.2.1. 64-비트 모드에서 레지스터 피연산자(Register Operands in 64-Bit Mode)

64 비트 모드의 레지스터 피연산자는 다음 중 하나 일 수 있다.

  • 64-비트 범용 레지스터 (RAX, RBX, RCX, RDX, RSI, RDI, RSP, RBP, or R8-R15)
  • 32-비트 범용 레지스터 (EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP, or R8D-R15D)
  • 16-비트 범용 레지스터 (AX, BX, CX, DX, SI, DI, SP, BP, or R8W-R15W)
  • 8-비트 범용 레지스터: AL, BL, CL, DL, SIL, DIL, SPL, BPL, 그리고 R8L-R15L은 REX 접두어를 사용할 수 있다. AL, BL, CL, DL, AH, BH, CH, DH는 REX 접두어 없이 사용할 수 있다.
  • 세그먼트 레지스터 (CS, DS, SS, ES, FS, and GS)
  • RFLAGS 레지스터
  • x87 FPU 레지스터 (ST0부터 ST7까지, 상태 워드, 제어 워드, 태그 워드, 데이터 피연산자 포인터, 명령 포인터)
  • MMX 레지스터 (MM0 through MM7)
  • XMM 레지스터 (XMM0 through XMM15) and the MXCSR register
  • 제어 레지스터 (CR0, CR2, CR3, CR4, and CR8) and system table pointer registers (GDTR, LDTR, IDTR, and task register)
  • 디버그 레지스터 (DR0, DR1, DR2, DR3, DR6, and DR7)
  • MSR 레지스터
  • RDX:RAX 레지스터 128 비트 피연산자를 나타내는 쌍

3.7.3. 메모리 피연산자(Memory Operands)

메모리에서 근원지(Source)와 목적지(Destination) 피연산자는 세그먼트 셀렉터와 오프셋을 통해 참조된다. (그림 3-9) 세그먼트 셀렉터는 피연산자를 포함하는 세그먼트를 지정한다. 오프셋은 피연산자의 선형 또는 유효 주소를 지정한다. 오프셋은 32 비트 (표기법 m16:32로 표시)나 16 비트(표기법 m16:16으로 표시)가 될 수 있다.

3.7.3.1. 64 비트에서 메모리 피연산자(Memory Operands in 64-Bit Mode)

64-비트 모드에서 메모리 피연산자는 세그먼트 셀렉터와 오프셋에 의해 참조될 수 있다. 오프셋은 16 비트, 32 비트 또는 64 비트일 수 있다. (그림 3-10)

3.7.4. 세그먼트 셀렉터 지정(Specifying a Segment Selector)

세그먼트 셀렉터는 명시적이나 묵시적으로 지정할 수 있다. 세그먼트 셀렉터 지정의 일반적인 방법은 세그먼트 레지스터에 로드한 다음 프로세서가 수행중인 작업 유형에 따라 묵시적으로 레지스터를 선택하도록 허용한다. 프로세서는 표 3-5에서 주어진 규칙에 따라 세그먼트를 자동으로 선택한다.

메모리로부터 데이터를 로드하거나 메모리에 데이터를 저장할 때 DS 세그먼트 기본값은 다른 세그먼트에 접근될 수 있도록 무시할 수 있다. 어셈블러 내에서 세그먼트 재정의는 일반적으로 콜론 ":" 연산자로 처리된다. 예를 들어, 다음 MOV 명령은 EAX 레지스터에서 ES 레지스터가 가리키는 세그먼트로 값을 이동한다. 세그먼트의 오프셋은 EBX 레지스터에 포함된다.

MOV ES:[EBX], EAX;

기계 레벨에서 세그먼트 재정의는 세그먼트-재정의 접두어로 지정되며, 이는 명령의 시작 부분에 배치된 바이트다. 다음 기본 세그먼트 집합은 재정의 할 수 없다.

  • 명령 페치(fetch)는 코드 세그먼트에서 만들어야 한다.
  • 문자열 명령의 목적지 문자열은 ES 레지스터가 가리키는 데이터 세그먼트에 저장해야 한다.
  • push와 pop 동작은 SS 세그먼트를 참조해야 한다.

일부 명령은 세그먼트 셀렉터를 명시적으로 지정되도록 요구한다. 이러한 경우 16-비트 세그먼트 셀렉터는 메모리 위치나 16-비트 레지스터에 위치할 수 있다. 예를 들어, 다음 MOV 명령은 레지스터 BX에 있는 세그먼트 셀렉터를 세그먼트 레지스터 DS로 이동한다.

MOV DS, BX

세그먼트 셀렉터는 메모리에 48-비트 원거리 포인터의 일부로 명시적으로 지정될 수도 있다. 여기서 메모리의 첫번째 더블 워드는 오프셋을 포함하고 다음 워드는 세그먼트 셀렉터를 포함한다.

3.7.4.1. 64-비트 모드에서 세그먼테이션(Segmentation in 64-Bit Mode)

IA-32e 모드에서 세그먼테화의 영향은 프로세서가 호환 모드 또는 64-비트 모드에서 실행되는지 여부에 따라 다르다. 호환 모드에서, 세그먼트화 기능은 기존 IA-32 모드와 동일하게 동작하며, 위에서 설명한 16-비트나 32-비트 보호 모드 의미를 사용한다.

64-비트 모드에서 세그먼트화는 일반적으로 (하지만 완벽하진 않음)비활성화되고, 평면 64-비트 선형 주소 공간을 생성한다. 프로세서는 CS, DS, ES, SS의 세그먼트 기준을 0으로 처리하여 실효 주소와 동일한 선형 주소를 만든다. 예외적으로 FS와 GS 세그먼트가 있으며, 세그먼트 레지스터 (세그먼트 기준을 유지)는  일부 선형 주소 계산에서 추가 기본 레지스터로 사용될 수 있다.

3.7.5. 오프셋 지정(Specifying an Offset)

메모리 주소의 오프셋 부분은 정적인 값 (변위라 부름)으로 직접 지정하거나 다음 구성 요소 중 하나 이상의 방법으로 주소를 계산하여 지정할 수 있다.

  • 변위(Displacement) - 8-비트, 16-비트 또는 32-비트 값
  • 베이스(Base) - 범용 레지스터의 값
  • 인덱스(Index) - 범용 레지스터의 값
  • 축척 계수(Scale factor) - 인젝스 값을 곱한 2, 4 또는 8의 값

이러한 구성 요소를 추가하여 생성한 오프셋을 실효 주소(Effective Address)라고 한다. 이들 각 구성 요소는 긍정과 부정 (2s complement) 값을 가질 수 있으며, scaling factor는 예외다. 그림 3-11은 이러한 구성 요소를 결합하여 선택한 세그먼트에서 유효한 주소를 생상하는 가능한 모든 방법을 보여준다.

base 또는 index 구성 요소로서의 범용 레지스터의 사용은 다음과 같은 방식으로 한정된다.

  • ESP 레지스터는 인젝스 레지스터로 사용할 수 없다.
  • ESP 또는 EBP 레지스타가 base로 사용될 때, SS 세그먼트는 기본 세그먼트이다. 다른 모든 경우에 DS 세그먼트는 기본 세그먼트다.

base, index 그리고 displacement 구성 요소는 어떤 조합으로도 사용될 수 있으며, 이러한 구성 요소 중 무언가는 NULL이 될 수 있다. scale factor는 index가 사용되는 경우에만 사용될 수 있다. 가능한 각 조합은 프로그래머가 고급 언어와 어셈블리 언어에서 일반적으로 사용하는 데이터 구조에 유용하다.

다음 주소 배정 모드는 주소 구성 요소의 일반적인 조합에 대한 사용을 시사한다.

  • Displacement - displacement만이 피연산자에 대한 직접적인(계산되지 않은) 오프셋을 나타낸다. displacement가 명령에서 인코딩되므로, 이 주소 형태를 절대 주소 또는 정적 주소로 부른다. 일반적으로 정적으로 할당된 스칼라 피연산자(scalar operand)에 접근하는데 사용된다.
  • Base - base 만으로 피연산자에 대한 간접 오프셋을 나타낸다. 기본 레지스터의 값이 변경될 수 있으므로 변수와 데이터 구조의 동적 저장에 사용할 수 있다.
  • Base + Displacement - base 레지스터와 displacement를 두 가지 목적으로 함께 사용할 수 있다.
    - 요소 크기가 2, 4 또는 8 바이트가 아닌 경우 배열의 index—displacement 구성 요소는 정적 오프셋을 배열의 시작 부분으로 인코딩한다. base 레지스터는 배열의 특정 요소에 대한 오프셋을 결정하기 위해 계산 결과를 유지한다.
    - 레코드의 필드에 접근하는 것: base 레지스터는 레코드 시작의 주소를 보유하고, displacement는 필드에 대한 정적 오프셋이다.
    특별히 이 조합이 중요한 경우는 프로시저 활성화 레코드의 매개 변수에 대한 접근이다. 프로시저 활성화 레코드는 프로시저가 입력 될 때 생성되는 스택 프레임이다. 여기서, EBP 레지스터는 스택 세그먼트를 자동으로 선택하기에 base 레지스터에 가장 적합한 옵션이다. 이는 이러한 공통 기능을 위한 간결한 인코딩이다.
  • (Index ∗ Scale) + Displacement -  이 주소 모드는 요소 크기가 2, 4 또는 8 바이트일 때 정적 배열에 효율적으로 index할 수 있는 방법을 제공한다. displacement는 배열의 시작 부분을 찾고, 인덱스 레지스터는 원하는 배열 요소의 첨자를 유지하고, 프로세서는 scaling factor를 적용하여 첨자(subscript)를 idnex로 자동 변환한다.
  • Base + Index + Displacement - 두 개의 레지스터를 함께 사하는 것은 2 차원 배열 (displacement가 배열의 시작 주소를 유지함)이나 레코드 배열의 여러 인스턴스 중 하나(displacement는 내부 필드의 오프셋)를 지원한다.
  • Base + (Index ∗ Scale) + Displacement - 모든 주소 배정 구성 요소를 함께 사용하면 배열의 요소가 2, 4 또는 8 바이트 크기일 때 2차원 배열을 효율적으로 인덱싱하도록 허용한다.

3.7.5.1. 64-비트 모드에서 오프셋 지정(Specifying an Offset in 64-Bit Mode)

64 비트 모드에서 메모리 주소의 오프셋 부분은 다음 구성 요소 중 하나 이상으로 직접적으로 정적 값이나 주소 계산을 통해 구성되어 지정 될 수 있다.

  • Displacement - 8-비트, 16-비트 또는 32-비트 값
  • Base - 64-bit 범용 레지스터의 값
  • Index - 64-bit 범용 레지스터의 값
  • Scale factor - 인젝스 값을 곱한 2, 4 또는 8의 값

대부분의 경우 16개의 사용 가능한 범용 레지스터 중 하나에서 인덱스 값을 지정할 수 있다. 자세한 정보는 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 2A의 2장 "Instruction Format"을 참고한다.

다음과 같은 고유한 주소 구성 요소 조합도 사용할 수 있다.

  • RIP + Displacement - 64-비트 모드에서 RIP-상대 주소 배정은 부호있는 32 비트 displacement를 사용하여 32-비트 값을 부호 확장하고 RIP에서 64-비트 값을 더하여 다음 명령의 실효 주소를 계산한다.

3.7.6. 어셈블러와 컴파일러 주소 배정 모드(Assembler and Compiler Addressing Modes)

기계 코드 레벨에서 displacement, base 레지스터, 인덱스 레지스터, scale factor의 선택된 조합이 명령어로 인코딩된다. 모든 어셈블러는 프로그래머가 이러한 주소 배정 구성 요소의 허용 가능한 조합을 허용하여 피연산자를 처리할 수 있다. 고급 언어 컴파일러는 프로그래머가 정의한 언어 구성에 따라 이러한 구성 요소의 적절한 조합을 선택한다.

3.7.7. I/O 포트 주소 배정(I/O Port Addressing)

프로세서는 최대 65,536개의 8-비트 I/O 포트를 포함하는 I/O 주소 공간을 지원한다. 16-비트와 32-비트 포트는 I/O 주소 공간에 정의될 수 있다. I/O 포트는 즉시 피연산자나 DX 레지스터의 값으로 주소가 배정될 수 있다. I/O 포트 주소 배정에 대한 자세한 내용은 18장 "Input/Output"을 참조한다.


1. 개요

공격자는 생각하지도 못한 방법으로 연산을 수행하여 결과를 도출한다. 한 기술을 정리하는 과정에 ![] 연산의 불린값이 생성되는 과정에 의문을 품게 되었다. 브라우저 개발자 도구를 통해 몇가지 테스트해보았다.

[ ] 불린 테스트

그러면 흔히 반대를 의미하는 ! 기호를 쓰면 결과가 달라진다. 예를 들면 true인 경우 false를 출력하고, false 인 경우 true를 출력한다. 이러한 연산을 자바스크립트 내부에서는 == false 를 연산한다. 그러면 ![]true가 출력되어야 한다. 하지만 실제 테스트하면 어떠할까?

그림 2. ![ ] 불린 테스트

결과는 의외의 결과로 false가 출력된다. 왜 그럴까?

2. 동등 연산자와 일치 연산자

동등 연산자는 느슨한 비교 연산자(Loose Equality Operators) 또는 더블 이퀄 연산자(Double Equals Operator)로 불리며 사용하는 방법은 == 연산자를 사용한다. 자바스크립트에서 동등 연산자는 자동 형변환을 제공한다. 다음 그림을 보면 동등 연산자가 자동 형변환을 사용하는 것을 알 수 있다.

그림 3. 동등 연산자를 통해 자동 형변환 테스트

이러한 이유로 "자동 형변환에 의해 []의 형태가 변환되고, 이로 인해 ![]false가 출력되지 않을까?" 가정을 세워보았다. 하지만 자동 형 변환되는 0""false 값을 가지기에 !0!""true을 출력한다.

그림 4. 0과 ""의 반대 불린 연산 수행 결과

[] 오브젝트에는 다른 형변환이 있지 않을까? 다음 그림을 보면 다른 형변환 요소는 존재하지 않는 것을 볼 수 있다.

그림 5. 동등 연산 테이블

실험에 의미는 없지만, 동등 연산자와 다른 개념이 일치 연산자이다. 일치 연산자는 엄격한 비교 연산(Strict Equality Operators) 또는 트리플 이퀄 연산자(Triple Equals Operator)로 불리며, 동등 연산자와 달리 자동 형변환 기능을 사용하지 않고 비교 연산을 수행한다.

그림 6. 일치 연산 테스트

일치 연산 테이블은 다음과 같다.

그림 7. 일치 연산 테이블

3. 조건 연산을 통한 데이터 성질 이해

본론으로 돌아와서 왜 ![]false를 출력하는지 그 이유를 찾아야 한다. 그 이유를 조건문 사용에서 찾을 수 있었다. []false이기 때문에 if([ ]){ source code }; 형태로 사용하게 되면 분명 source code 부분은 동작하지 않아야한다. 하지만 실제 사용해보면 어떻게 될까?

그림 8. [ ]을 조건 구문에 사용한 테스트

조건 구문이 실행되는 것을 볼 수 있다. 그렇다면 조건문에서는 []true로 동작하는 것이 증명된 것이다. 이 또한 다음과 같은 테이블로 표현할 수 있다.

그림 9. 조건 구문을 통한 자료의 성질 테이블

이러한 이유로 ![]false로 출력된다.

4. 결론

왜 그렇게 동작하는지는 찾았지만, 왜 그렇게 만들어졌는지는 잘 모르겠다. 아마도 자바스크립트를 설계하고 개발한 사람만 알고 있지 않을까? 처음 ![]false로 출력되는 물음을 해결하는게 상당히 어려웠지만, 이정도 결론으로 만족한다. 향후에 ECMA-262 6th 문서를 한번 뒤져봐야겠다.

5. 참조 사이트


  1. 사랑은 2016.01.27 19:35

    도움 얻어 갑니다..!

  2. BlogIcon . 2017.07.13 13:55

    배워갑니다

MIT 공대에서 컴퓨터 공학과 프로그래밍 소개에 관한 강의가 유튜브에 올라왔다. 최근에 업로드된 강의가 있음에도 이 강의들을 정리한 이유는 아무래도 한글 자막이 잘 되어 있기 때문이다.

출처 : MIT OpenCourseWare YouTube

교수 : Eric Grimson, John Guttag

제 01강 - 연산이란 - 데이터 타입, 연산자 및 변수 소개

제 02강 - 연산자와 피연산자 - 분기문, 조건문 그리고 반복문

제 03강 - 공통 코드 패턴, 반복 프로그램

제 04강 - 기능을 통한 분해 및 추상화, 재귀 소개

제 05강 - 부동 소수점, 계통적 명세화, 루트 찾기

제 06강 - 이분법, 뉴턴/랩슨, 그리고 리스트 소개

제 07강 - 리스트와 가변성, 딕셔너리, 의사코드, 그리고 효율성 소개

제 08강 - 복잡성 - 로그, 선형, 이차 방정식, 지수 연산 알고리즘

제 09강 - 이진 탐색, 버블 그리고 분류 선택

제 10강 - 분할 정복 방법, 합병 정렬, 예외

제 11강 - 테스트와 디버깅

제 12강 - 디버깅 추가 강의, 배낭 문제, 동적 프로그래밍 소개

제 13강 - 동적 프로그래밍 - Overlapping subproblems, Optimal substructure

제 14강 - 배낭 문제 분석, 객체 지향 프로그래밍 소개

제 15강 - 추상 데이터 타입, 클래스와 메소드

제 16강 - 캡슐화, 상속, 쉐도잉

제 17강 - 연산 모델 - 랜덤워크 시뮬레이션

제 18강 - 시물레이션 결과 제시, Pylab, Plotting

제 19강 - 편향된 랜덤워크, 배포

제 20강 - 몬테카를로(Monte Carlo) 시뮬레이션, 추정 파이

제 21강 - 시뮬레이션 결과 검증, 곡선 적합, 선형 회귀

제 22강 - 일반, 균등 그리고 지수 분포 - 통계의 오류

제 23강 - 주식 시장 시뮬레이션

제 24강 - 과정 개요 - 컴퓨터 과학자들은 무엇을 하나요?

  1. cabin 2016.04.19 15:02

    한글 자막이 않나오는데요?

    • 박문용 2016.04.19 16:20

      유튜브영상 우측 하단의 설정>자막에서 한국어 선택하세요

    • TongGoon 2016.04.19 18:36

      유튜브 영상 우측 하단에 톱니바퀴(설정) 버튼 클릭 후 자막을 클릭하면 한국어로 변경해서 볼 수 있습니다.

  2. gkdn 2016.04.20 01:11

    13강 부터는 한글 자막이 없는 것 같네요

  3. Favicon of http://moneycoach.kr/ BlogIcon 소액결제 현금화 2017.12.06 07:38

    잘보고 갑니다 ~~~

  4. 과객 2018.12.06 20:30

    한글 자막 만들어 주셔서 감사합니다만 그냥 번역기 돌린 수준이예요.
    그냥 끄고 듣는게 집중도 잘 되고 낫네요.
    다른 분들은 이 점 참고하세요.

    • Favicon of https://www.hakawati.co.kr BlogIcon hakawati 2018.12.14 14:01 신고

      제가 만든게 아닙니다~ 만들어져 있던거 공유했을 뿐입니다~

  5. 김태순 2020.06.28 19:26

    좋은 글 올려주신 덕분에 보기 시작했습니다.
    파이썬 교재로 따라하기만 하다보니 어떻게 사고해야 할지 막막했는데 강의 보니까 도움이 많이 되네요.
    감사합니다.

1. 개요

JavaScript Garden은 자바스크립트 언어의 핵심적인 내용을 모아 놓은 웹 문서이다. 이 문서는 자바스크립트 언어 자체를 설명하지 않고, 이 언어를 익히고, 사용하는데 있어 자주 겪는 실수, 미묘한 버그, 성능 이슈, 나쁜 습관 등 자바스크립트 언어의 독특한 특징들을 설명하고 있다.

2. 난독화 관련 내용

JavaScript Garden 내용을 기반으로 자바스크립트 난독화에서 이해하기 어려웠던 언어의 특징들을 잘 설명하고 있어 공부하는데 많은 도움이 되었다.

2.1. 객체 > 객체와 프로퍼티 > 프로퍼티 접근

객체이름 다음에 점을 찍어(Dot Notation) 접근하거나 각괄호를 이용해(Square Bracket Notation, []) 접근할 수 있다. 두 방식 모두 거의 동일하게 동작한다. 다만 차이가 있다면 각괄호 방식은 프로퍼티 이름을 동적으로 할당해서 값에 접근 할수 있지만 점을 이용한 방식은 구문 오류를 발생시킨다.

var foo = {name: 'kitten'}
foo.name; // kitten
foo['name']; // kitten

var get = 'name';
foo[get]; // kitten

foo.1234; // SyntaxError
foo['1234']; // works

document.write()함수는 document["write"] 가 가능하고 다시 window["document"]["write"] 가 가능하다. 각괄호 안의 값은 문자열이기 때문에 인코딩 형태로 변형할 수 있다.

그림 1. 16진수 난독화

2.2. 함수 > 함수 선언과 함수 표현식 > 표현식

자바스크립트에서 함수는 First Class Object다. 즉, 함수 자체가 또 다른 함수의 인자가 될 수 있다는 말이다.

var foo = function() {}

그래서 기존에 정의된 함수를 다른 변수로 대체 가능하다. 예를 들면 난독화에서 함수명을 쉽게 읽히지 않도록 하기위해 djEfUz = eval 형태로 변경 가능하다. 다음 소스코드는 공다팩의 일부이다.

그림 2. 공다팩 소스코드 중

2.3. 함수 > 스코프와 네임스페이스

자바스크립트는 '{ }' Block이 배배 꼬여 있어도 문법적으로는 잘 처리하지만, Block Scope은 지원하지 않는다. 그래서 JavaScript에서는 항상 함수 스코프를 사용한다. 난독화에서는 이러한 특징을 이용하여 자바스크립트 압축을 구현할 수 있다.

자바스크립트 컴프레셔는 자바스크립트 압축기술로 YUI Compressor 같은 도구들이 존재한다. 압축기를 사용하는 이유는 다운로드 받는 자바스크립트 파일의 용량을 줄이면, 사용자 입장에서는 빠르게 받고 실행할 수 있어 브라우징 속도가 빨라지고, 서버 입장에서는 트래픽 소비량을 줄여 비용을 절감할 수 있다.

var is = {
    ie:      navigator.appName == 'Microsoft Internet Explorer',
    java:    navigator.javaEnabled(),
    ns:      navigator.appName == 'Netscape',
    ua:      navigator.userAgent.toLowerCase(),
    version: parseFloat(navigator.appVersion.substr(21)) ||
             parseFloat(navigator.appVersion),
    win:     navigator.platform == 'Win32'
}
is.mac = is.ua.indexOf('mac') >= 0;
if (is.ua.indexOf('opera') >= 0) {
    is.ie = is.ns = false;
    is.opera = true;
}
if (is.ua.indexOf('gecko') >= 0) {
    is.ie = is.ns = false;
    is.gecko = true;
}

이 코드를 압축시키면 대부분 이런형태로 생성된다.

var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloatnavigator.appVersion),win:navigator.platform=='Win32'}is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}

2.4. 타입 > 객체 비교하기 > 타입 캐스팅

자바스크립트는 Weak Typing 언어이기 때문에 필요할 때마다 알아서 타입을 변환한다.

Strong / Weak Typing 은 타입에 제약이 많을 수록 Strong, 적어질 수록 Weak에 가까워진다. 예를 들면 var a = 3 으로 했을 때 정수형으로 자동 형 변환을 해주는 형태가 Weak Type, 정확하게 int a = 3 으로 선언해야 정수형으로 저장되는 경우가 Strong Type 으로 이해하면 된다. 자바스크립트는 Weak Typing을 따르기 때문에 자동 형 변환을 해주며, 이런 변환을 타입 캐스팅이라 부른다.

그래서 [] == 0 비교를 하면 true로 출력되는데, 이 때 [] 객체가 0과 비교에서 숫자 타입으로 타입 캐스팅된다. 이중 등호 연산자(==)는 두 객체의 자료형을 강제로 변환하기 때문에 비교가 가능하고, []이 변환되었을 경우 0을 가지기 때문에 true가 출력된다.

이와 같은 맥락으로 ~ 연산이나 + 연산 같이 숫자를 대상으로 연산이 포함될 경우 타입 캐스팅에 의해 강제 형 변환되어 연산이 진행되며 jjencode에서 사용된 ~[]-1이라는 값을 가지게 되는 이유이다.

그림 3. jjencode

그림 4. [ ] 오브젝트와 타입 캐스팅 테스트

2.5. 핵심 > 왜 eval을 사용하면 안 될까?

eval() 함수는 자바스크립트 문자열을 지역 스코프에서 실행한다.

var number = 1;
function test() {
    var number = 2;
    eval('number = 3');
    return number;
}
test(); // 3
number; // 1

eval() 함수는 eval() 이라는 이름으로 직접 실행할 때만 지역 스포크에서 실행된다.

var number = 1;
function test() {
    var number = 2;
    var copyOfEval = eval;
    copyOfEval('number = 3');
    return number;
}
test(); // 2
number; // 3

어쨌든 eval()은 사용하지 말아야 한다. eval()을 사용하는 99.9%는 사실 eval() 없이도 만들수있다. eval()은 어떤 코드라도 무조건 실행하기 때문에 보안 문제도 있다. 따라서 신뢰하지 못하거나 모르는 코드가 포함되어 있을 경우 절대로 사용해서는 안된다. 어쨋든 eval()은 사용하지 않는게 좋다. eval()을 사용하는 모든 코드는 성능, 보안,버그 문제를 일으킬 수 있다. 만약 eval()이 필요해지면 설계를 변경해서라도 eval()이 필요 없게 만들어야 한다.

전역과 지역 스코프에서 사용될 때 보안적 이슈와 차이점에 대해 자세한 설명이 없어 이해하기가 어렵다. 하지만 자바스크립트 난독화에서 흔히 사용하는 함수가 eval() 인것은 확실하고, eval() 함수를 사용했을 경우 안의 내용을 무조건적으로 실행하기 때문에 많은 문제를 가지고 있는 것은 확실하다.

2.6. 핵심 > undefined와 null > undefined도 변수

undefinedundefined라는 값을 가지는 데이터 형식이다. undefined는 상수도 아니고 자바스크립트의 키워드도 아니다. 그냥 undefined라는 이름의 Global 변수이고 이 변수에는 undefined라고 할당돼 있다. 그래서 이 Global 변수의 값을 쉽게 바꿀 수 있다.

같은 맥락으로 0/0으로 출력되는 NaN이나 123/0으로 출력되는 Infinity도 동일하다. 이렇게 출력되는 값을 다시 재활용 가능한데, 이러한 형태를 jjencode에서도 볼 수 있다.

그림 6. ECMAScript 6th 내용

타입 캐스팅에 의존하지 않고 정확한 형을 지정하기 위해 사용한 방법 중에 +"" 또는 ""+ 가 있다. (더블 쿼터 대신 싱글 쿼터를 써도 무방하다.) + 연산자 옆에 쓰여질 피연산자를 문자열로 자동 형 변환을 시켜준다. 이렇게 형 변환된 데이터를 ()로 감싼다. 괄호로 감싸는 이유는 연산자 우선순위를 두기 위해서이다.

그림 7. 선언된 글로벌 변수 변형

2.7. 보이지 않게 사용되는 eval 함수

setTimeout() 함수와 setInterval() 첫 파라미터는 실행가능한 문자열을 넘길 수 있다. 하지만 이 실행은 내부적으로 eval()을 사용하는 것이기 때문에 두 함수를 사용하지 않는 것이 좋다.

그림 8. setTimeout의 첫 파라미터 테스트

3. 참조 사이트

1. 개요

지난 포스트에서 ftp를 설치했기 때문에 자동으로 설정되어 테마와 플러그인 설치를 쉽게 할 수 있다. 만약 다른 방법으로 설치했다면 wp-config.php 파일에 다음 내용을 추가한다.

define('FTP_USER', '[ftp계정]');
define('FTP_PASS', '[ftp 비밀번호]');
define('FTP_HOST', '[ftp 서버 ip:포트번호]');
define('FTP_SSL', false);
define('FTP_BASE', '/www/var/wordpress/');
define('FTP_CONTENT_DIR', '/www/var/wordpress/wp-content/');
define('FTP_PLUGIN_DIR ', '/www/var/wordpress/wp-content/plugins/');

이제 워드프레스 관리 페이지에서 외모 > 테마 > 선택 > 활성화를 클릭하여 테마를 활성화 할 수 있다. 테마가 설치 되었을 땐 웹 서비스로 접근하면 아름다운 테마를 확인 가능하다.

그림 1. 워드프레스 테마 설치

똑같은 방식으로 플러그인 > 플러그인 추가 > 지금 설치하기 를 통해 플러그인을 추가하고 설치 가능하다. 특히 플러그인 설치가 완료되면 다음 그림과 같이 "성공적으로 설치했습니다." 로그를 확인할 수 있다. 만약 해당 메시지를 볼 수 없거나 실패 메시지를 보게 된다면 ftp 관련 문제이다.

그림 2. 플러그인 설치

설치 직후 바로 활성화 하지 않았다면 플러그인 > 설치된 플러그인으로 들어가서 각각의 플러그인을 활성화 할 수 있고, 기존에 설치된 플러그인이 업데이트를 요구할 경우 여기서 업데이트를 간편하게 진행 가능하다.

그림 3. 플러그인 활성화/비활성화

1.1. 다른 방법으로 플러그인 설치

1.1.1. 서버 플러그인 디렉터리에 직접 설치

다른 방법으로 플러그인 설치는 웹 서버에서 직접적으로 설치하는 방법이다. 플러그인이 설치되는 주소인 /var/www/wordpress/wp-content/plugin/ 에 플러그인을 직접 다운로드하여 저장한다. 저장 이후 설정은 위에서 설명한 내용과 동일하다. 이렇게 설치하는 것의 단점은, 플러그인의 퍼미션과 소유권을 재설정 해야 하는 경우가 필요 할 수 있다.

1.1.2. 관리자 패널에서 플러그인 설치하기

플러그인 설치는 관리자 패널에서 플러그인을 설치할 수 있다. 다음과 같이 플러그인에서 플러그인 추가하기 버튼을 누르고, 플러그인 업로드를 클릭한다.

그림 4. 플러그인 업로드 버튼 클릭

그러면 파일 업로드 창을 볼 수 있는데, 여기에 압축 형태가 zip 인 파일을 업로드 한다. 대부분 플러그인을 다운로드하면, zip 파일로 다운로드 받기에 무리없이 업로드 가능하다.

그림 5. 플러그인 추가 및 설치 완료

+ Recent posts