x86_64 명령어셋 레퍼런스

x86_64(AMD64/Intel 64) 아키텍처의 명령어를 AT&T 문법 기준으로 종합 정리합니다. CISC 설계 철학과 가변 길이 인코딩, 16개 범용 레지스터와 RFLAGS, SSE/AVX/AVX-512 SIMD 레지스터, 주소 지정 모드, 데이터 전송·산술·논리·분기·스택·시스템·원자적·SIMD 명령어 카테고리 표, REX/VEX/EVEX 인코딩 다이어그램, 커널 핵심 명령어(SYSCALL, SWAPGS, LOCK CMPXCHG, INVLPG) 심화까지 Linux 커널 개발에 필요한 x86_64 ISA 전체를 다룹니다.

전제 조건: 어셈블리 종합을 먼저 읽으세요. x86_64 명령어 레퍼런스는 AT&T 문법, 레지스터 규약, 피연산자 크기 접미사에 대한 기본 이해가 필요합니다.
일상 비유: x86_64는 스위스 아미 나이프와 같습니다. 하나의 도구(명령어)가 다양한 모드와 접두사를 조합해 수백 가지 동작을 수행할 수 있지만, 그만큼 복잡합니다. CISC 설계 특유의 풍부한 명령어 세트를 카테고리별로 정리하면 전체 구조가 보입니다.

핵심 요약

  • CISC 아키텍처 — 가변 길이 명령어(1~15바이트), 메모리 피연산자 직접 사용, 풍부한 주소 모드.
  • AT&T 문법 — 소스→목적지 순서, % 레지스터 접두사, $ 즉시값 접두사, b/w/l/q 크기 접미사.
  • 16개 범용 레지스터 — RAX-RDI(기존 8개) + R8-R15(AMD64 확장), 64/32/16/8-bit 접근 가능.
  • SIMD 확장 — SSE(XMM, 128-bit) → AVX(YMM, 256-bit) → AVX-512(ZMM, 512-bit + 마스크 레지스터).
  • LOCK 접두사 — 원자적 메모리 연산의 핵심. CMPXCHG, XADD 등과 결합.

단계별 이해

  1. 레지스터 맵 파악
    16개 범용 레지스터의 이름 규칙(RAX/EAX/AX/AL)과 System V ABI 용도를 먼저 익힙니다.
  2. AT&T 문법 숙지
    접미사(b/w/l/q), 접두사(%/$), 소스→목적지 순서를 반드시 구분합니다.
  3. 주소 모드 이해
    displacement(base,index,scale) SIB 형식이 x86_64 주소 지정의 핵심입니다.
  4. 카테고리별 명령어 학습
    데이터 전송 → 산술 → 논리 → 분기 → 시스템 순서로 진행하면 체계적입니다.

아키텍처 개요

x86_64(AMD64)는 2003년 AMD가 IA-32(x86)를 64-bit로 확장한 CISC 아키텍처입니다. 8086(1978) → 80386(1985, 32-bit) → AMD64(2003, 64-bit) 순으로 발전했으며, 하위 호환성을 유지하면서 레지스터와 주소 공간을 확장했습니다.

특성x86_64
설계 철학CISC (Complex Instruction Set Computer)
명령어 길이가변 (1~15바이트)
엔디언리틀 엔디언 (Little-Endian)
범용 레지스터16개 (64-bit)
주소 공간가상 48-bit (256TB), 물리 최대 52-bit
동작 모드Long Mode (64-bit), Compatibility Mode (32-bit), Legacy Mode
페이지 크기4KB, 2MB, 1GB
명령어 접두사REX, VEX, EVEX, LOCK, REP, 세그먼트 오버라이드
Long Mode: 64-bit 모드에서는 기본 오퍼랜드 크기가 32-bit이며, REX.W 접두사로 64-bit 연산을 지정합니다. 주소 크기는 기본 64-bit입니다.

동작 모드 전환 다이어그램

x86_64 프로세서는 전원 인가 후 Real Mode에서 시작하며, 제어 레지스터 비트를 조작해 단계적으로 Long Mode(64-bit)까지 전환합니다. 리눅스 커널 부트 과정에서 이 전환은 arch/x86/boot/compressed/head_64.S에서 수행됩니다.

x86_64 동작 모드 전환 (Power-On → Long Mode) Real Mode 16-bit 주소 1MB 메모리 (전원 인가 시 시작) CR0.PE=1 Protected Mode 32-bit 주소 4GB 메모리, 특권 링 (GDT/IDT 설정 필요) CR4.PAE=1 EFER.LME=1 CR0.PG=1 Long Mode (IA-32e) 64-bit 가상 주소 256TB (48-bit), 4-level 페이징 16개 범용 레지스터 64-bit Mode CS.L=1, CS.D=0 커널 + 64-bit 앱 Compat Mode CS.L=0 32-bit 앱 Legacy Mode EFER.LME=0 (Long Mode 미전환) 전환 순서 (리눅스 부트): 1. GDT 설정 + CR0.PE=1 (Protected Mode 진입) 2. CR4.PAE=1 (PAE 활성) → CR3=PML4 (4-level 페이지 테이블 설정) → EFER.LME=1 → CR0.PG=1 (Long Mode 활성) 3. CS.L=1인 코드 세그먼트로 far jump → 64-bit Mode 실행
주의: Long Mode 진입 전에 반드시 4-level 페이징(PML4)을 설정해야 합니다. CR0.PG=1과 EFER.LME=1이 동시에 활성화되면 프로세서는 Long Mode로 전환됩니다. 페이지 테이블이 올바르지 않으면 즉시 트리플 폴트가 발생합니다.

레지스터 셋

범용 레지스터 (64-bit / 32-bit / 16-bit / 8-bit)

64-bit32-bit16-bit8-bit (Low)8-bit (High)System V ABI 용도
%rax%eax%ax%al%ah반환값 (1st)
%rbx%ebx%bx%bl%bhCallee-saved
%rcx%ecx%cx%cl%ch4th 인자
%rdx%edx%dx%dl%dh3rd 인자, 반환값 (2nd)
%rsi%esi%si%sil2nd 인자
%rdi%edi%di%dil1st 인자
%rbp%ebp%bp%bpl프레임 포인터 (Callee-saved)
%rsp%esp%sp%spl스택 포인터
%r8%r8d%r8w%r8b5th 인자
%r9%r9d%r9w%r9b6th 인자
%r10%r10d%r10w%r10bCaller-saved
%r11%r11d%r11w%r11bCaller-saved
%r12%r12d%r12w%r12bCallee-saved
%r13%r13d%r13w%r13bCallee-saved
%r14%r14d%r14w%r14bCallee-saved
%r15%r15d%r15w%r15bCallee-saved

레지스터 중첩 구조 (RAX 예시)

x86_64 범용 레지스터는 하위 호환성을 위해 중첩 구조를 가집니다. 64-bit RAX 안에 32-bit EAX가, 그 안에 16-bit AX가, AX는 다시 상위 AH와 하위 AL로 나뉩니다.

RAX 레지스터 비트 구조 (64-bit) 63 32 31 16 15 8 7 0 RAX (64-bit) 상위 32-bit (32-bit 쓰기 시 0) EAX (32-bit) 비트 31-16 AX (16-bit) AH (비트 15-8) AL (비트 7-0) movl %eax, ... 실행 시 RAX의 비트 63-32가 자동으로 0이 됨 (제로 확장)
32-bit 쓰기 주의: x86_64에서 32-bit 레지스터(EAX, EBX 등)에 쓰면 상위 32-bit이 자동으로 0이 됩니다. 예: movl $1, %eax → RAX = 0x00000001. 반면 16-bit/8-bit 쓰기는 상위 비트에 영향을 주지 않습니다. 예: movw $1, %ax → RAX의 상위 48-bit은 그대로 유지됩니다. R8-R15 레지스터에서는 AH 같은 상위 8-bit 접근이 불가능합니다.

RFLAGS 레지스터 주요 비트

비트약어이름설명
0CFCarry Flag부호 없는 연산 올림/빌림
2PFParity Flag결과 하위 바이트의 짝수 패리티
6ZFZero Flag결과가 0이면 세트
7SFSign Flag결과의 최상위 비트 (부호)
8TFTrap Flag단일 스텝 디버깅
9IFInterrupt Flag인터럽트 활성화/비활성화
10DFDirection Flag문자열 명령어 방향 (0=증가, 1=감소)
11OFOverflow Flag부호 있는 연산 오버플로

특수/시스템 레지스터

레지스터설명
%rip명령어 포인터 (Instruction Pointer)
%cs, %ds, %es, %fs, %gs, %ss세그먼트 레지스터 (Long Mode에서 FS/GS만 유효)
CR0제어 레지스터: PE(보호모드), PG(페이징), WP(쓰기 보호) 등
CR2Page Fault 선형 주소
CR3페이지 디렉토리 베이스 (PML4 물리 주소)
CR4확장 기능: PAE, PSE, OSXSAVE, PCIDE, SMEP, SMAP 등
MSR EFERExtended Feature Enable: LME(Long Mode Enable), SCE(SYSCALL Enable), NXE
MSR LSTARSYSCALL 진입 주소 (64-bit)
MSR STARSYSCALL/SYSRET CS/SS 세그먼트
MSR FMASKSYSCALL 시 RFLAGS 마스크

SIMD 레지스터

확장레지스터크기개수
SSEXMM0-XMM15128-bit16
AVXYMM0-YMM15256-bit16
AVX-512ZMM0-ZMM31512-bit32
AVX-512 마스크k0-k764-bit8 (k0은 암묵적 all-ones)
SSE 제어MXCSR32-bit1 (라운딩 모드, 예외 마스크)

SIMD 레지스터 중첩 구조

SIMD 레지스터는 SSE → AVX → AVX-512 확장에 따라 중첩 구조를 가집니다. ZMM의 하위 256-bit은 YMM이고, YMM의 하위 128-bit은 XMM입니다.

SIMD 레지스터 중첩 구조 (ZMM0 예시) 511 256 255 128 127 0 ZMM0 (512-bit) — AVX-512 YMM0 (256-bit) — AVX XMM0 (128-bit) — SSE 요소 패킹 예시 (XMM 128-bit 기준) float x 4 (PS) 32b 32b 32b 32b double x 2 (PD) 64b 64b int32 x 4 (D) int16 x 8 (W) int8 x 16 (B) int64 x 2 (Q) VEX 128-bit 명령어 실행 시 YMM 상위 128-bit 자동 제로화 | SSE 레거시 명령어는 상위 비트 보존 (성능 저하 가능)
커널에서의 SIMD: 리눅스 커널은 기본적으로 SIMD 레지스터를 사용하지 않습니다. 커널 공간에서 XMM/YMM/ZMM 레지스터를 사용하려면 반드시 kernel_fpu_begin() / kernel_fpu_end()로 FPU 상태를 저장/복원해야 합니다. 이는 주로 암호화(aesni-intel), CRC 계산, RAID XOR 등에서 활용됩니다.

주소 지정 모드

x86_64 AT&T 문법에서 메모리 피연산자는 displacement(base, index, scale) 형식을 사용합니다.

모드AT&T 문법계산예제
즉시값$imm상수 값movq $42, %rax
레지스터%reg레지스터 값movq %rbx, %rax
직접 메모리addr[addr]movq 0x1000, %rax
간접(%reg)[reg]movq (%rdi), %rax
오프셋disp(%reg)[reg + disp]movq 8(%rbp), %rax
인덱스(%base,%idx)[base + idx]movq (%rax,%rcx), %rdx
SIBdisp(%base,%idx,s)[base + idx*s + disp]movq 16(%rdi,%rsi,8), %rax
RIP 상대symbol(%rip)[RIP + offset]movq var(%rip), %rax
크기 접미사: b(byte, 8-bit), w(word, 16-bit), l(long, 32-bit), q(quad, 64-bit). 예: movb, movw, movl, movq.

ModR/M 및 SIB 바이트 구조

x86_64 메모리 피연산자의 인코딩에서 ModR/M 바이트는 주소 모드와 레지스터를 지정하고, SIB(Scale-Index-Base) 바이트는 복합 주소 계산(base + index * scale + displacement)을 인코딩합니다. ModR/M의 R/M 필드가 100(RSP 인코딩)이면 SIB 바이트가 뒤따릅니다.

ModR/M 바이트 (1 byte = 8 bits) 7 6 5 4 3 2 1 0 Mod (2 bits) Reg/Opcode (3 bits) R/M (3 bits) Mod: 00=간접 01=disp8, 10=disp32 11=레지스터 R/M=100 (RSP) → SIB 사용 SIB 바이트 (Scale-Index-Base, 1 byte) 7 6 5 4 3 2 1 0 Scale (2 bits) Index (3 bits) Base (3 bits) Scale: 00=x1 01=x2, 10=x4 11=x8 유효 주소 = Base + (Index * Scale) + Displacement 예: 16(%rdi,%rsi,8) → Mod=01(disp8), R/M=100(SIB), Scale=11(x8), Index=RSI, Base=RDI, Disp=16
RIP 상대 주소: x86_64 Long Mode에서는 Mod=00, R/M=101 조합이 RIP 상대 주소를 의미합니다 (32-bit에서는 절대 주소). movq var(%rip), %rax에서 어셈블러는 현재 RIP부터 var까지의 오프셋을 32-bit displacement로 인코딩합니다. 이 방식은 Position-Independent Code(PIC)에 필수적이며, 커널의 KASLR(Kernel Address Space Layout Randomization)에서도 활용됩니다.

데이터 전송 명령어

명령어AT&T 문법설명동작
MOVmovq %rax, %rbx데이터 이동dst ← src
MOVSXmovslq %eax, %rbx부호 확장 이동dst ← sign_extend(src)
MOVZXmovzbl %al, %eax제로 확장 이동dst ← zero_extend(src)
LEAleaq 8(%rdi,%rsi,4), %rax유효 주소 계산dst ← effective_address (메모리 접근 없음)
XCHGxchgq %rax, %rbx값 교환 (메모리 시 암묵적 LOCK)tmp ← dst; dst ← src; src ← tmp
BSWAPbswap %eax바이트 순서 반전엔디언 변환
CMOVcccmovzq %rbx, %rax조건부 이동조건 충족 시 dst ← src
MOVSmovsq문자열 복사[RDI] ← [RSI]; RSI/RDI 갱신
LODSlodsq문자열 로드RAX ← [RSI]; RSI 갱신
STOSstosq문자열 저장[RDI] ← RAX; RDI 갱신
PUSHpushq %rax스택 푸시RSP -= 8; [RSP] ← src
POPpopq %rax스택 팝dst ← [RSP]; RSP += 8
MOV vs LEA vs MOVSX/MOVZX 비교:
  • MOV — 메모리에서 값을 읽어서 레지스터에 저장합니다. movq (%rdi), %rax는 RDI가 가리키는 주소의 8바이트 값을 RAX에 로드합니다.
  • LEA — 메모리를 접근하지 않고 주소 자체를 계산합니다. leaq 8(%rdi,%rsi,4), %rax는 RDI + RSI*4 + 8 결과를 RAX에 저장하며, 플래그를 변경하지 않습니다. 산술 연산의 대용으로 자주 사용됩니다.
  • MOVSX (movslq) — 작은 크기의 부호 있는 값을 큰 레지스터로 부호 확장합니다. 커널에서 int(32-bit) → long(64-bit) 변환에 필수적입니다.
  • MOVZX (movzbl) — 작은 크기의 부호 없는 값을 제로 확장합니다. u8u64 변환 등에 사용됩니다.
/* 커널에서 자주 보이는 패턴 */

/* 1. LEA로 구조체 멤버 주소 계산 (메모리 접근 없음) */
/*    leaq offset(%rdi), %rax   — container_of() 매크로 결과 */

/* 2. MOVSX: syscall 번호(int) → 테이블 인덱스(long) */
/*    movslq %eax, %rax  — 32-bit 부호 있는 값을 64-bit로 확장 */

/* 3. MOVZX: 바이트 읽기 → 레지스터 제로 확장 */
/*    movzbl (%rdi), %eax  — 1바이트 로드, EAX 제로 확장 (RAX 상위도 0) */

/* 4. CMOVcc: 조건부 이동으로 분기 제거 */
int clamp_min(int val, int min_val) {
    return val < min_val ? min_val : val;
    /* 컴파일 결과:
       cmpl %esi, %edi      // val - min_val
       cmovll %esi, %edi    // val < min_val이면 edi = min_val
       movl %edi, %eax      // return
    */
}

산술 명령어

명령어AT&T 문법설명플래그 영향
ADDaddq %rax, %rbx덧셈CF, ZF, SF, OF, PF
SUBsubq %rax, %rbx뺄셈CF, ZF, SF, OF, PF
ADCadcq %rax, %rbx올림 포함 덧셈CF, ZF, SF, OF, PF
SBBsbbq %rax, %rbx빌림 포함 뺄셈CF, ZF, SF, OF, PF
INCincq %rax1 증가 (CF 미변경)ZF, SF, OF, PF
DECdecq %rax1 감소 (CF 미변경)ZF, SF, OF, PF
NEGnegq %rax2의 보수 부정CF, ZF, SF, OF, PF
MULmulq %rbx부호 없는 곱셈CF, OF (RDX:RAX ← RAX * src)
IMULimulq %rbx, %rax부호 있는 곱셈 (2/3 오퍼랜드)CF, OF
DIVdivq %rbx부호 없는 나눗셈RAX ← 몫, RDX ← 나머지
IDIVidivq %rbx부호 있는 나눗셈RAX ← 몫, RDX ← 나머지
CQOcqoRAX 부호를 RDX로 확장
CDQcdqEAX 부호를 EDX로 확장
LEA를 이용한 산술 트릭: LEA는 주소 계산 명령어지만, 플래그를 변경하지 않으면서 덧셈과 곱셈을 동시에 수행할 수 있어 커널 코드에서 최적화 용도로 광범위하게 사용됩니다.
  • leaq (%rdi,%rdi,1), %raxrax = rdi * 2 (SHL보다 유연)
  • leaq (%rdi,%rdi,2), %raxrax = rdi * 3
  • leaq (%rdi,%rdi,4), %raxrax = rdi * 5
  • leaq (%rdi,%rdi,8), %raxrax = rdi * 9
  • leaq 7(%rdi,%rdi,8), %raxrax = rdi * 9 + 7
  • leaq (,%rdi,8), %raxrax = rdi * 8 (shift 대체)
/* GCC가 자주 생성하는 LEA 패턴 */

/* x * 3 */
leaq    (%rdi,%rdi,2), %rax    /* rax = rdi + rdi*2 = rdi*3 */

/* x * 5 + 1 */
leaq    1(%rdi,%rdi,4), %rax   /* rax = rdi + rdi*4 + 1 = rdi*5 + 1 */

/* x * 12 (두 단계) */
leaq    (%rdi,%rdi,2), %rax    /* rax = rdi*3 */
shlq    $2, %rax               /* rax = rdi*3*4 = rdi*12 */

/* 주의: LEA는 RFLAGS를 변경하지 않으므로 */
/* CMP/TEST 뒤의 조건 분기를 방해하지 않음 */
cmpq    $0, %rsi
leaq    1(%rdi), %rdi          /* rdi++, 플래그 보존 (INC는 ZF 변경) */
je      .Lzero                  /* 위의 CMP 결과로 분기 */

논리/시프트/비트 조작 명령어

명령어AT&T 문법설명플래그 영향
ANDandq %rax, %rbx비트 ANDZF, SF, PF (CF=OF=0)
ORorq %rax, %rbx비트 ORZF, SF, PF (CF=OF=0)
XORxorq %rax, %rax비트 XOR (셀프 XOR = 0)ZF, SF, PF (CF=OF=0)
NOTnotq %rax비트 반전
TESTtestq %rax, %rbx비트 AND (결과 저장 안 함)ZF, SF, PF (CF=OF=0)
SHL/SALshlq $3, %rax좌측 시프트CF(마지막 밀려난 비트), ZF, SF
SHRshrq $1, %rax논리 우측 시프트CF, ZF, SF
SARsarq $1, %rax산술 우측 시프트 (부호 보존)CF, ZF, SF
ROL/RORrolq $4, %rax좌측/우측 순환 시프트CF, OF
BTbtq $5, %rax비트 테스트CF ← 지정 비트
BTS/BTR/BTCbtsq $5, %rax비트 테스트 후 세트/리셋/토글CF ← 이전 비트
BSFbsfq %rbx, %rax최하위 세트 비트 검색ZF (src=0이면 세트)
BSRbsrq %rbx, %rax최상위 세트 비트 검색ZF
POPCNTpopcntq %rbx, %rax세트 비트 수 카운트ZF (CF=SF=OF=PF=0)
LZCNTlzcntq %rbx, %rax선행 제로 비트 수CF, ZF
TZCNTtzcntq %rbx, %rax후행 제로 비트 수CF, ZF
PEXTpextq %rcx, %rbx, %rax병렬 비트 추출 (BMI2)
PDEPpdepq %rcx, %rbx, %rax병렬 비트 배치 (BMI2)

비교/분기 명령어

명령어AT&T 문법설명조건
CMPcmpq %rax, %rbxrbx - rax (결과 저장 안 함)CF, ZF, SF, OF 세트
TESTtestq %rax, %raxrax & rax (zero 검사)ZF, SF, PF 세트
JE/JZje label같으면 분기ZF=1
JNE/JNZjne label다르면 분기ZF=0
JG/JNLEjg label부호 있는 >ZF=0 && SF=OF
JGE/JNLjge label부호 있는 >=SF=OF
JL/JNGEjl label부호 있는 <SF≠OF
JLE/JNGjle label부호 있는 <=ZF=1 || SF≠OF
JA/JNBEja label부호 없는 >CF=0 && ZF=0
JAE/JNBjae label부호 없는 >=CF=0
JB/JNAEjb label부호 없는 <CF=1
JBE/JNAjbe label부호 없는 <=CF=1 || ZF=1
JS/JNSjs label부호 비트SF=1 / SF=0
JO/JNOjo label오버플로OF=1 / OF=0
JMPjmp label무조건 분기
LOOPloop labelRCX-- 후 0이 아니면 분기

분기 예측과 커널 최적화

현대 x86_64 프로세서는 분기 예측 유닛(BPU)을 사용해 조건 분기의 결과를 투기적으로 예측합니다. 예측이 맞으면 파이프라인이 지연 없이 계속 진행되지만, 예측 실패(misprediction) 시 10~20 사이클의 페널티가 발생합니다.

likely() / unlikely() 매크로: 리눅스 커널은 GCC의 __builtin_expect()를 활용해 분기 예측 힌트를 제공합니다. 이 매크로는 코드 레이아웃을 변경하여 예상되는 경로(hot path)를 직선으로 배치하고, 예외 경로(cold path)를 별도 위치로 분리합니다.
  • likely(cond)__builtin_expect(!!(cond), 1) — 조건이 참일 가능성이 높음
  • unlikely(cond)__builtin_expect(!!(cond), 0) — 조건이 거짓일 가능성이 높음 (에러 경로 등)
/* include/linux/compiler.h */
#define likely(x)   __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

/* 사용 예시 — 페이지 폴트 핸들러 */
if (unlikely(fault_signal_pending(fault, regs))) {
    /* 시그널 처리 (cold path — 거의 실행되지 않음) */
    return;
}
/* 정상 처리 (hot path — 대부분 여기로 진행) */
/* unlikely() 적용 시 GCC가 생성하는 코드 레이아웃 */
/* hot path가 직선(fall-through)이 되도록 배치 */

.Lhot_path:
    testq   %rax, %rax
    jne     .Lcold_path         /* unlikely: 분기 안 하는 것이 일반적 */
    /* ... 정상 처리 (fall-through) ... */
    ret

    /* cold path는 함수 끝으로 분리 (I-cache 효율) */
    .section .text.unlikely
.Lcold_path:
    /* ... 에러 처리 ... */
    jmp     .Lerror_handler
Spectre 완화: 분기 예측의 투기적 실행은 보안 취약점(Spectre v1/v2)의 원인이 됩니다. 커널은 LFENCE 삽입, retpoline(간접 분기 보호), IBRS/IBPB(Indirect Branch Prediction Barrier) 등의 완화 기법을 사용합니다. array_index_nospec() 매크로는 LFENCE를 사용해 투기적 배열 접근을 방지합니다.

스택/함수 호출 명령어

명령어AT&T 문법설명동작
PUSHpushq %rax스택 푸시RSP -= 8; [RSP] ← src
POPpopq %rax스택 팝dst ← [RSP]; RSP += 8
CALLcall func함수 호출PUSH RIP; RIP ← target
RETret함수 복귀POP RIP
ENTERenter $N, $0스택 프레임 설정PUSH RBP; RBP ← RSP; RSP -= N
LEAVEleave스택 프레임 해제RSP ← RBP; POP RBP
System V AMD64 ABI 호출 규약:
  • 정수 인자: RDI, RSI, RDX, RCX, R8, R9 (순서대로 6개)
  • 반환값: RAX (+ RDX 128-bit)
  • Callee-saved: RBX, RBP, R12-R15
  • Caller-saved: RAX, RCX, RDX, RSI, RDI, R8-R11
  • 스택 16-byte 정렬 필수 (CALL 직전)
  • Red Zone: RSP 아래 128바이트 (리프 함수용, 커널에서는 비활성화)

시스템/특권 명령어

명령어설명특권 수준
SYSCALL시스템 콜 진입 (MSR LSTAR → RIP)Ring 3 → Ring 0
SYSRET시스템 콜 복귀 (RCX → RIP)Ring 0 → Ring 3
INT n소프트웨어 인터럽트 (IDT[n])Ring 3
IRET/IRETQ인터럽트/예외 복귀Ring 0
CLI인터럽트 비활성화 (IF=0)Ring 0
STI인터럽트 활성화 (IF=1)Ring 0
HLT프로세서 정지 (인터럽트 대기)Ring 0
LGDT/SGDTGDT 로드/저장Ring 0 / Ring 3
LIDT/SIDTIDT 로드/저장Ring 0 / Ring 3
LLDT/LTRLDT/TSS 로드Ring 0
SWAPGSGS 베이스와 MSR_KERNEL_GS_BASE 교환Ring 0
WRMSR/RDMSRMSR 쓰기/읽기 (ECX=번호)Ring 0
RDTSC타임스탬프 카운터 읽기Ring 3 (CR4.TSD로 제한 가능)
RDTSCPRDTSC + 프로세서 ID (IA32_TSC_AUX)Ring 3
CPUIDCPU 정보 쿼리Ring 3
INVLPGTLB 엔트리 무효화Ring 0
MOV CRn제어 레지스터 접근Ring 0
MOV DRn디버그 레지스터 접근Ring 0
IN/OUTI/O 포트 입출력Ring 0 (또는 IOPL)
WBINVD캐시 라이트백 + 무효화Ring 0
CLFLUSH캐시 라인 플러시Ring 3
CLFLUSHOPT최적화된 캐시 라인 플러시Ring 3
CLWB캐시 라인 라이트백 (무효화 없음)Ring 3
MFENCE메모리 펜스 (전체 직렬화)Ring 3
LFENCE로드 펜스 + 명령어 직렬화Ring 3
SFENCE스토어 펜스Ring 3
PAUSE스핀-웨이트 루프 힌트Ring 3

SYSCALL/SYSRET 메커니즘 상세

SYSCALL은 인터럽트(INT 0x80)보다 훨씬 빠른 시스템 콜 진입 방법입니다. 스택 전환이나 IDT 조회 없이 MSR에 미리 설정된 값으로 즉시 커널 코드로 점프합니다. 이 과정에서 하드웨어가 자동으로 수행하는 레지스터 조작을 이해하는 것이 중요합니다.

SYSCALL / SYSRET 시스템 콜 흐름 User Space (Ring 3) 사용자 프로세스 SYSCALL SYSRET RIP ← RCX Kernel Space (Ring 0) entry_SYSCALL_64 SWAPGS + 레지스터 저장 sys_call_table RAX = syscall 번호 시스콜 핸들러 sys_read() 등 SYSRET SYSCALL 하드웨어 동작: RCX ← RIP | R11 ← RFLAGS | RIP ← MSR_LSTAR CS ← MSR_STAR[47:32] | SS ← MSR_STAR[47:32]+8 SYSRET 하드웨어 동작: RIP ← RCX | RFLAGS ← R11 CS ← MSR_STAR[63:48]+16 | SS ← MSR_STAR[63:48]+8 커널 부트 시 MSR 초기화 (arch/x86/kernel/cpu/common.c): MSR_LSTAR = entry_SYSCALL_64 /* SYSCALL 시 점프할 커널 진입점 */ MSR_STAR = (USER_CS-16)<<48 | KERNEL_CS<<32 /* CS/SS 세그먼트 */ MSR_FMASK = X86_EFLAGS_IF | X86_EFLAGS_TF | ... /* SYSCALL 시 클리어할 RFLAGS */
SYSRET 보안 주의: SYSRET은 비표준(non-canonical) RCX 값에 대해 Ring 0에서 #GP 예외를 발생시킵니다. 이는 잠재적 보안 취약점(CVE-2014-4699)의 원인이 됩니다. 리눅스 커널은 이를 방지하기 위해 RCX가 표준 주소인지 반드시 검증한 후 SYSRET을 실행합니다. 비표준 주소가 감지되면 더 안전하지만 느린 IRETQ 경로를 사용합니다.

원자적/동기화 명령어

LOCK 접두사는 다음 명령어의 메모리 연산을 원자적으로 만듭니다. 캐시 라인 락 또는 버스 락을 통해 멀티코어 환경에서 원자성을 보장합니다.

명령어AT&T 문법설명
LOCK ADDlock addq $1, (%rdi)원자적 덧셈
LOCK SUBlock subq $1, (%rdi)원자적 뺄셈
LOCK INC/DEClock incq (%rdi)원자적 증가/감소
LOCK AND/OR/XORlock andq %rax, (%rdi)원자적 비트 연산
LOCK BTS/BTR/BTClock btsq $5, (%rdi)원자적 비트 테스트-세트/리셋/토글
LOCK XADDlock xaddq %rax, (%rdi)원자적 교환-덧셈 (old → rax)
LOCK CMPXCHGlock cmpxchgq %rcx, (%rdi)원자적 비교-교환 (CAS)
LOCK CMPXCHG16Block cmpxchg16b (%rdi)128-bit CAS (RDX:RAX vs [mem])
XCHGxchgq %rax, (%rdi)교환 (메모리 시 암묵적 LOCK)

LOCK CMPXCHG 패턴 (Compare-And-Swap)

/* atomic_cmpxchg: [rdi]가 rsi이면 rdx로 교체 */
atomic_cmpxchg:
    movq    %rsi, %rax          /* RAX ← expected (old) */
    lock cmpxchgq %rdx, (%rdi) /* if [RDI]==RAX then [RDI]←RDX */
                                  /* RAX ← [RDI] (이전 값) */
    ret                         /* RAX에 이전 값 반환 */
LOCK 접두사 구현 방식: LOCK 접두사의 원자성 보장 메커니즘은 메모리 주소의 정렬 상태에 따라 다릅니다.
  • 캐시 라인 락 (Cache Line Lock) — 대상 메모리가 단일 캐시 라인 내에 정렬되어 있으면, MESI 프로토콜의 Exclusive/Modified 상태를 이용해 해당 캐시 라인만 잠급니다. 다른 코어는 이 캐시 라인에 대한 Invalidate 요청이 완료될 때까지 대기합니다. 이 방식이 대부분의 경우에 사용되며 성능이 좋습니다.
  • 버스 락 (Bus Lock) — 대상이 캐시 라인 경계를 걸쳐 있거나(split lock), 캐시 불가능 메모리인 경우 #LOCK 시그널로 전체 메모리 버스를 잠급니다. 이는 시스템 전체 성능에 심각한 영향을 줍니다.
커널은 CONFIG_SPLIT_LOCK_DETECT 옵션으로 split lock을 감지하고 경고합니다.

XCHG 기반 스핀락 구현

XCHG는 메모리 피연산자와 사용될 때 암묵적으로 LOCK이 적용됩니다. 이 특성을 이용한 스핀락은 가장 기본적인 커널 동기화 방식입니다.

/* 단순 스핀락 구현 (Test-and-Set) */
/* RDI = lock 주소, lock=0 (해제), lock=1 (획득) */

spin_lock:
    movl    $1, %eax
.Lretry:
    xchgl   %eax, (%rdi)          /* 원자적 교환 (암묵적 LOCK) */
    testl   %eax, %eax             /* 이전 값이 0이었으면 → 락 획득 성공 */
    jnz     .Lspin                  /* 아니면 스핀 */
    ret

.Lspin:
    pause                           /* 스핀 루프 힌트 (전력 절감 + 파이프라인) */
    cmpl    $0, (%rdi)              /* Test: 락이 해제되었는지 읽기만 (LOCK 없이) */
    jne     .Lspin                  /* 아직 잠겨있으면 계속 스핀 */
    jmp     .Lretry                 /* 해제된 것 같으면 Set 재시도 */

spin_unlock:
    movl    $0, (%rdi)              /* 단순 쓰기 (x86 스토어 순서 보장) */
    ret
Test-and-Test-and-Set (TTAS): 위 코드에서 .Lspin 루프가 일반 cmpl(LOCK 없음)로 먼저 확인하는 이유는 LOCK 접두사가 캐시 라인을 Exclusive로 가져오기 때문입니다. 여러 코어가 동시에 XCHG를 시도하면 캐시 라인이 계속 바운싱(bouncing)됩니다. 먼저 Shared 상태에서 읽기만 수행하면 캐시 효율이 크게 개선됩니다.

XADD 기반 참조 카운팅

LOCK XADD는 원자적으로 값을 더하면서 이전 값을 반환합니다. 이는 참조 카운팅에서 이전 카운트 확인이 필요할 때 핵심적으로 사용됩니다.

/* 커널 refcount 감소 (arch/x86/include/asm/refcount.h 기반) */
static inline bool refcount_dec_and_test(refcount_t *r)
{
    int val = -1;  /* 감소할 값 */

    asm volatile(LOCK_PREFIX "xaddl %0, %1"
                 : "+r"(val), "+m"(r->refs.counter)
                 :: "memory");

    /* val = 이전 값, counter는 이미 감소됨 */
    /* 이전 값이 1이었으면 → 감소 후 0 → 마지막 참조 해제 */
    return val == 1;
}

/* 사용 패턴 */
if (refcount_dec_and_test(&obj->refcnt)) {
    /* 참조 카운트 0 → 객체 해제 */
    kfree(obj);
}

SIMD/벡터 명령어

SSE 명령어 (128-bit XMM)

명령어설명동작
MOVAPS/MOVUPS정렬/비정렬 팩 단정도 이동XMM ← 128-bit 메모리/XMM
MOVAPD/MOVUPD정렬/비정렬 팩 배정도 이동XMM ← 128-bit 메모리/XMM
ADDPS/ADDPD팩 단정도/배정도 덧셈각 요소 병렬 덧셈
SUBPS/SUBPD팩 단정도/배정도 뺄셈각 요소 병렬 뺄셈
MULPS/MULPD팩 단정도/배정도 곱셈각 요소 병렬 곱셈
DIVPS/DIVPD팩 단정도/배정도 나눗셈각 요소 병렬 나눗셈
MINPS/MAXPS팩 최솟값/최댓값각 요소 min/max
SQRTPS팩 제곱근각 요소 sqrt
CMPPS팩 비교조건 충족 시 0xFFFFFFFF, 아니면 0
SHUFPS팩 셔플즉시값으로 요소 재배치
UNPCKLPS/UNPCKHPS하위/상위 인터리브두 벡터의 요소 교차 배치
PAND/POR/PXOR팩 정수 비트 논리128-bit 논리 연산
PADDB/W/D/Q팩 정수 덧셈바이트/워드/더블워드/쿼드워드 요소별
PMULLW/PMULLD팩 정수 곱셈 (하위)워드/더블워드 요소별 곱셈
PCMPEQB/PCMPGTB팩 바이트 비교 (같음/큼)요소별 비교 → 마스크
PSHUFD더블워드 셔플즉시값으로 4개 요소 재배치
PSHUFB바이트 셔플 (SSSE3)마스크 벡터로 바이트 재배치

AVX 명령어 (256-bit YMM)

AVX 변경점: VEX 접두사 사용, V 접두사 명령어(VADDPS 등), 3-오퍼랜드 형식(비파괴적), 256-bit 확장. 128-bit VEX 명령어는 YMM 상위 128-bit을 자동 제로화합니다.
명령어설명
VMOVAPS/VMOVUPS256-bit 정렬/비정렬 이동
VADDPS/VADDPD3-오퍼랜드 팩 덧셈: dst ← src1 + src2
VFMADD132PS/213/231FMA (Fused Multiply-Add): a*b+c 단일 명령
VBROADCASTSS스칼라를 모든 요소에 복제
VPERM2F128128-bit 레인 순열
VEXTRACTF128YMM에서 128-bit 레인 추출
VINSERTF128YMM에 128-bit 레인 삽입
VZEROALL/VZEROUPPERYMM 상위 제로화 (SSE↔AVX 전환 시)

AVX-512 명령어 (512-bit ZMM)

AVX-512 특징: EVEX 접두사(4바이트), 512-bit ZMM0-31, 마스크 레지스터 k1-k7(k0=전체), 브로드캐스트 {1toN}, 임베디드 라운딩 {rn-sae}, 32개 레지스터.
명령어설명
VMOVAPS zmm{k1}{z}마스크 적용 512-bit 이동 ({z}=제로 마스킹)
VADDPS zmm, zmm, zmm{k1}마스크 적용 512-bit 덧셈
VADDPS zmm, zmm, m512/m32bcst브로드캐스트 로드 후 덧셈
VPCMPD k1{k2}, zmm, zmm, imm팩 정수 비교 → 마스크 레지스터
VPCOMPRESSD마스크 기반 압축 저장
VPEXPANDD마스크 기반 확장 로드
VPERMD/VPERMQ크로스-레인 순열
VCONFLICTD충돌 감지 (히스토그램/scatter용)

커널 핵심 명령어 심화

SYSCALL/SYSRET 진입 경로

x86_64 Linux에서 시스템 콜은 SYSCALL 명령어로 진입합니다. MSR_LSTAR에 저장된 entry_SYSCALL_64 주소로 점프합니다.

/* arch/x86/entry/entry_64.S — entry_SYSCALL_64 핵심 경로 */
entry_SYSCALL_64:
    swapgs                       /* GS를 커널 per-cpu로 교환 */
    movq    %rsp, PER_CPU_VAR(cpu_tss_rw + TSS_sp2)
    movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp
    /* pt_regs 구조체 저장 */
    pushq   $__USER_DS            /* SS */
    pushq   PER_CPU_VAR(cpu_tss_rw + TSS_sp2) /* RSP */
    pushq   %r11                    /* RFLAGS (SYSCALL이 R11에 저장) */
    pushq   $__USER_CS              /* CS */
    pushq   %rcx                    /* RIP (SYSCALL이 RCX에 저장) */
    pushq   %rax                    /* syscall 번호 */
    /* ... 나머지 레지스터 저장, 시스콜 디스패치 ... */

컨텍스트 전환 시 레지스터 저장/복원

시스템 콜이나 인터럽트로 커널에 진입할 때, 하드웨어와 소프트웨어가 역할을 분담하여 사용자 레지스터를 저장합니다. SYSCALL은 최소한의 레지스터만 하드웨어가 저장하고, 나머지는 커널 진입 코드(entry_SYSCALL_64)가 수동으로 저장합니다.

SYSCALL 진입 시 레지스터 저장 분담 하드웨어 (SYSCALL 명령어) RCX ← RIP (복귀 주소) R11 ← RFLAGS RIP ← MSR_LSTAR CS/SS ← MSR_STAR RSP는 변경되지 않음! (커널이 수동 교체) 소프트웨어 (entry_SYSCALL_64) 1. SWAPGS (GS 교환) 2. RSP 교환 (커널 스택) 3. push SS, RSP (유저) 4. push R11 (RFLAGS) 5. push CS, RCX (RIP) 6. push RAX (syscall 번호) 7. 나머지 범용 레지스터 pt_regs 구조체 R15, R14, R13, R12 RBP, RBX R11, R10, R9, R8 RAX (orig_rax) RCX (= user RIP) RDX, RSI, RDI --- 하드웨어 프레임 --- RIP (= RCX) CS RFLAGS (= R11) RSP (user) SS 비교: 인터럽트/예외 진입 인터럽트 시 하드웨어가 자동 push: SS, RSP, RFLAGS, CS, RIP (+ Error Code, 일부 예외) IRETQ로 복귀 (5개 값 자동 pop) TSS.RSP0에서 커널 스택 자동 로드 SYSCALL보다 느리지만 더 안전

SWAPGS와 per-cpu 데이터 접근 패턴

SWAPGS는 GS 베이스 레지스터와 MSR_KERNEL_GS_BASE를 교환합니다. 커널 진입 시 per-cpu 데이터 접근을 위해 사용되며, 복귀 시 다시 교환합니다. GS 베이스를 통해 현재 CPU의 per-cpu 영역에 빠르게 접근할 수 있습니다.

/* SWAPGS + per-cpu 접근 패턴 */

/* 1. 커널 진입 시: GS를 커널 per-cpu 영역으로 교환 */
/*    SWAPGS → GS.base = 현재 CPU의 per-cpu 오프셋 */

/* 2. per-cpu 변수 접근 (GS 세그먼트 오버라이드) */
/*    movq %gs:offset, %rax  — per-cpu 변수 읽기 */

/* arch/x86/include/asm/percpu.h — 간략화 */
#define this_cpu_read_8(pcp) ({                           \
    u64 val;                                               \
    asm volatile("movq %%gs:%1, %0"                       \
                 : "=r"(val)                               \
                 : "m"(pcp));                               \
    val;                                                     \
})

/* 사용 예: 현재 CPU의 current task 가져오기 */
static inline struct task_struct *get_current(void)
{
    return this_cpu_read_8(current_task);
    /* 컴파일 결과: movq %gs:current_task, %rax */
}

/* 3. 커널 복귀 시: SWAPGS로 GS를 사용자 공간 값으로 복원 */
/*    SWAPGS → GS.base = 사용자 프로세스의 GS (TLS 등) */
SWAPGS 타이밍 주의: SWAPGS는 커널 진입/복귀 시 정확히 한 번만 실행되어야 합니다. 중첩 인터럽트나 예외 상황에서 이미 커널 모드인지 확인하지 않고 SWAPGS를 실행하면 GS가 꼬이게 됩니다. 커널은 CS 세그먼트 값(유저 vs 커널)을 검사하여 SWAPGS 실행 여부를 결정합니다: testb $3, CS(%rsp) — CS의 RPL(Ring Privilege Level) 비트가 3(유저)이면 SWAPGS 필요.

LOCK CMPXCHG — 커널 atomic_cmpxchg

/* arch/x86/include/asm/cmpxchg.h — 간략화 */
static inline u64 __cmpxchg(volatile void *ptr, u64 old, u64 new)
{
    u64 prev;
    asm volatile(LOCK_PREFIX "cmpxchgq %2, %1"
                 : "=a"(prev), "+m"(*(volatile u64 *)ptr)
                 : "r"(new), "0"(old)
                 : "memory");
    return prev;
}

INVLPG — TLB 무효화

/* 단일 페이지 TLB 엔트리 무효화 */
static inline void __invlpg(unsigned long addr)
{
    asm volatile("invlpg (%0)" :: "r"(addr) : "memory");
}

WRMSR/RDMSR — MSR 접근

static inline void wrmsr(u32 msr, u32 low, u32 high)
{
    asm volatile("wrmsr"
                 :: "c"(msr), "a"(low), "d"(high)
                 : "memory");
}

명령어 인코딩

x86_64 명령어는 가변 길이로, 최대 15바이트까지 가능합니다. 레거시 접두사, REX, VEX, EVEX 네 가지 인코딩 체계가 있습니다.

x86_64 Legacy + REX 인코딩 포맷 Legacy Prefix (0-4) REX (0-1 byte) Opcode (1-3 bytes) ModR/M (0-1 byte) SIB (0-1 byte) Displacement (0/1/2/4 bytes) Immediate (0/1/2/4 bytes) 0100 W R X B W=64bit R=reg X=idx B=base VEX / EVEX 접두사 구조 VEX 2-byte: C5h R | vvvv | L | pp VEX 3-byte: C4h R|X|B|mmmmm | W|vvvv|L|pp EVEX 4-byte: 62h R|X|B|R'|mm | W|vvvv|1|pp | z|L'|L|b|V'|aaa L=벡터 길이(0=128,1=256) | pp=오퍼랜드 접두사 | vvvv=추가 소스 레지스터 | aaa=마스크(k0-k7) | z=제로 마스킹 | b=브로드캐스트 mm=오피코드 맵 | W=오퍼랜드 크기 | R/X/B/R'/V'=레지스터 확장 비트

인코딩 실전 예제

실제 명령어가 어떻게 바이트로 인코딩되는지 두 가지 예제를 통해 살펴봅니다.

명령어 인코딩 예제 예제 1: movq $42, %rax → movabs (64-bit 즉시값 이동), 총 10바이트 48h REX.W B8h Opcode+rd 2Ah imm[0] 00h imm[1] 00h imm[2] ... 00h x5 imm[3..7] 0100 1000 W=1 (64-bit) R=0 B=0 B8 + 0 (RAX) MOV reg, imm64 예제 2: movq %rbx, 8(%rdi) → 메모리에 레지스터 저장, 총 4바이트 48h REX.W 89h MOV r/m, r 5Fh ModR/M 08h disp8 (=8) 0101 1111 Mod=01(disp8) Reg=011(RBX) R/M=111(RDI) 인코딩 참고 REX: 0100 WRXB (4-bit 고정 + 4 플래그) B8+rd: 레지스터가 opcode에 내장 RAX=0, RCX=1, RDX=2, RBX=3 RSP=4, RBP=5, RSI=6, RDI=7 R8-R15: REX.B=1 + 하위 3비트 리틀 엔디언: 42=0x2A → 2A 00 00 ...
최적화 힌트: GCC/LLVM은 가능하면 짧은 인코딩을 선택합니다. movq $42, %rax는 실제로 movl $42, %eax(5바이트)로 대체 가능합니다 — 32-bit 쓰기가 자동으로 상위 32-bit를 제로화하므로 결과는 동일하지만 5바이트 절약됩니다. xorl %eax, %eax(2바이트)는 movq $0, %rax(10바이트)보다 효율적인 레지스터 제로화 방법입니다. 또한 xorl은 현대 프로세서에서 제로화 관용어(zeroing idiom)로 인식되어 실행 유닛을 사용하지 않고 레지스터 파일에서 직접 처리됩니다.

최근 아키텍처 확장 (v6.14+)

Intel APX — Advanced Performance Extensions (v6.16+)

커널 6.16에서 Intel APX(Advanced Performance Extensions) 지원이 추가되었습니다. APX는 x86-64의 주요 한계를 해소하는 ISA 확장으로, 다음과 같은 핵심 기능을 제공합니다:

기능설명효과
32개 GPR기존 16개 → 32개 범용 레지스터 (R16~R31)레지스터 스필/리로드 감소, 함수 호출 오버헤드 감소
REX2 접두사새로운 2바이트 REX 접두사 (확장 레지스터 인코딩)R16~R31 접근을 위한 인코딩 지원
NDD (New Data Destination)3-오퍼랜드 형식 (ADD r1, r2, r3)소스 보존 연산 — MOV+연산 패턴 제거
NF (No Flags)플래그 레지스터 미수정 옵션플래그 의존성 제거, 비순차 실행 개선
커널에서의 의미: 32개 레지스터는 커널의 인터럽트 핸들러, 시스템 콜 경로 등에서 레지스터 압박을 줄입니다. NDD/NF는 컴파일러가 더 효율적인 코드를 생성할 수 있게 합니다. APX는 EVEX 인코딩을 확장하므로 기존 바이너리와 완전 호환됩니다.

4096 CPU 코어 지원 (v6.14+)

커널 6.14에서 x86_64의 최대 CPU 코어 수 제한이 2048에서 4096으로 확장되었습니다 (CONFIG_NR_CPUS 최댓값 증가). 이는 AMD EPYC/Intel Xeon의 고코어 서버와 멀티소켓 시스템의 확장성을 지원합니다.

관련 최적화: 4096 코어 지원과 함께 per-CPU 자료구조의 확장성 개선, SLUB sheaves(v6.18) 등의 락 경합 완화 최적화가 병행되고 있습니다.

시스템 레지스터 심화

x86-64의 시스템 레지스터는 CPU 모드 전환, 페이징, 디버깅, 성능 모니터링 등 커널 동작의 핵심을 제어합니다. Control Register(CR0-CR4), Debug Register(DR0-DR7), MSR(Model-Specific Register)의 비트 필드를 정확히 이해해야 커널 초기화 코드와 예외 처리를 분석할 수 있습니다.

x86-64 시스템 레지스터 구조 CR0 — 시스템 제어 bit 0 (PE): Protected Mode Enable bit 1 (MP): Monitor Coprocessor bit 2 (EM): FPU Emulation bit 3 (TS): Task Switched (FPU lazy) bit 16 (WP): Write Protect bit 18 (AM): Alignment Mask bit 29 (NW): Not Write-through bit 30 (CD): Cache Disable bit 31 (PG): Paging Enable CR3 — 페이지 테이블 기준 bit 3 (PWT): Page Write-Through bit 4 (PCD): Page Cache Disable bit 12-51: PML4/PML5 물리 주소 PCID 활성화 시 (CR4.PCIDE=1): bit 0-11: PCID (Process Context ID) CR4 — 기능 활성화 bit 4 (PSE): Page Size Ext (4MB) bit 5 (PAE): Physical Addr Ext bit 7 (PGE): Page Global Enable bit 9 (OSFXSR): SSE 지원 bit 10 (OSXMMEXCPT): SSE 예외 bit 13 (VMXE): VMX Enable bit 14 (SMXE): SMX Enable bit 16 (FSGSBASE): RD/WR FS/GS bit 17 (PCIDE): PCID Enable bit 18 (OSXSAVE): XSAVE Enable bit 20 (SMEP): 커널의 유저코드실행차단 bit 21 (SMAP): 커널의 유저메모리접근차단 bit 23 (CET): Control-flow Enforce bit 12 (LA57): 5-Level Paging EFER (MSR 0xC0000080) bit 0 (SCE): SYSCALL Enable bit 8 (LME): Long Mode Enable bit 10 (LMA): Long Mode Active (R/O) bit 11 (NXE): No-Execute Enable Long Mode 전환: LME=1 → CR0.PG=1 → LMA=1 주요 MSR: 커널 핵심 MSR 레지스터 IA32_STAR (0xC0000081) SYSCALL 세그먼트 셀렉터 IA32_LSTAR (0xC0000082) SYSCALL 진입점 (RIP) IA32_FMASK (0xC0000084) SYSCALL RFLAGS 마스크 IA32_GS_BASE (0xC0000101) GS 세그먼트 베이스 IA32_KERNEL_GS (0xC0000102) SWAPGS용 커널 GS IA32_SPEC_CTRL (0x48) Spectre 완화 제어 IA32_PRED_CMD (0x49) IBPB 트리거 IA32_APIC_BASE (0x1B) LAPIC 기준 주소 IA32_PAT (0x277) Page Attribute Table IA32_PERF_CTL (0x199) P-state 제어 IA32_TSC_DEADLINE (0x6E0) TSC 데드라인 타이머 IA32_PMCx / IA32_PERFEVTSELx 성능 카운터 IA32_MTRR* (0x200+) 메모리 타입 범위 IA32_VMX_* (0x480+) VMX 제어 정보 rdmsr: ECX=MSR번호 → EDX:EAX=값 | wrmsr: ECX=MSR번호, EDX:EAX=값

디버그 레지스터 (DR0-DR7)

레지스터용도커널 사용
DR0-DR3하드웨어 브레이크포인트 주소 (4개)ptrace(PTRACE_POKEUSER) — perf hw_breakpoint
DR6디버그 상태 (어떤 BP가 트리거됐는지)#DB 예외 핸들러에서 읽기
DR7디버그 제어 (활성화, 조건, 길이)bit 0-7: BP 활성화, bit 16-31: 조건/길이
/* DR7 비트 필드 */
/* bit 0,2,4,6 (L0-L3): 로컬 BP 활성화 */
/* bit 1,3,5,7 (G0-G3): 글로벌 BP 활성화 */
/* bit 16-17 (R/W0): DR0 조건 (00=실행, 01=쓰기, 10=I/O, 11=읽기/쓰기) */
/* bit 18-19 (LEN0): DR0 길이 (00=1B, 01=2B, 10=8B, 11=4B) */
/* bit 20-23: DR1 조건/길이, bit 24-27: DR2, bit 28-31: DR3 */

/* 커널 hw_breakpoint 사용 예 */
/* perf_event_create_kernel_counter() → arch_install_hw_breakpoint() */
/* → set_debugreg(addr, 0)  // DR0에 주소 설정 */
/* → set_debugreg(ctrl, 7)  // DR7에 조건 설정 */

성능 모니터링 카운터 (PMC)

MSR이름용도
0x186-0x189IA32_PERFEVTSELx이벤트 선택 (EventSelect, UMask, USR, OS, EN)
0xC1-0xC4IA32_PMCx카운터 값 (48비트)
0x38DIA32_FIXED_CTR_CTRL고정 카운터 제어
0x309-0x30BIA32_FIXED_CTRx고정 카운터 (inst_retired, cpu_clk, ref_clk)
0x38FIA32_PERF_GLOBAL_CTRL전체 카운터 활성화
0x390IA32_PERF_GLOBAL_STATUS오버플로 상태 (NMI 트리거)
/* PERFEVTSELx 비트 필드 */
/* bit 0-7   : EventSelect (이벤트 코드) */
/* bit 8-15  : UMask (이벤트 세분류) */
/* bit 16    : USR (유저 모드 카운트) */
/* bit 17    : OS (커널 모드 카운트) */
/* bit 20    : INT (오버플로 시 인터럽트/NMI) */
/* bit 22    : EN (카운터 활성화) */
/* bit 23    : INV (조건 반전) */
/* bit 24-31 : CMASK (카운트 마스크) */

/* 커널 perf 서브시스템 사용 흐름 */
/* perf_event_open() → x86_pmu_hw_config() */
/* → wrmsrl(MSR_P6_EVNTSEL0, config) → wrmsrl(MSR_P6_PERFCTR0, 0) */
/* 카운터 오버플로 → NMI → intel_pmu_handle_irq() → 샘플 저장 */

가상화 확장 (VMX) 레지스터

구분설명커널 사용
VMCSVirtual Machine Control Structure (4KB)KVM: vmcs_write*()
VMXON/VMXOFFVMX 모드 진입/탈출kvm_cpu_vmxon()
VMLAUNCH/VMRESUME게스트 실행 시작/재개vmx_vcpu_run()
VMPTRLD/VMPTRST현재 VMCS 로드/저장vCPU 스위칭 시
VMREAD/VMWRITEVMCS 필드 읽기/쓰기게스트 레지스터, 제어 필드
EPTExtended Page Table (2단계 주소 변환)게스트 물리→호스트 물리
VPIDVirtual Processor ID (TLB 태깅)VM 전환 시 TLB 보존
ℹ️

MTRR과 PAT: IA32_MTRR* MSR은 물리 메모리 범위별 캐시 정책(UC/WC/WT/WB/WP)을 설정합니다. IA32_PAT는 페이지 테이블 엔트리의 PWT/PCD/PAT 비트 조합으로 8가지 메모리 타입 중 하나를 선택합니다. 커널은 memtype_reserve()로 디바이스 메모리의 MTRR/PAT 정합성을 관리합니다.

SIMD/벡터 확장 심화

x86-64의 SIMD 확장은 SSE → AVX → AVX-512 → AMX로 발전해왔습니다. 커널은 암호화(AES-NI), 체크섬(CRC32c), RAID(XOR/P+Q), 문자열 연산에서 SIMD를 활용합니다. 각 세대의 레지스터 폭, 명령어 형식, 커널 사용 패턴을 이해해야 합니다.

x86 SIMD 확장 세대별 비교 SSE/SSE2-4.2 XMM0-15 (128비트) 4×float / 2×double 16×byte / 8×word SSE4.2: CRC32, PCMPSTR AES-NI: AESENC/AESDEC 접두사: 66/F2/F3 + 0F 2-오퍼랜드 (파괴적) 커널: CRC32c, AES-NI AVX / AVX2 YMM0-15 (256비트) 8×float / 4×double 32×byte / 16×word AVX2: 정수 256비트 FMA: 융합 곱셈-덧셈 VEX 접두사 (C4/C5) 3-오퍼랜드 (비파괴적) 커널: RAID6, SHA AVX-512 ZMM0-31 (512비트) 16×float / 8×double 64×byte / 32×word k0-k7 마스크 레지스터 32개 벡터 레지스터 EVEX 접두사 (4바이트) 마스크+머지/제로링 커널: RAID6, 암호화 AMX (12세대+) TMM0-7 (타일 8KB) 16×1024 행렬 타일 BF16/INT8 연산 TDPBF16PS: 타일 곱 TILELOADD/TILESTORED TILECFG: 타일 구성 XCR0 bit 17-18 AI/ML 워크로드 커널 SIMD 활용 상세 암호화 (crypto/) AES-NI: aesenc/aesenclast — arch/x86/crypto/aesni-intel_asm.S SHA-NI: sha256rnds2 — arch/x86/crypto/sha256_ni_asm.S PCLMULQDQ: GCM 갈루아 곱셈 — arch/x86/crypto/ghash-clmulni-intel_asm.S ChaCha20: AVX2/AVX-512 — arch/x86/crypto/chacha-avx2-x86_64.S RAID (lib/raid6/) SSE: raid6_sse2x2_gen_syndrome() — XOR + GF(2^8) 곱셈 AVX2: raid6_avx2x2_gen_syndrome() — 256비트 병렬 P+Q AVX-512: raid6_avx512x2_gen_syndrome() — 512비트 최대 처리 체크섬 CRC32c: crc32c-intel (SSE4.2 crc32 명령어) IP 체크섬: csum_partial() SSE2 최적화 문자열 연산 memcpy: REP MOVSB (ERMS/FSRM) memset: REP STOSB / AVX non-temporal clear_page: REP STOSQ (64비트 fill) FPU 상태 관리 kernel_fpu_begin() → XSAVEOPT → SIMD 사용 kernel_fpu_end() → XRSTOR → preempt_enable() ⚠ IRQ/softirq에서 사용 불가 (sleep 가능)
세대레지스터레지스터 수인코딩커널 주요 용도
SSEXMM128비트16레거시 (66/F2/F3)AES-NI, CRC32c
AVXYMM256비트16VEX (C4/C5)RAID6, SHA
AVX-512ZMM+k512비트32+8EVEX (62)RAID6, ChaCha20
AMXTMM8KB 타일8VEX유저공간 AI/ML
⚠️

AVX-512 주파수 감소: AVX-512 사용 시 일부 CPU(Skylake 서버 등)에서 코어 주파수가 낮아집니다(License Level 1→2→3). 커널의 RAID6는 이를 고려하여 raid6_avx512x2_gen_syndrome()이 항상 최적은 아닐 수 있으며, lib/raid6/algos.c에서 부팅 시 벤치마크로 최적 구현을 선택합니다.

다음 학습: