x86 32/64 레지스터 어드레싱
I. x86 레지스터 어드레싱
x86 레지스터 어드레싱은 16비트 시스템부터 지속적으로 사용되어왔던 개념이다.
16비트 레지스터 어드레싱과 32/64비트 레지스터 어드레싱의 궁극적 차이는 확장성이다. 32/64비트에서는 SIB 바이트로 어드레싱 매커니즘을 확장함으로서 더 자유로운 어드레싱 방법을 제공한다.
16비트 어드레싱에서는 ModR/M 만이 어드레싱을 위해 사용되었으며 표현 가능한 어드레싱 타입은 Mod 11(일반 레지스터 참조)를 제외한 00~10 즉 3 * (2 ^ 3) 이다 (R/M 은 3비트). Intel 에서는 이 제한 이내에 어드레싱을 인덱스/포인터 레지스터, BX+SI/BX+DI 조합으로 한정하였다. (의미상 AX는 Accumulator GPR, BX 는 Base GPR, CX 는 Count GPR, DX 는 Data GPR 로 통용된다)
32/64비트 모드에서는 모든 GPR 및 인덱스/포인터 레지스터(근대 메뉴얼에서는 인덱스/포인터 레지스터도 GPR 로 취급한다)도 레지스터 어드레싱 대상이 될 수 있다. 또한 ModR/M 과 SIB 바이트의 조합으로 동적 레지스터 산술 연산을 실행할 수 있다. (산술 연산은 +, -, * 로 한정되며, -의 경우는 x86 이 음수를 2의 보수로 표현하며, 랩어라운드 가산 회로를 사용하기때문에 +로 표현할 수 있다)
II. 레지스터 산술 연산 조합
- 레지스터 산술 연산 조합은 다음과 같은 형태를 기준으로 다음과 같이 분류할 수 있다:
1. gpr1
2. gpr1 + displacement
3. gpr1 * number
4. gpr1 * number + displacement
5. gpr1 + gpr2
6. gpr1 + gpr2 + displacement
7. gpr1 + gpr2 * number
8. gpr1 + gpr2 * number + displacement
displacement는 8또는 32비트의 직접값이며, number 은 2, 4, 혹은 8이다.
이 경우 주목할점은 8. gpr1 + gpr2 * number + displacement 에서 연산은 gpr1 + displacement + (gpr2 * number)과 같은 식으로 전개된다는것이다. (특별한 가정을 생성하여 ((gpr1 + gpr2) * number) + displacement 같은 식을 만들어내지 않기를 바란다)
- gpr의 승수가 3, 5, 9가 될 수 있는 경우
위에서 정의했듯이 number(승수)의 값은 2, 4, 혹은 8이다. 그러나 어셈블러 처리상 이를 3, 5, 혹은 9로 가상화할 수 있다.
이는 x + ax = x(1 + a) 로 증명된다. 즉 gpr1 * 3 = gpr1 + gpr1 * 2 로 재변환될 수 있다. 이 경우 식에 명시될 수 있는 gpr 의 개수는 1개로 한정된다.
- 항상 무효(invalid)한 승수
항상 유효하는 승수는 2, 4, 및 8. 조건적으로 유효하는 승수는 3, 5, 및 9. 항상 무효하는 승수는 6, 7, 9 < x 인 경우이다. (7이 항상 무효하는 이유는 한 명령상에서 gpr의 2의 보수를 동적으로 예측할 수 있는 방법이 존재하지 않기때문이다)
참조: AMD64/EM64T 에서는 RIP-relative Addressing 이 존재하며 이는 실행중인 명령의 RIP(Instruction Pointer)을 기준으로 상대 주소를 계산합니다. 물론 x86-32 에서도 브랜치 인스트럭션들에서는 EIP를 기준으로 하는 상대 주소 계산이 가능하였으나, RIP-relative Addressing 의 경우는 확장된 기능을 제공합니다 (데이터 접근에서도 RIP가 참조될 수 있습니다) ex: mov qword ptr [rip + 0x1000], rax 단, NASM에서는 이를 rip 대신 rel으로 표현합니다 [rel ~]. RIP Addressing에 명시되는 주소는 Non-canonical address가 될 수 없습니다. 자세한 내용은 AMD64 혹은 Intel 메뉴얼을 참조하십시오.
ps) 예전에 작성했던 내용을 RIP-relative Addressing에 대한 내용을 추가하여 올립니다.


댓글 달기