x86 Assembly Reference
x86/x64 어셈블리 명령어 레퍼런스
x86 Assembly Reference 소개
x86 어셈블리 레퍼런스는 Intel 구문을 사용하는 x86 및 x86-64(AMD64) 명령어 세트 아키텍처의 필수 명령어를 다루는 검색 가능한 빠른 참조입니다. 데이터전송(MOV, LEA, PUSH/POP, XCHG, MOVZX/MOVSX 제로/부호 확장, CMOVcc 조건부 이동), 산술연산(ADD/SUB, INC/DEC, IMUL/MUL 부호있는/없는 곱셈, IDIV/DIV 나눗셈, NEG 부정, ADC/SBB 64비트 캐리 연산), 논리연산(AND/OR/XOR 비트 연산, NOT 보수, SHL/SHR 논리 시프트, SAR/SAL 산술 시프트, ROL/ROR 회전, TEST 플래그 전용 AND), 비교분기(CMP 비교, JMP 무조건 점프, JE/JNE 동등 점프, JG/JL/JGE/JLE 부호있는 비교, JA/JB/JAE/JBE 부호없는 비교, LOOP 카운터 반복), 함수호출(CALL/RET, cdecl과 stdcall 호출 규약, 프롤로그/에필로그 패턴, ENTER/LEAVE), 문자열연산(REP MOVSB/D memcpy용, REP STOSB/D memset용, REPNE SCASB 바이트 검색, REPE CMPSB memcmp용), 레지스터(EAX-EDX 범용, ESI/EDI 인덱스, ESP/EBP 스택, EFLAGS, EIP), 시스템(INT 0x80 Linux 시스템 콜, SYSCALL x64, NOP, CPUID, RDTSC)의 8개 카테고리로 구성되어 있습니다.
x86 어셈블리 이해는 리버스 엔지니어링, 취약점 연구, 악성코드 분석, 컴파일러 개발, 저수준 시스템 프로그래밍에 기본적입니다. 컴파일된 바이너리를 분석할 때 보안 연구자는 디스어셈블리 출력을 읽어 프로그램 흐름 이해, 버퍼 오버플로우 식별, 함수 호출 추적, 셸코드 위치 파악이 필요합니다. 게임 엔진, 암호화 구현, 운영 체제 커널의 성능 중요 코드에는 특정 CPU 기능을 위한 수작업 어셈블리가 포함되는 경우가 많습니다. 호출 규약 섹션(cdecl vs stdcall)은 함수가 인수를 전달하고 스택을 정리하는 방법을 이해하는 데 특히 중요하며, 이는 익스플로잇 작성, 크래시 디버깅, FFI 인터페이스에 필수적입니다.
각 명령어 항목에는 니모닉, 동작에 대한 명확한 설명, 일반적인 사용 패턴을 보여주는 실용적인 예제가 포함됩니다. 예제는 현실적인 시나리오를 사용합니다: 빠른 곱셈을 위한 LEA(LEA EAX, [EAX+EAX*2]로 EAX*3), 효율적인 레지스터 초기화를 위한 XOR EAX,EAX, 거의 모든 컴파일된 함수에 나타나는 프롤로그/에필로그 패턴, sys_write를 위한 Linux/x64 시스템 콜 시퀀스 등이 있습니다. 레지스터 섹션은 각 레지스터의 관습적 역할(EAX는 누산기/반환값, ECX는 카운터, ESP/EBP는 스택 프레임)과 EFLAGS 레지스터 비트(CF, ZF, SF, OF, DF, IF)를 문서화합니다. 모든 콘텐츠는 즉시 필터링 및 다크 모드 지원으로 검색 가능합니다.
주요 기능
- 데이터 전송 명령어: MOV, LEA 유효 주소 계산, PUSH/POP 스택 연산, XCHG, MOVZX/MOVSX 확장, CMOVcc 조건부
- 산술 명령어: ADD/SUB, INC/DEC, IMUL/MUL 부호있는/없는 곱셈, CDQ/XOR EDX 준비를 포함한 IDIV/DIV, NEG, ADC/SBB 캐리 연산
- 논리 및 시프트 명령어: AND/OR/XOR 비트 연산, NOT 보수, SHL/SHR/SAR/SAL 시프트, ROL/ROR 회전, 플래그 전용 TEST
- 비교와 분기: CMP, JMP(직접/간접/테이블), 부호있는(JG/JL) 및 부호없는(JA/JB) 비교 조건 점프, LOOP 명령어
- 함수 호출 규약: CALL/RET, cdecl(호출자 정리) vs stdcall(피호출자 정리), 프롤로그/에필로그 스택 프레임 패턴, ENTER/LEAVE
- 문자열 연산: REP MOVSB/D(memcpy), REP STOSB/D(memset), REPNE SCASB(strchr), REPE CMPSB(memcmp)와 CLD 방향 플래그
- 레지스터 문서화: EAX-EDX 역할, ESI/EDI 문자열 연산, 인수/지역 변수 오프셋을 포함한 ESP/EBP 스택 프레임 레이아웃, EFLAGS 비트, EIP
- 시스템 명령어: INT 0x80(Linux 32비트 시스템콜), SYSCALL(x64), NOP/멀티바이트 NOP 패딩, CPUID CPU 식별, RDTSC 타임스탬프 카운터
자주 묻는 질문
이 레퍼런스에서 어떤 x86 명령어를 다루나요?
8개 카테고리를 다룹니다: 데이터전송(MOV, LEA, PUSH/POP, XCHG, MOVZX/MOVSX, CMOVcc), 산술연산(ADD/SUB, INC/DEC, IMUL/MUL, IDIV/DIV, NEG, ADC/SBB), 논리연산(AND/OR/XOR, NOT, SHL/SHR, SAR/SAL, ROL/ROR, TEST), 비교분기(CMP, JMP, JE/JNE, JG/JL/JGE/JLE 부호있는, JA/JB/JAE/JBE 부호없는, LOOP), 함수호출(CALL/RET, cdecl, stdcall, 프롤로그/에필로그, ENTER/LEAVE), 문자열연산(REP MOVSB/D, REP STOSB/D, REPNE SCASB, REPE CMPSB), 레지스터(EAX-EDX, ESI/EDI, ESP/EBP, EFLAGS, EIP), 시스템(INT 0x80, SYSCALL, NOP, CPUID, RDTSC)입니다.
cdecl과 stdcall 호출 규약의 차이점은 무엇인가요?
cdecl(표준 C 호출 규약)에서는 호출자가 인수를 오른쪽에서 왼쪽으로 스택에 푸시하고, 호출 후 호출자가 스택을 정리합니다(4바이트 인수 2개의 경우 ADD ESP, 8). stdcall(Windows API에서 사용)에서는 피호출자가 RET N으로 스택을 정리합니다(예: RET 8). 반환값은 둘 다 EAX에 들어갑니다. cdecl은 호출자가 인수 개수를 알기 때문에 가변 인수 함수(printf 등)를 지원하고, stdcall은 정리가 피호출자에서 한 번만 이루어져 약간 더 작은 코드를 생성합니다.
LEA 명령어는 MOV와 어떻게 다른가요?
MOV는 레지스터와 메모리 사이에 데이터를 복사합니다. LEA(Load Effective Address)는 x86 주소 지정 모드를 사용하여 주소를 계산하되, 해당 주소의 데이터가 아닌 계산된 주소 자체를 저장합니다. 이로 인해 LEA는 빠른 산술에 유용합니다: LEA EAX, [EBX+ECX*4]는 한 명령어로 EBX + ECX*4를 계산하고, LEA EAX, [EAX+EAX*2]는 EAX에 3을 곱하며, LEA EAX, [EBP-0x10]은 스택 변수 주소를 계산합니다. ADD/MUL과 달리 LEA는 EFLAGS 레지스터를 수정하지 않습니다.
XOR EAX, EAX가 MOV EAX, 0 대신 사용되는 이유는 무엇인가요?
XOR EAX, EAX는 2바이트(31 C0)로 인코딩되고 MOV EAX, 0은 5바이트(B8 00 00 00 00)로 인코딩됩니다. 둘 다 EAX를 0으로 설정하지만 XOR이 더 짧고, 현대 CPU에서 더 빠르며(제로화 관용구로 인식되어 이전 EAX 값을 기다리지 않음), 레지스터의 종속성 체인을 끊습니다. 컴파일러는 보편적으로 레지스터 초기화에 XOR을 선호합니다. 단, XOR은 플래그를 수정(ZF=1 설정, CF/OF 클리어)하고 MOV는 수정하지 않아 드문 플래그 민감 상황에서 차이가 있습니다.
x86에서 함수 프롤로그와 에필로그란 무엇인가요?
프롤로그는 스택 프레임을 설정합니다: PUSH EBP로 호출자의 프레임 포인터 저장, MOV EBP, ESP로 새 프레임 포인터 설정, SUB ESP, N으로 지역 변수 공간 확보. callee-saved 레지스터(EBX, ESI, EDI)를 다음에 푸시합니다. 에필로그는 이를 역순으로 수행합니다: 저장된 레지스터 POP, MOV ESP, EBP로 스택 복원, POP EBP로 프레임 포인터 복원, RET로 반환. ENTER N,0은 프롤로그 3개 명령어를, LEAVE는 에필로그 2개 명령어를 대체하는 축약형입니다.
부호있는 조건 점프와 부호없는 조건 점프는 어떻게 다른가요?
CMP 명령어 후, 부호있는 점프(JG/JL/JGE/JLE)는 부호 플래그(SF), 오버플로우 플래그(OF), 제로 플래그(ZF)를 확인하여 2의 보수 부호있는 정수로 해석된 값을 비교합니다. 부호없는 점프(JA/JB/JAE/JBE)는 캐리 플래그(CF)와 제로 플래그(ZF)를 확인하여 부호없는 정수로 해석된 값을 비교합니다. 예를 들어 0xFFFFFFFF 비교 시: 부호있는 값으로는 -1이므로 JL이 점프하고, 부호없는 값으로는 4294967295이므로 JA가 점프합니다. CMP 후 잘못된 점프 유형 사용은 흔한 버그 원인입니다.
x86에서 Linux 시스템 콜 인터페이스는 어떻게 작동하나요?
32비트 Linux에서는 INT 0x80을 사용합니다: EAX에 시스템 콜 번호(예: sys_write는 4), EBX/ECX/EDX/ESI/EDI/EBP에 인수를 넣고 INT 0x80을 실행합니다. 반환값은 EAX에 나타납니다. 64비트 Linux(x86-64)에서는 SYSCALL을 사용합니다: RAX에 시스템 콜 번호(예: sys_write는 1), RDI/RSI/RDX/R10/R8/R9에 인수를 넣고 SYSCALL을 실행합니다. 64비트 인터페이스는 SYSCALL이 INT 0x80이 사용하는 인터럽트 디스크립터 테이블 조회를 피하므로 더 빠릅니다.
이 레퍼런스 사용 시 데이터가 서버로 전송되나요?
아닙니다. 전체 x86 어셈블리 명령어 레퍼런스는 페이지에 내장되어 완전히 클라이언트 사이드로 렌더링됩니다. 명령어 이름 검색, 카테고리 필터링, 항목 탐색 모두 JavaScript로 브라우저 내에서만 이루어집니다. 어셈블리 코드, 검색 쿼리, 데이터가 어떤 서버로도 전송되지 않습니다.