다음을 통해 공유


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비트 하위 등록이 있습니다.

도끼

낮은 16비트 eax

bx

낮은 16비트 ebx

cx

낮은 16비트 ecx

dx

낮은 16비트 edx

si

낮은 16비트 esi

di

낮은 16비트 edi

혈압

낮은 16비트 ebp

sp

낮은 16비트 esp

낮은 8비트 eax

높은 8비트 도끼

bl

낮은 8비트 ebx

bh

높은 8비트 bx

cl

낮은 8비트 ecx

ch

높은 8비트 cx

dl

낮은 8비트 edx

dh

높은 8비트 dx

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

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

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

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

eip

명령 포인터

flags

flags

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

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

호출 규칙

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

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

  • 결과가 32비트 이하인 경우 eax 레지스터는 함수 반환 값을 받습니다. 결과가 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 위쪽 방향 - 아래쪽 방향
if 인터럽트 플래그 0 1 diei 인터럽트 사용 안 함 - 인터럽트 사용
sf 서명 플래그 0 1 plng 양수(또는 0) - 음수
zf 0 플래그 0 1 nzzr 0이 아닌 - 0
af 보조 캐리 플래그 0 1 naac 보조 캐리 없음 - 보조 캐리
pf 패리티 플래그 0 1 pepo 패리티 홀수 - 패리티 짝수
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이었습니다.

NZ

ZF=0

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

C

CF=1

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

NC

CF=0

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

S

SF=1

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

NS

SF=0

마지막 작업의 결과는 매우 명확합니다.

O

OF=1

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

아니요

OF=0

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

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

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

E

ZF=1

value1 == value2.

NE

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 또는 테스트 명령의 결과에 따라 작동하는 데 사용됩니다. 예를 들면 다음과 같습니다.

cmp eax, 5
jz equal

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

데이터 형식

  • 바이트: 8비트

  • 단어: 16비트

  • dword: 32비트

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

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

  • oword: 128비트

기보법

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

표기법 의미

r, r1, r2...

레지스터

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

#n

직접 실행 상수

r/m

등록 또는 메모리

r/#n

등록 또는 즉시 상수

r/m/#n

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

cc(cc)

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

T

"B", "W" 또는 "D"(바이트, 단어 또는 dword)

accT

크기 T 누적기: al if T = "B", ax if T = "W" 또는 eax if T = "D"

주소 지정 모드

주소 지정 모드는 여러 가지가 있지만 모두 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 주소가 정렬되려면 DWORD 주소가 4의 배수여야 합니다.

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