23.09.04 최초 작성
프로세서에서 지원하는 명령어들의 집합. 프로세서가 다를 경우 다른 Instruction Set을 지원한다.
ABI = User portion of the Instruction Set + Operating System Interface // 작성된 프로그램(이진코드)의 이식성 표준을 결정한다.
ADD X9, X20, X21
Op Code : 수행할 명령어 (ADD)
Operand : 피연산자 (X20, X21)
Place to Store Result : 연산 결과를 저장할 공간(X9)
레지스터는 프로세서 내부에 위치한 저장공간으로 프로세서가 명령어 실행에 사용할 데이터를 저장한다. ARMv8의 경우 레지스터의 크기는 64비트이며 총 32개의 레지스터를 갖고 있다. 레지스터의 크기인 64비트를 묶어 더블 워드(Double Word)
라고 한다.
산술 피연산자
산술 명령어의 피연산자는 레지스터에 위치한 값만을 사용할 수 있다.
메모리 피연산자
모든 값을 레지스터에 저장할 수 없으므로 메모리로부터 인출해 사용해야 한다. 이를 위한 명령어를 데이터 전송 명령어(Data Transfer Instruction)
이라고 한다.
수치(Immediate) 피연산자
메모리로부터 인출하지 않아 해당 피연산자를 활용하면 연산 속도가 빠르다.
표기할 것 | 표기 방법(예시) | 의미 |
---|---|---|
레지스터 | X2 | 2번 레지스터(0~31), 혹은 그 레지스터에 저장된 값 |
메모리 | [X11, #8] | X11레지스터에 저장된 배열의 시작주소에 8을 더한 주소의 값 |
수치 | #6 | 정수 6 |
opcode
: 명령어가 실행할 연산의 종류
Rm
: 두 번째 피연산자 레지스터
shamt
: 자리이동(shift) 양
Rn
: 첫번째 피연산자 레지스터
Rd
: 결과를 저장할 레지스터
R-Type
의 경우 피연산자 레지스터 정보의 크기가 5-bit로 제한되어 를 넘는 값을 지정할 수 없다.
D-Type
은 이 문제를 해결하기 위해 필드의 크기를 조절하여 까지의 값을 지정할 수 있도록 한 형식이다.
LDUR ...
ex) `LDUR X9, [X22, #64]`
address
: #64 ()
Rn
: X22
Rt
: X9
D-Type
의 경우에도 값이 제한되어 R-Type
에서와 같은 문제가 발생할 수 있다.
이를 위해 I-Type
명령어 형식을 만들어 더 큰 상수를 활용한 연산을 가능하게 했다.
ADDI, SUBI ...
더블 워드 내의 모든 비트를 오른쪽 or 왼쪽으로 옮기며 이동 후 빈자리는 0으로 채워넣는다.
LSL, LSR ...
LSL X11, X19, #4
shamt
: #4
Rd
: X11
Rn
: X19
각 비트별 연산을 담당한다.
AND, ORR, NOT, EOR ...
AND X9, X11, X12
ORR X9, X11, X12
NOT X9, X11, X12
...
입력 데이터나 연산 결과를 판단해 실행하기 위한 연산자 (반복문또한 포함)
CBZ, CBNZ ...
if (i = j) f = g + h; else f = g - h;
SUB X9, X22, X23 //i-j 값을 X9에 저장
CBNZ X9, Else //X9 값이 0이 아니면 Else로 분기
ADD X19, X20, X21
B Exit
Else : SUB X19, X20, X21
Exit :
Loop Operation
while (save[i] == k) i += 1;
Loop : LSL X10, X22, #3 // Temp reg X10 = i * 8
ADD X10, X10, X25 // X10 = address of save[i], 주소에 8을 더해줘야 다음 위치 가르킴
LDUR X9, [X10, #0] // Temp reg X9 = save[i]
SUB X11, X9, X24 // X11 = save[i] - k
CBNZ X11, eXIT // go to Exit if save[i] is not k
ADDI X22, X22, #1 // i = i + 1
B Loop // go to Loop
Exit :
연산 결과의 상태를 저장해 나타내는 비트를 flag라고 한다.
Signed Number
B.[X] | 기능 | flag 조건 |
---|---|---|
EQ | Z = 1 | |
NE | Z = 0 | |
LT | N! = V | |
LE | ~(Z = 0 & N = V) | |
GT | Z = 0 & N = V | |
GE | N = V |
Unsigned Number
B.[X] | 기능 | flag 조건 |
---|---|---|
EQ | Z = 1 | |
NE | Z = 0 | |
LT | C = 0 | |
LE | ~(Z = 0 & C = 1) | |
GT | Z = 0 & C = 1 | |
GE | C = 1 |
Procedure(프로시저)
: 이해하기 쉽고 재사용이 가능하도록 프로그램을 구조화 하는 방법(=함수)
Parameter
: 프로시저에 값을 보내고 결과를 받아오는 역할
Procedure 실행 단계
LEG
아키텍처 Procedure 레지스터 할당 관례
X0 ~ X7
: 전달할 인수와 결과값을 가짐X9 ~ X17
: 프로시저 호출 시 피호출 프로그램이 값을 보존해 주지 않음Return Address(복귀 주소)
를 가짐. AAPCS (Procedure Call Standard for ARM Architecture)
: ARM
아키텍처 프로시저 레지스터 할당 관례
X0 ~ X7
: 전달할 인수와 결과값을 가짐X9 ~ X15
: 프로시저 호출 시 피호출 프로그램이 값을 보존해 주지 않음 (지역변수)FP (X29)
: 프레임 포인터
로 레지스터로 이전 스택 포인터 주소 저장LR (X30)
: 호출한 곳으로 돌아가기 위한 Return Address(복귀 주소)
를 가짐. Caller (호출 프로그램) : 프로시저 실행을 시작시키고 필요한 인수를 제공하는 프로그램
Callee (피호출 프로그램) : Caller가 제공하는 인수를 이용해 연산을 실행하고 Caller로 제어를 넘기는 프로그램.
Leaf Procedure : 다른 프로시저를 호출하지 않는 프로시저
BL ProcdureAddress // 지정된 주소로 점프하며(ProcdureAddress) 다음 명령어의 주소를 LR에 저장
BR LR // LR에 저장된 주소로 복귀
long long int leaf_example (long long int g, long long
int h, long long int i, long long int j)
{
long long int f;
f = (g + h) − (i + j);
return f;
}
---
leaf_example: SUBI SP, SP, #24 // adjust stack to make room for 3 items
STUR X10, [SP,#16] // save register X10 for use afterwards
STUR X9, [SP,#8] // save register X9 for use afterwards
STUR X19, [SP,#0] // save register X19 for use afterwards
ADD X9,X0,X1 // register X9 contains g + h
ADD X10,X2,X3 // register X10 contains i + j
SUB X19,X9,X10 // f = X9 − X10, which is (g + h) − (i + j)
ADD X0,X19,XZR // returns f (X0 = X19 + 0)
LDUR X19, [SP,#0] // restore register X19 for caller
LDUR X9, [SP,#8] // restore register X9 for caller
LDUR X10, [SP,#16] // restore register X10 for caller
ADDI SP,SP,#24 // adjust stack to delete 3 items
BR LR // branch back to calling routine
long long int fact (long long int n)
{
if (n < 1) return (1);
else return (n * fact(n − 1));
}
---
fact:
SUBI SP, SP, #16 // adjust stack for 2 items
STUR LR, [SP,#8] // save the return address
STUR X0, [SP,#0] // save the argument n
SUBIS ZXR,X0, #1 // test for n < 1
B.GE L1 // if n >= 1, go to L1
ADDI X1,XZR, #1 // return 1
ADDI SP,SP,#16 // pop 2 items off stack
BR LR // return to caller
L1: SUBI X0,X0,#1 // n >= 1: argument gets (n − 1)
BL fact // call fact with (n − 1)
LDUR X0, [SP,#0] // return from BL: restore argument n
LDUR LR, [SP,#8] // restore the return address
ADDI SP, SP, #16 // adjust stack pointer to pop 2 items
MUL X1,X0,X1 // return n * fact (n − 1)
BR LR // return to the caller
Text : 프로그램 코드 영역
Static Data : 전역 변수 및 상수 저장 공간
Dynamic Data : 힙 공간 (동적으로 할당되는 데이터를 저장)
Stack : 스택 공간
Procedure Frame
: 프로시저의 레지스터 데이터와 지역 변수를 가지고 있는 스택 영역.Frame Pointer (FP)
: 프로시저의 저장된 레지스터와 지역 변수의 시작 위치를 표시하는 값. 일반적으로 X29를 사용한다.SP
: 프로시저의 저장된 레지스터와 지역 변수의 마지막 위치를 표시하는 값. X28를 사용한다.수치의 경우
명령어 형식에 따라 값을 저장하면 큰 상수를 저장할 수 없는 경우가 발생한다. 큰 상수를 저장하기 위한 명령어로 MOVZ
, MOVK
가 있다.
- `MOVZ` : 지정한 비트를 제외하고 0으로 만들며 지정한 위치에 값을 입력한다.
- `MOVK` : 지정한 비트 외의 비트를 조작하지 않으며 지정한 위치에 값을 입력한다.
주소의 경우
명령어 형식에 따라 분기하는 주소를 나타내는 비트의 크기가 제한된다. 이를 해결하기 위해 특정 레지스터의 값(프로그램 카운터 (PC) 등...
)에 주소를 나타내는 비트의 값을 더해 나타낸다.