rax
x86-64 아키텍처에서 사용되는 64비트 범용 레지스터로, 시스템 콜 번호 저장과 함수 반환값 전달에 주로 사용됩니다.
레지스터 크기 변천
x86 아키텍처가 발전하면서 레지스터 크기가 확장되었고, 하위 호환성을 유지합니다.
64비트 ┌──────────────────────────────────────────────────────┐
│ RAX │
32비트 │ ┌─────────────────────────────┤
│ │ EAX │
16비트 │ │ ┌────────────────┤
│ │ │ AX │
8비트 │ │ ├────────┬───────┤
│ │ │ AH │ AL │
└────────────────────────┴────────────┴────────┴───────┘
63 31 15 8 7 0
| 이름 | 크기 | 도입 시기 |
|---|---|---|
| AL / AH | 8비트 | 8086 (1978) |
| AX | 16비트 | 8086 (1978) |
| EAX | 32비트 | 80386 (1985) |
| RAX | 64비트 | x86-64 / AMD64 (2003) |
x86-64 범용 레지스터 전체
| 레지스터 | 주요 용도 | 시스템 콜 규약 |
|---|---|---|
| RAX | 누산기, 반환값 | 시스템 콜 번호 (입력) / 반환값 (출력) |
| RBX | 베이스 레지스터 | callee-saved |
| RCX | 카운터 | syscall 시 복귀 주소 저장 |
| RDX | 데이터 | 3번째 인자 |
| RSI | 소스 인덱스 | 2번째 인자 |
| RDI | 목적지 인덱스 | 1번째 인자 |
| RBP | 베이스 포인터 | 스택 프레임 기준 |
| RSP | 스택 포인터 | 스택 최상단 |
| R8~R9 | 범용 | 5번째, 6번째 인자 |
| R10 | 범용 | 4번째 인자 |
| R11 | 범용 | syscall 시 RFLAGS 저장 |
| R12~R15 | 범용 | callee-saved |
시스템 콜에서 RAX의 역할
[시스템 콜 호출 시]
RAX = 시스템 콜 번호 ──→ 커널이 sys_call_table[RAX] 조회
[시스템 콜 완료 시]
RAX = 반환값 ──→ 성공 시 결과값, 실패 시 음수 에러 코드
예시: read(fd=3, buf=0x7fff1000, size=100)
호출 전 완료 후
┌──────────────────┐ ┌──────────────────┐
│ RAX = 0 (sys_read)│ │ RAX = 100 (읽은 바이트)│
│ RDI = 3 (fd) │ │ │
│ RSI = 0x7fff1000 │ syscall │ │
│ RDX = 100 (size) │ ────────→ │ 성공 시: 양수 │
│ │ │ 실패 시: -errno │
└──────────────────┘ └──────────────────┘
주요 시스템 콜 번호 (RAX에 들어가는 값)
| RAX 값 | 시스템 콜 | 설명 |
|---|---|---|
| 0 | sys_read | 파일 읽기 |
| 1 | sys_write | 파일 쓰기 |
| 2 | sys_open | 파일 열기 |
| 3 | sys_close | 파일 닫기 |
| 39 | sys_getpid | PID 조회 |
| 57 | sys_fork | 프로세스 복제 |
| 59 | sys_execve | 프로그램 실행 |
| 60 | sys_exit | 프로세스 종료 |
함수 호출에서 RAX의 역할
시스템 콜뿐 아니라 일반 함수 호출에서도 RAX는 반환값을 담습니다.
// C 코드
int add(int a, int b) {
return a + b;
}
int result = add(3, 5);
; 어셈블리 변환
mov edi, 3 ; 첫 번째 인자 → RDI
mov esi, 5 ; 두 번째 인자 → RSI
call add ; add 함수 호출
; RAX = 8 ; 반환값이 RAX에 담김
mov [result], eax ; 결과 저장
Java와의 관계
Java 개발자는 RAX를 직접 다루지 않지만, JVM 내부에서는 시스템 콜 시 RAX를 사용합니다.
System.out.println("hello");
Java: System.out.println("hello")
→ JVM native: write()
→ glibc: write(1, "hello\n", 6)
→ RAX = 1 (sys_write 번호)
RDI = 1 (stdout fd)
RSI = "hello\n" 주소
RDX = 6 (길이)
syscall 실행
← RAX = 6 (쓴 바이트 수) 반환