개요
2장 : x86 프로세서를 사용한 컴퓨터 시스템 구조를 프로그래머 관점에서 알아보겠다.
✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯
내 생각에는 어셈블리 언어를 공부하면서 가장 중요한 절이다 x86의 동작모드, 레지스터, 부동 소수점 장치의 개념을 기술한다.
✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯ ✯
x86 프로세서의 기본적인 구조
CPU는 레지스터, 고주파수 클럭, 제어장치, 산술논리연산장치를 포함한다. 이는 가상 마이크로컴퓨터의 기본적인 설계이다.
기계어 명령어 실행 사이클은 인출(fetch), 해독(decode), 실행(execute)이라고 할 수 있다.
이 페치, 디코드, 익세큐트는 절대 법칙이라고 봐도 될 정도로 모든 설계의 기초이다.
모든(all)경우라고 하는 것은 굉장히 위험한 발언이지만 모든 컴퓨터는 이러한 명령어 실행 사이클을 따른다.
x86 프로세서 구조에 필요한 기본 개념
CPU
: 중앙 처리 장치(Central Processor클럭
: 다른 시스템 구성요소를 CPU의 내부와 동기시킨다. 딱!딱!딱!~~~ 클럭 단위로 cpu는 일을 처리한다.제어 장치
: CU(Control Unit)이라고 하며 명령어를 실행하는 순서를 조정한다.산술 논리 장치
: ALU(arithmetic logic unit)이라고 하며 덧셈이라는 산술연산을 진행한다. 겉으로 보기에는 뺄셈등의 나머지 산술연산과 and와 같은 논리연산도 진행하는 것처럼 보이지만 실제로는 덧셈으로 모두 처리하는 것이다.버스
: 데이터를 다른 부분으로 전송하는 병렬 와이어 그룹이다.인출
: fetch라고 하며 CU는 명령어 큐에서 다음 명령어를 가져오고 명령어 포인터(IP)를 증가시킨다.해독
: decode라고 하며 CU는 명령어의 기능을 해독하여 명령어의 입력 피연산자와 수행될 연산을 ALU보낸다.실행
: execute라고 하며 ALU는 명령어를 처리하고 그에 대한 결과를 메모리로 보낸다.
메모리 읽기
프로그램 처리량은 메모리 접근 속도에 매우 큰 관련이 있으며 메모리 접근은 시스템 버스를 통해서 이루어진다.
Cycle 1
: 메모리의 피연산자의 주소비트가 주소 버스에 놓인다. (돈까스(메모리의 피연산자) 주세요 하자 주방에서 돈까스를 홀에 줬다)Cycle 2
: 메모리야! 나 이제 값 읽는다~! 읽기신호(rd) -> 0 (셀프 식당이라 사장님! 이거 돈까스 가져갈께요!라고 한다.)Cycle 3
: 메모리의 대답을 듣기 위해 CPU는 대기/ 피연산자를 데이터 버스에 놓는다.(돈까스를 식판에 놓고 사장님의 OK사인을 기다린다.)Cycle 4
: 메모리야! 나 값 읽었다~! 읽기신호(rd) -> 1 (돈까스를 자리에 가져와서 사장님! 돈까스 맛있네요!라고 한다.)
x86 프로세서의 동작 모드
보호 모드
: 32비트이며 모든 명령어와 특징을 사용할수 있는 상태이다.실제 주소 모드
: 인텔 8086 프로세서의 프로그래밍 환경을 구현한다. windows98에서 사용할 수 있으며 ms-dos프로그램을 실행하는데 사용된다.
✯✯✯✯✯레지스터
별이 다섯개! 그만큼 중요하다.
레지스터는 CPU 안에 있는 고속 저장 장소이며 일반 메모리보다 훨씬 빠른 속도로 접근할 수 있다.
범용 레지스터는 영어단어 General Purpose Register에서 알 수 있듯이 다목적으로 사용할 수 있다.
위의 사진은 중요한 범용 레지스터들의 종류를 간단하게 나타낸 것이고, 밑의 사진은 운영체제의 비트에 따라서 범용 레지스터를 간단하게 나타낸 것이다.
예시를 EAX로 들었지만 모든 범용 레지스터는 사진의 규칙에 따른다.
각 레지스터에 대한 간략한 소개
EAX
: (E)arithmetic register/ ALU 그 자체라고 보면 된다.EBX
: (E)base register/ 산악 캠프의 베이스캠프 개념과 비슷하다. 연산 도중에 메모리 주소를 저장한다.ECX
: (E)count register/ 반복문에서 사용되는 카운터이다.EDX
: (E)data register/ EAX 다음에 위치해 있으며 EAX의 확장성을 부여한다./ 데이터를 다른 객체로 옮길 때 거쳐서 간다.EBP
: (E)base pointer/ 스택 프레임에서 사용되는 개념이다. 베이스캠프 개념과 비슷하다.ESP
: (E)stack pointer/ 스택 프레임에서 사용되는 개념이다. 스택프레임의 현재 인덱스를 담고있다.ESI
: (E)source index/ 데이터 조작시의 해당 데이터의 시작주소 / 고속 메모리 전송 명령어에서 사용EDI
: (E)destination index/ 데이터 조작시의 해당 데이터의 종료주소 / 고속 메모리 전송 명령어에서 사용EFLAGS
: (E)FLAGS register/ CPU의 동작을 제어하는 제어 플래그와 산술 논리 연산의 결과를 반영하는 상태 플래그로 나뉜다.EIP
: (E)instuction pointer/ 다음에 실행할 명령어의 주소를 가지고 있다. program counter라고도 한다.CS
: code segment/ main문 안의 내용을 처리하는 곳DS
: data segment/ main문 밖의 내용을 처리하는 곳SS
: stack segment/ 함수 혹은 지역 변수같은 데이터를 처리하는 곳ES
: extra segment라고하며 32비트에서는 힙과 비슷한 역할이다. 힙이라고 보면 된다.
위의 소개에서 4개의 16비트 세그먼트 레지스터에 대해서는 부가 설명이 필요해보인다.
실제 주소 모드에서 x86 프로세서는 20비트 주소를 사용하여 1MB의 메모리에 접근한다.
그러나 16비트 레지스터가 20비트 주소를 저장할수는 없다. 따라서 세그먼트 메모리라는 방식을 이용한다.
아래 그림에서 왼쪽에 그림을 하나의 건물이라고 생각해보자.
세그먼트는 몇층인지를 의미하며, 오프셋는 엘레베이터를 타고 세그먼트 층에 도착한 후 생각하고 있는 방까지의 거리이다.
CPU는 세그먼트-오프셋 주소에서 세그먼트 값에 16을 곱하고 오프셋을 더하여 20비트 선형 주소로 자동변환한다.
코드 영역은 main문 안의 내용을 다룬다. 프로그램의 기계어 명령어가 들어있으며 IP가 가리키고 있는 부분입니다. READ_ONLY 영역으로 프로그램이 종료될 때까지 유지된다.
데이터 영역은 main문 밖의 내용을 다룬다. data + bss의 영역을 의미하지만 data 영역이라고 불린다.
전역 변수, 정적 변수만 들어간다고 알고있었지만 구조체, 배열도 있다고 하는데 공부를 더 해야할것같다.
data는 초기화된 데이터들이 들어오고 bss는 초기화되지 않은 데이터들이 들어온다.
스택 영역은 함수의 파라메터, 지역변수를 다룬다. 후입선출 구조를 가지고 있으며 함수를 실행하면 프로그램이 자동으로 사용하였다가 사라지는 영역이다.
사용 가능한 스택의 최대 크기는 컴퓨터의 남은 램의 용량을 사용할 수 있다. 운영체제마다 다르긴 하지만 스택의 크기를 정해놓는다.
Windows 환경에서는 1MB이다. 메모리를 많이 잡아먹을 것 같으면 힙 메모리에 설정하는 것이 일반적이기 때문에 그럴일은 잘 없지만 1MB를 넘어간다면 Windows에서 자동으로 스택의 사이즈를 늘려준다.
Linux 환경에서는 8MB이다. 이 크기를 넘어갈 경우 Segmentation Fault에러가 발생한다.
스택은 상위 주소부터 내려오는 형식으로 설계되어있다.
이후 8장에서 스택에 관하여 자세하게 다루도록 하겠다.
힙 영역은 사용자가 할당하여 사용할 수 있는 공간이다. 이 공간을 사용할 때는 메모리 해제를 꼭 진행해야한다. 그렇지 않으면 Memory Leaks 에러가 발생할 것이다.
고수준의 언어를 배울 때 동적할당을 하는 방법을 배울 것이다. 동적할당을 하면 이 위치에서 데이터들이 처리되는 것이다.
선입선출의 구조를 가지며 큰 데이터 혹은 데이터의 크기가 유동적으로 바뀌는 경우 동적할당을 해준다.
스택 영역과 힙 영역의 경계는 유동적이다. 스택의 크기가 증가하면 힙이 사용가능한 크기가 줄어든다. 반대의 경우도 같다.
부동 소수점 장치
부동 소수점 장치는 고속 부동소수점 산술 연산을 수행한다. 이후에 12장에서 자세히 살펴보도록하겠다. 지금은 이런게 있구나 정도만 알고있어도 된다.
페이징(스왑)
세그먼트 페이지라고 하는 4096 바이트의 메모리 블록으로 나누는 작업
페이징을 사용하면 사용가능한 메모리가 물리적인 메모리 용량을 넘어설 수 있다.
자세한건 운영체제의 포스팅에서 다루도록 하겠다.