다음을 통해 공유


x86 아키텍처

Intel x86 프로세서는 복잡한 CISC(명령 집합 컴퓨터) 아키텍처를 사용합니다. 즉, 다량의 범용 레지스터 대신 적은 수의 특수 용도 레지스터가 있습니다. 또한 복잡한 특수 목적 지침이 우세하다는 것을 의미합니다.

x86 프로세서는 적어도 8비트 Intel 8080 프로세서까지 그 유산을 추적합니다. x86 명령 집합의 많은 특수성은 해당 프로세서(및 해당 Zilog Z-80 변형)와의 이전 버전과의 호환성 때문입니다.

Microsoft Win32는 32비트 플랫 모드x86 프로세서를 사용합니다. 이 설명서는 플랫 모드에만 집중합니다.

등록

x86 아키텍처는 다음과 같은 권한 없는 정수 레지스터로 구성됩니다.

eax

에너지 저장 장치

ebx

기본 레지스터

ecx

카운터 레지스터

edx

데이터 레지스터 - I/O 포트 액세스 및 산술 함수에 사용할 수 있습니다.

esi

소스 인덱스 레지스터

edi

대상 인덱스 레지스터

ebp

기본 포인터 레지스터

esp

스택 포인터

모든 정수 레지스터는 32비트입니다. 그러나 대부분 16비트 또는 8비트 하위 등록이 있습니다.

도끼

eax의 낮은 16비트

bx

낮은 16비트 ebx

cx

낮은 16비트 영역 ecx

dx

낮은 16비트 edx

si

하위 16비트 esi

낮은 16비트의 edi

bp

낮은 16비트 ebp

sp

낮은 16비트 esp

낮은 8비트 eax

상위 8비트 ax

bl

낮은 8비트 ebx

bh

상위 8비트 의 bx

cl

낮은 8비트 ecx

ch

상위 8비트 cx

dl

낮은 8비트 edx

dh

상위 8비트 dx

하위 등록에서 작동하면 하위 등록자만 영향을 받고 하위 등록 외부의 파트는 영향을 미치지 않습니다. 예를 들어 ax 레지스터에 저장하면 eax 레지스터의 상위 16비트가 변경되지 않은 상태로 유지됩니다.

을 사용하는 경우 (식 계산) 명령에는 "@" 기호(@)가 접두사로 지정되어야 합니다. 예를 들어, ? @ax를 사용해야 하며, ? ax를 사용하지 마세요. 이렇게 하면 디버거가 ax 기호가 아닌 레지스터로 인식할 수 있습니다.

그러나 (@)는 r(Registers) 명령에 필요하지 않습니다. 예를 들어 r ax=5 항상 올바르게 해석됩니다.

다른 두 레지스터는 프로세서의 현재 상태에 중요합니다.

명령 포인터

플래그

플래그

명령 포인터는 실행 중인 명령의 주소입니다.

플래그 레지스터는 단일 비트 플래그의 컬렉션입니다. 많은 지침은 명령의 결과를 설명하기 위해 플래그를 변경합니다. 그런 다음 조건부 점프 지침에 따라 이러한 플래그를 테스트할 수 있습니다. 자세한 내용은 x86 Flags 참조하세요.

호출 규칙

x86 아키텍처에는 여러 가지 호출 규칙이 있습니다. 다행히도 모두 동일한 레지스터 보존 및 함수 반환 규칙을 따릅니다.

  • 함수는 eax, ecx및 함수 호출에서 변경할 수 있는 edx, 호출 규칙에 따라 업데이트해야 하는 esp제외한 모든 레지스터를 유지해야 합니다.

  • eax 레지스터는 결과가 32비트 이하인 경우 함수 반환 값을 받습니다. 결과가 64비트인 경우 결과는 edx:eax 쌍에 저장됩니다.

다음은 x86 아키텍처에서 사용되는 호출 규칙 목록입니다.

  • Win32(__stdcall)

    함수 매개 변수는 스택에 전달되고 오른쪽에서 왼쪽으로 푸시되며 호출 수신자는 스택을 정리합니다.

  • 네이티브 C++ 메서드 호출(thiscall이라고도 함)

    함수 매개변수는 스택에 전달되고, 오른쪽에서 왼쪽으로 푸시되며, "this" 포인터는 ecx 레지스터에 전달됩니다. 피호출자가 스택을 정리합니다.

  • COM(C++ 메서드 호출의 경우__stdcall)

    함수 매개 변수는 스택에 전달되고 오른쪽에서 왼쪽으로 푸시된 다음 스택에 "this" 포인터가 푸시된 다음 함수가 호출됩니다. 호출 함수가 스택을 정리합니다.

  • __fastcall

    처음 두 개의 DWORD 또는 더 작은 인수는 ecx 레지스터 및 edx 레지스터에 전달됩니다. 나머지 매개 변수는 스택에 전달되고 오른쪽에서 왼쪽으로 푸시됩니다. 호출 수신자가 스택을 정리합니다.

  • __cdecl

    함수 매개 변수는 스택에 전달되고 오른쪽에서 왼쪽으로 푸시되며 호출자는 스택을 정리합니다. __cdecl 호출 규칙은 가변 길이 매개 변수가 있는 모든 함수에 사용됩니다.

디버거에서 레지스터와 플래그 표시

다음은 샘플 디버거 레지스터 화면입니다.

eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000286

사용자 모드 디버깅에서는 iopl 및 디버거 디스플레이의 마지막 줄 전체를 무시할 수 있습니다.

x86 플래그

앞의 예제에서 두 번째 줄 끝에 있는 두 글자 코드는 플래그입니다. 이러한 레지스터는 단일 비트 레지스터이며 다양한 용도로 사용됩니다.

다음 표에서는 x86 플래그를 나열합니다.

국기 코드 플래그 이름 플래그 상태 묘사
오버플로 플래그 0 1 nvov 오버플로가 없음 - 오버플로
df 방향 플래그 0 1 updn 위쪽 방향 - 아래쪽 방향
이면 인터럽트 플래그 0 1 diei 인터럽트 비활성화 - 인터럽트 활성화
sf 서명 플래그 0 1 plng 양수(또는 0) - 음수
zf 제로 플래그 0 1 nzzr 0이 아닌 - 0
af 보조 캐리 플래그 0 1 naac 보조 캐리 없음 - 보조 캐리
pf 패리티 플래그 0 1 페포 패리티 홀수 - 패리티 짝수
cf 캐리 플래그 0 1 nccy 캐리 없음 - 캐리
tf 트랩 플래그 tf이 1이라면, 프로세서가 명령어 하나를 실행한 후 STATUS_SINGLE_STEP 예외를 발생시킵니다. 이 플래그는 디버거에서 단일 단계 추적을 구현하는 데 사용됩니다. 다른 애플리케이션에서 사용하면 안 됩니다.
iopl I/O 권한 수준 I/O 권한 수준 0에서 3 사이의 값을 가진 2비트 정수입니다. 운영 체제에서 하드웨어에 대한 액세스를 제어하는 데 사용됩니다. 애플리케이션에서 사용하면 안 됩니다.

디버거 명령 창에서 일부 명령의 결과로 레지스터가 표시될 때, 표시되는 것은 플래그 상태입니다. 그러나 r(Registers) 명령을 사용하여 플래그를 변경하려면 플래그 코드참조해야 합니다.

WinDbg의 레지스터 창에서 플래그 코드는 플래그를 보거나 변경하는 데 사용됩니다. 플래그 상태는 지원되지 않습니다.

다음은 예제입니다. 앞의 레지스터 표시에서 플래그 상태 ng 나타납니다. 즉, 기호 플래그는 현재 1로 설정됩니다. 이를 변경하려면 다음 명령을 사용합니다.

r sf=0

그러면 기호 플래그가 0으로 설정됩니다. 다른 레지스터 표시를 수행하면 ng 상태 코드가 표시되지 않습니다. 대신 pl 상태 코드가 표시됩니다.

기호 플래그, 제로 플래그, 그리고 캐리 플래그는 가장 일반적으로 사용되는 플래그입니다.

여건

조건 하나 이상의 플래그 상태를 설명합니다. x86의 모든 조건부 작업은 조건부로 표현됩니다.

어셈블러는 하나 또는 두 개의 문자 약어를 사용하여 조건을 나타냅니다. 조건은 여러 약어로 나타낼 수 있습니다. 예를 들어 AE("위 또는 같음")는 NB("아래 아님")와 동일한 조건입니다. 다음 표에서는 몇 가지 일반적인 조건과 그 의미를 나열합니다.

조건 이름 플래그 의미

Z

ZF=1

마지막 작업의 결과는 0이었습니다.

뉴질랜드

ZF=0

마지막 작업의 결과가 0이 아닙니다.

C

CF=1

마지막 수술에는 캐리 또는 대여가 필요했습니다. 부호 없는 정수의 경우 오버플로를 나타냅니다.

노스캐롤라이나

CF=0

마지막 연산에는 캐리 또는 차용이 필요하지 않았습니다. 부호 없는 정수의 경우 오버플로를 나타냅니다.

S

SF=1

마지막 작업의 결과에는 높은 비트 집합이 있습니다.

NS

SF=0

마지막 작업의 결과는 최상위 비트가 초기화되어 있습니다.

O

OF=1

서명된 정수 작업으로 처리되는 경우 마지막 작업으로 인해 오버플로 또는 언더플로가 발생했습니다.

아니요

OF=0

서명된 정수 작업으로 처리되는 경우 마지막 작업으로 인해 오버플로 또는 언더플로가 발생하지 않았습니다.

조건을 사용하여 두 값을 비교할 수도 있습니다. cmp 명령은 두 피연산자를 비교한 다음, 한 피연산자를 다른 피연산자에서 빼는 것처럼 플래그를 설정합니다. 다음 조건을 사용하여 cmpvalue1value2의 결과를 확인할 수 있습니다.

조건명 플래그 CMP 작업 후의 의미입니다.

E

ZF=1

value1 == value2.

네브라스카

ZF=0

value1 != value2.

GE NL

SF=OF

value1>= value2. 값은 부호 있는 정수로 처리됩니다.

LE NG

ZF=1 또는 SF!=OF

value1<= value2. 값은 부호 있는 정수로 처리됩니다.

G NLE

ZF=0 및 SF=OF

value1>value2. 값은 부호 있는 정수로 처리됩니다.

L NGE

SF!=OF

value1<value2. 값은 부호 있는 정수로 처리됩니다.

AE NB

CF=0

value1>= value2. 값은 부호 없는 정수로 처리됩니다.

BE NA

CF=1 또는 ZF=1

value1<= value2. 값은 부호 없는 정수로 처리됩니다.

A NBE

CF=0 및 ZF=0

value1>value2. 값은 부호 없는 정수로 처리됩니다.

B NAE

CF=1

value1<value2. 값은 부호 없는 정수로 처리됩니다.

조건은 일반적으로 cmp 또는 test 명령어의 결과에 따라 작동하는 데 사용됩니다. 예를 들어

cmp eax, 5
jz equal

식(eax - 5)을 계산하고 결과에 따라 플래그를 설정하여 eax 레지스터를 숫자 5와 비교합니다. 빼기의 결과가 0이면 zr 플래그가 설정되고 jz 조건이 true이므로 점프가 수행됩니다.

데이터 형식

  • 바이트: 8비트

  • 단어: 16비트

  • dword: 32비트

  • qword: 64비트(부동 소수점 더블 포함)

  • 2번째: 80비트(부동 소수점 확장 더블 포함)

  • oword: 128비트

표기법

다음 표에서는 어셈블리 언어 지침을 설명하는 데 사용되는 표기법을 나타냅니다.

표기법 의미

r, r1, r2...

등록

m

메모리 주소(자세한 내용은 다음 주소 지정 모드 섹션 참조)

#n

즉시 상수

r/m

등록 또는 메모리

r/#n

레지스터 또는 즉시 값

r/m/#n

레지스터, 메모리 또는 즉시 상수

이전 조건 섹션에 나열된 조건 코드입니다.

T

"B", "W" 또는 "D"(바이트, 워드 또는 더블워드)

accT

크기 T 누산기: alT = "B"인 경우, T = "W"이면 ax, 그리고 T = "D"인 경우 eax

주소 지정 방식

주소 지정 모드는 여러 가지가 있지만 모두 T ptr [expr]형식을 사용합니다. 여기서 T 일부 데이터 형식이며(이전 데이터 형식 섹션 참조) expr 상수 및 레지스터와 관련된 일부 식입니다.

대부분의 모드에 대한 표기법은 많은 어려움 없이 추론할 수 있습니다. 예를 들어, BYTE PTR [esi+edx*8+3]는 "esi 레지스터의 값을 가져와서, 여기에 edx 레지스터 값의 8배를 더하고, 3을 더한 결과 주소에서 바이트에 액세스하라"는 의미입니다.

파이프라인

펜티엄은 듀얼 이슈로, 한 클록 사이클에서 최대 두 개의 작업을 수행할 수 있습니다. 그러나 한 번에 두 작업을 수행할 수 있는 경우(페어링라고 함)에 대한 규칙은 매우 복잡합니다.

x86은 CISC 프로세서이므로 점프 지연 슬롯에 대해 걱정할 필요가 없습니다.

동기화된 메모리 액세스

로드, 수정 및 저장 명령어는 잠금 접두사를 받을 수 있으며, 이는 명령어를 다음과 같이 수정합니다.

  1. 명령을 실행하기 전에 CPU는 모든 보류 중인 메모리 작업을 플러시하여 일관성을 보장합니다. 모든 데이터 프리페치는 중단됩니다.

  2. 명령을 실행하는 동안 CPU는 버스에 단독으로 액세스할 수 있습니다. 이렇게 하면 로드/수정/저장소 작업의 원자성이 보장됩니다.

xchg 명령은 메모리와 값을 교환할 때마다 이전 규칙을 자동으로 따릅니다.

다른 모든 지침은 기본적으로 비잠금 상태로 설정됩니다.

점프 예측

무조건 점프가 수행될 것으로 예측됩니다.

조건부 점프는 마지막으로 실행된 시간에 수행되었는지 여부에 따라 수행되거나 수행되지 않을 것으로 예측됩니다. 점프 기록을 기록하기 위한 캐시의 크기는 제한됩니다.

CPU에 조건부 점프가 마지막으로 실행되었을 때 수행되었는지 여부에 관한 기록이 없는 경우, 역방향 조건부 점프는 수행된 것으로, 정방향 조건부 점프는 수행되지 않은 것으로 예측합니다.

정렬

x86 프로세서는 성능 저하를 감수하고 정렬되지 않은 메모리 액세스를 자동으로 수정합니다. 예외가 발생하지 않습니다.

주소가 개체 크기의 정수 배수인 경우 메모리 액세스가 정렬된 것으로 간주됩니다. 예를 들어 모든 BYTE 액세스는 항상 정렬됩니다 (모든 값이 1의 배수이기 때문입니다). 또한, 짝수 주소에 대한 WORD 액세스는 정렬되며, DWORD 주소는 정렬되기 위해 반드시 4의 배수여야 합니다.

잠금 접두사는 정렬되지 않은 메모리 액세스에 사용하면 안 됩니다.

참고하기

x64 아키텍처

X86-64 Wikipedia