[Pre_시스템]

8086 Memory Architecture

8086 Memory Architecture

시스템이 시작되면 커널(Kernal)이 가용 메모리에 적재된다.

시스템은 운영에 필요한 기본적인 명령어 집합을 커널에서 찾기 때문에 사진과 같은 위치에 적재시켜야 한다.

 

 

프로세스 실행

segment 구조

운영체제는 하나의 프로세스를 처리할 때 segment단위로 묶어서 처리한다.

segment는 code segment, data segment, stack segment로 이루어져 있고 가용 메모리 영역에 저장된다.

 

 

code segment

code segment

code segment에는 시스템이 인지할 수 있는 명령어 instruction이 들이 있다. 컴퓨터가 instrcution을 실행하려면 메모리 상의 특정 위치에 있는 명령을 지정해야 한다. 그러나 segment는 자신이 현재 메모리 상에 어느 위치에 저장되는 지 알 수 없기 때문에 physical address대신 logical address를 사용한다.

 

segment는 segment selector에 의해서 자신의 시작 주소(offset)를 알 수 있다. 자신의 시작 주소로부터의 위치가 바로 logical address이고 이 위치에 있는 명령의 수행 여부를 결정한다. 따라서 실제 physical address는 offset+logical address이다.

 

 

data segment

data segment에는 프로그램이 실행시에 사용되는 데이터가 저장돼 있다. 저장된 데이터는 전역 변수로 프로그램 내에서 전역 변수를 선언하면 data segment에 저장된다.

 

data segment는 현재 모듈의 data segment, 상위 레벨로부터 받아들이는 데이터 모듈, 동적 생성 데이터, 다른 프로그램과 공유하는 데이터 부분으로 다시 네 개의 data segment로 나뉜다.

 

 

stack segment

stack segment는 현재 수행되고 있는 handler, task, program이 저장하는 데이터 영역이다.

보통 버퍼와 지역 변수가 이 stack segment에 자리잡는다.

 

스택은 처음 생성될 때 필요한 크기만큼 공간이 생성된다.stack pointer(SP)라고 하는 레지스터가 스택의 맨 꼭대기를 가리키고 있다.스택에 데이터를 저장하고 읽어오는 과정은 PUSH와 POP instruction에 의해서 수행된다.

 

PUSH할 때는 스택의 맨 위에 저장하고, POP할 때는 스택의 맨 위에서 데이터를 읽어 온다.

 

 

8086 CPU 레지스터 구조

CPU는 프로세스를 재빨리 처리해야 하므로 데이터를 처리할 때 CPU 내부에 있는 메모리를 활용한다.

이때 사용하는 공간을 레지스터(register)라고 한다.

 

일반적인 시스템의 레지스터 구조는 다음과 같다.

CPU 레지스터 구조

레지스터는 목적에 따라서 범용 레지스터(General-Purpose register), 세그먼트 레지스터(segment register), 플래그 레지스터(Program status and control register), 그리고 인스트럭션 포인터(instruction pointer)로 구성된다.

 

 

범용 레지스터(General-Purpose register)

범용 레지스터

범용 레지스터는 프로그래머가 임의로 조작할 수 있게 허용된 레지스터로 논리 연산, 수리 연산에 사용되는 피연산자, 주소를 계산하는데 사용되는 피연산자, 그리고 메모리 포인터가 저장되는 레지스터다.

 

16bit에서 32bit로 넘어오면서 레지스터 앞에 E(Extended)를 붙여 부르게 됐다.

AX 레지스터의 상위 부분을 AH, 하위 부분을 AL이라고 한다.

 

각 레지스터는 프로그래머의 필요에 따라 자유롭게 사용해도 되지만, 레지스터마자 자신의 목적을 가지고 있고 컴파일러도 이러한 목적에 맞게 사용하고 있기 때문에 그 목적대로 사용해주는 것이 좋다.

 

<각 레지스터의 목적>

EAX 피연산자와 연산 결과의 저장소
EBX DS segment안의 데이터를 가리키는 포인터
ECX 문자열 처리나 루프를 위한 카운터
EDX I/O 포인터
ESI DS 레지스터가 가리키는 data segment 내의 어느 데이터를 가리키고 있는 포인터.
문자열 처리에서 source를 가리킴.
EDI ES 레지스터가 가리키고 있는 data segment 내의 어느 데이터를 가리키고 있는 포인터.
문자열 처리에서 destination을 가리킴.
ESP SS 레지스터가 가리키는 stack segment의 맨 꼭대기를 가리키는 포인터
EBP SS 레지스터가 가리키는 스택 상의 한 데이터를 가리키는 포인터

 

 

세그먼트 레지스터(segment register)

세그먼트 레지스터

code segment, data segment, stack segment를 가리키는 주소가 들어 있는 레지스터다.

세그먼트 레지스터는 위 그림과 같이 프로세스의 특정 세그먼트를 가리키는 포인터 역할을 한다.

 

CS 레지스터 code segment
DS 레지스터 data segment
ES 레지스터
FS 레지스터
GS 레지스터
SS 레지스터 stack segment

 

다음 사진은 각 레지스터가 가리키는 세그먼트들을 설명해 주고 있다.

레지스터 - 세그먼트

 

 

플래그 레지스터(Program status and control register)

플래그 레지스터의 구성

프로그램의 현재 상태나 조건 등을 검사하는데 사용되는 플래그들이 있는 레지스터다.

상태 플래그, 컨트롤 플래그, 시스템 플래그의 집합이며 시스템이 리셋되어 초기화 되면 레지스터는 0x00000002의 값을 가진다. 그리고 1, 3, 5, 15, 22~31번 비트는 예약되어 있어 소프트웨어에 의해 조작할 수 없다.

 

각 플래그들의 역할은 다음과 같다.

 

<Status flags>

CF carry flag: 연산을 수행하면서 carry 혹은 borrow가 발생하면 1이 된다.
Carry와 borrow는 덧셈 연산시 bit bound를 넘어가거나 뺄셈을 하는데 빌려오는 경우를 말한다.
PF parity flag: 연산 결과 최하위 바이트의 값이 1이 짝수일 경우 1이 된다.
패리티 체크를 하는데 사용된다.
AF adjust falg: 연산 결과 carry나 borrow가 3bit 이상 발생할 경우 1이 된다.
ZF zero flag: 결과가 zero임을 가리킨다. if문 같은 조건문이 만족될 경우 set된다.
SF sign flag: 이것은 연산 결과 최상위 비트의 값과 같다. signed 변수의 경우 양수이면 0, 음수이면 1이 된다.
OF overflow flag: 정수형 결과값이 너무 큰 양수이거나 너무 작은 음수여서 피연산자의 데이터 타입에 모두 들어가지 않을 경우 1이 된다.
DF direction flag: 문자열 처리에 있어서 1일 경우 문자열 처리 instruction이 자동으로 감소(문자열 처리가 high address에서 low address로 이루어진다), 0일 경우 자동으로 증가 한다.

 

 

<System flags>

IF Interrupt enable flag: 프로세서에게 mask한 interrupt에 응답할 수 있게 하려면 1을 준다.
TF Trap flag: 디버깅을 할 때 single-step을 가능하게 하려면 1을 준다.
IOPL I/O privilege level field: 현재 수행 중인 프로세스 혹은 task의 권한 레벨을 가리킨다.
현재 수행 중인 프로세스의 권한을 가리키는 CPL이 I/O address 영역에 접근하기 위해서는 I/O privilege level보다 작거나 같아야 한다.
NT Nested task flag: Interrupt의 chain을 제어한다.
1이 되면 이전 실행 task와 현재 task가 열결되어 있음을 나타낸다.
RF Resume flag: Exception debug 하기 위해 프로세서의 응답을 제어한다.
VM Virtual-8086 mode flag: Virtual-8086 모드를 사용하려면 1을 준다.
AC Alignment check flag: 이 비트와 CR0 레지스터의 AM 비트가 set되어 있으면 메모리 레퍼런스의 alignment checking이 가능하다.
VIF Virtual interrupt flag: IF flag의 가상 이미지이다. 
VIP flag와 결합시켜 사용한다.
VIP Virtual interrupt pending flag: 인터럽트가 pending(경쟁 상태) 되었음을 가리킨다.
ID Identification flag: CPUID instruction을 지원하는 CPU인지를 나타낸다.

 

 

인스트럭션 포인터(instruction pointer)

Instruction pointer 레지스터는 다음 수행해야 하는 명령(instruction)이 있는 현재 code segment의 offset 값을 가진다. 또한 JMP, Jcc, CALL, RET와 IRET instruction이 있는 주소값을 가진다.

 

EIP 레지스터는 소프트웨어에 의해 바로 엑세스 할 수 없고 control-transfer instruction(JMP, Jcc, CALL, RET)이나 interrupt와 exception에 의해서 제어된다.

EIP 레지스터를 읽으려면 CALL instruction을 수행하고 나서 프로시저 스택(procedure stack)으로부터 리턴하는 instruction의 address를 읽는 것이다.

프로시저 스택의 return instruction pointer의 값을 수정하고 return instruction(RET, IRET)을 수행함으로 해서 EIP 레지스터의 값을 간접적으로 지정해 줄 수 있다.

 

 

 

***달고나 와우해커 BOF 기초문서 참고

복사했습니다!