ARMv8부터 새로 추가된 64비트 명령어 집합 A64(AArch64 상태에서 실행)는 기존 32비트 ARM/Thumb(A32/T32)과 문법이 상당히 다르다. 레지스터 이름, 조건 코드, 주소 지정 방식을 매번 ARM 공식 문서에서 찾아보기는 번거롭기 때문에, 자주 찾아보게 되는 항목만 골라 표로 정리해둔다. 세부 레지스터 구조는 이미 다룬 ARMv8 Registers, AArch64 레지스터 글로, ARM32 명령어 집합은 ARM Instruction Set 글로 넘기고, 이 글에서는 A64 고유의 니모닉 규칙·조건 코드·주소 지정 모드·자주 쓰는 명령어를 표로 정리한다.
니모닉 구성 규칙
A64 니모닉은 <name>{<subtype>} <container> 형태로 구성된다. 연산 이름과 서브타입은 니모닉이, 크기는 레지스터 이름이 나타낸다. 예를 들어 LDRSW는 Load(연산) + Signed Word(서브타입) 조합이다.
| 구분 | 기호 | 의미 |
|---|---|---|
| 정수 컨테이너 | W | 32비트 정수 |
| X | 64비트 정수 | |
| SIMD/FP 컨테이너 | B | 8비트 스칼라 |
| H | 16비트 스칼라 · half-precision | |
| S | 32비트 스칼라 · single-precision | |
| D | 64비트 스칼라 · double-precision | |
| Q | 128비트 스칼라 | |
| Load/Store 서브타입 | B / SB | byte / signed byte |
| H / SH | halfword / signed halfword | |
| W / SW | word / signed word |
레지스터 표기법 요약
범용 레지스터는 0~30번까지 Xn(64비트)/Wn(32비트)으로 부르고, 31번은 문맥에 따라 이름이 바뀐다. 상세 설명은 위 링크 글에서 다루므로 여기서는 표기만 정리한다.
| 의미 | 32비트 | 64비트 |
|---|---|---|
| 범용 레지스터 (0~30) | Wn | Xn |
| Zero 레지스터 (31번, 읽으면 0 / 쓰면 버림) | WZR | XZR |
| 스택 포인터 (31번, base/일부 산술 연산에서만) | WSP | SP |
X30은 아키텍처상 이름이 정해져 있지 않지만 관례적으로 링크 레지스터(LR, 함수 호출 시 복귀 주소)로 쓰인다. PC는 아예 이름이 있는 레지스터로 취급되지 않아 데이터 처리·load 명령의 destination이 될 수 없고, ADR/ADRP·리터럴 로드·분기 명령에서만 암묵적으로 읽힌다.
조건 코드
| 코드 | 의미(정수) | 플래그 조건 |
|---|---|---|
| EQ | 같음 | Z==1 |
| NE | 다름 | Z==0 |
| HS / CS | 부호 없음 크거나 같음 (carry set) | C==1 |
| LO / CC | 부호 없음 작음 (carry clear) | C==0 |
| MI | 음수 | N==1 |
| PL | 양수 또는 0 | N==0 |
| VS | 오버플로우 발생 | V==1 |
| VC | 오버플로우 없음 | V==0 |
| HI | 부호 없음 큼 | C==1 && Z==0 |
| LS | 부호 없음 작거나 같음 | !(C==1 && Z==0) |
| GE | 부호 있음 크거나 같음 | N==V |
| LT | 부호 있음 작음 | N!=V |
| GT | 부호 있음 큼 | Z==0 && N==V |
| LE | 부호 있음 작거나 같음 | !(Z==0 && N==V) |
| AL / NV | 항상 참 | – |
ARM32와 달리 조건은 니모닉에 바로 붙지 않고 .으로 구분한다(예: B.EQ). 조건 플래그를 갱신하는 명령은 대신 S 접미사로 구분한다(예: ADDS).
주소 지정 모드
| 종류 | Immediate Offset | Register Offset | Extended Register Offset |
|---|---|---|---|
| 단순 레지스터(exclusive) | [base{,#0}] | – | – |
| Offset | [base{,#imm}] | [base,Xm{,LSL #imm}] | [base,Wm,(S|U)XTW {#imm}] |
| Pre-indexed | [base,#imm]! | – | – |
| Post-indexed | [base],#imm | – | – |
| PC-relative (literal) | label | – | – |
immediate offset의 비트 폭과 스케일링 방식은 명령어 종류마다 다르다.
| 비트 수 | 부호 | 스케일링 | Writeback | 대상 |
|---|---|---|---|---|
| 0 | – | – | – | exclusive / acquire / release |
| 7 | signed | scaled | 옵션 | register pair (LDP/STP) |
| 9 | signed | unscaled | 옵션 | single register (LDUR/STUR 등) |
| 12 | unsigned | scaled | 없음 | single register (LDR/STR) |
scaled offset은 접근 크기의 배수로 인코딩되므로, 실제 바이트 오프셋 범위는 접근 크기(byte/half/word/double)에 따라 달라진다. Pre/post-indexed 형태는 register offset과 함께 쓸 수 없다.
자주 쓰는 명령어 빠른 참조
| 분류 | 명령어 | 동작 |
|---|---|---|
| 데이터 이동 | MOV Xd, Xn | 레지스터 이동 (ORR Xd,XZR,Xn의 alias) |
MOVZ Xt, #imm{,LSL #pos} | 16비트 즉치값을 지정 위치에 넣고 나머지는 0 | |
MOVK Xt, #imm{,LSL #pos} | 16비트 즉치값을 지정 위치에 넣고 나머지는 유지 | |
MOVN Xt, #imm{,LSL #pos} | 16비트 즉치값을 넣고 비트반전 | |
| 산술 | ADD/SUB Xd, Xn, Xm{,shift} | 덧셈/뺄셈 |
ADDS/SUBS | 연산 후 조건 플래그 갱신 | |
CMP Xn, Xm | 비교 (SUBS XZR,Xn,Xm의 alias) | |
CMN Xn, Xm | 음수 비교 (ADDS XZR,Xn,Xm의 alias) | |
NEG Xd, Xm | 부호 반전 (SUB Xd,XZR,Xm의 alias) | |
| 논리/시프트 | AND / ORR / EOR Xd, Xn, Xm | 비트 AND/OR/XOR |
MVN Xd, Xm | 비트 반전 (ORN Xd,XZR,Xm의 alias) | |
TST Xn, Xm | 비트 테스트 (ANDS XZR,Xn,Xm의 alias) | |
LSL / LSR / ASR / ROR Xd, Xn, #imm|Xm | 논리/산술 시프트, 회전 | |
BIC Xd, Xn, Xm | Xn AND NOT(Xm) | |
| 곱셈/나눗셈 | MUL Xd, Xn, Xm | 곱셈 (MADD Xd,Xn,Xm,XZR의 alias) |
MADD / MSUB Xd, Xn, Xm, Xa | 곱셈-누산 / 곱셈-감산 | |
SDIV / UDIV Xd, Xn, Xm | 부호 있는/없는 나눗셈 (0으로 나누면 결과 0, trap 없음) | |
MSUB로 나머지 계산 | remainder = 피제수 – (몫 × 제수) | |
| Load/Store | LDR/STR Xt, addr | 레지스터 하나 로드/스토어 |
LDP/STP Xt1, Xt2, addr | 레지스터 쌍 로드/스토어 (ARM32의 LDM/STM/PUSH/POP 대체) | |
LDUR/STUR Xt, [base,#simm9] | unscaled 9비트 offset 명시 | |
LDXR/STXR | exclusive load/store (락 구현용) | |
LDAR/STLR | load-acquire / store-release (메모리 배리어 내장) | |
| 제어 흐름 | B label / BL label | 무조건 분기 / 분기+링크(X30에 복귀주소 저장) |
BR Xm / BLR Xm | 레지스터로 분기 / 분기+링크 | |
RET {Xm} | 서브루틴 복귀 (기본 X30) | |
B.cond label | 조건부 분기 (±1MiB) | |
CBZ / CBNZ Xn, label | Xn이 0이면/아니면 분기 | |
TBZ / TBNZ Xn, #bit, label | 특정 비트가 0이면/아니면 분기 (±32KiB) | |
SVC #imm | EL1(시스템)을 대상으로 예외 발생 (시스템 콜) |
AArch32 → AArch64 명령어 대응표
ARM32(A32/T32) NEON·VFP 코드를 A64로 옮길 때 자주 찾게 되는 대응 관계만 추려봤다. 전체 대응표는 ARM 공식 문서 5.7.23절에 있다.
| AArch32 | AArch64 (정수) | AArch64 (부동소수점) |
|---|---|---|
| VADD | ADD | FADD |
| VSUB | SUB | FSUB |
| VMUL | MUL (PMUL 포함) | FMUL |
| VABS | ABS | FABS |
| VNEG | NEG | FNEG |
| VAND / VORR / VEOR | AND / ORR / EOR | – |
| VMVN | MVN (=NOT의 alias) | – |
| VCEQ | CMEQ | FCMEQ |
| VDUP | DUP | – |
| VTST | CMTST | – |
| VTBL / VTBX | TBL / TBX | – |
| VLD1..4 / VST1..4 | LD1..4 / ST1..4 | – |
| VLDM / VLDR | LDP / LDR | – |
| VSTM / VSTR | STP / STR | – |
| VCVT.s32.f32 (round to zero 고정) | – | FCVTZS (그 외 FCVTAS/FCVTMS/FCVTNS/FCVTPS로 반올림 방향 지정 가능) |
주의사항
- 같은 연산이라도 32비트/64비트 형태는 서로 다른 opcode다.
Wn에 쓰면 대응하는Xn의 상위 32비트는 항상 0으로 채워진다(반대로 Wn을 읽을 때는 상위 32비트가 그냥 무시된다). - A64에는 ARM32/Thumb의
IT블록 같은 조건부 실행이 없다. 조건부로 동작하는 것은B.cond계열 분기와CSEL/CSINC/CCMP같은 소수의 conditional data processing 명령뿐이다. LDM/STM/PUSH/POP이 A64에는 없다. 여러 레지스터를 한 번에 옮길 때는LDP/STP로 두 개씩 묶어서 처리한다.- PC는 이름 있는 레지스터가 아니라서 데이터 처리 명령이나 load 명령의 destination으로 쓸 수 없다. PC 상대 주소가 필요하면
ADR/ADRP나 리터럴 로드를 써야 한다. - 나눗셈 명령(
SDIV/UDIV)은 0으로 나누면 예외 없이 결과가 0이 된다. 나머지 연산 명령은 따로 없고MSUB로 직접 계산해야 한다.
마무리
A64는 ARM32와 니모닉 이름은 비슷해 보여도 조건부 실행 축소, LDM/STM 폐지, 32/64비트 opcode 분리처럼 세부 규칙이 다른 부분이 많다. 이 글에 정리한 조건 코드·주소 지정 모드·명령어 빠른 참조 표를 어셈블리 코드를 읽거나 인라인 asm을 작성할 때 1차 참고 자료로 쓰고, 레지스터 구조나 특정 명령어의 정확한 동작이 필요하면 위에서 링크한 상세 글과 ARM 공식 문서를 함께 확인하면 된다.