어셈블리 명령어의 기본 형식
*stp : 두 개의 레지스터를 동시에 스택에 push / 함수 호출 시 현재 상태를 저장
*ldp : 두 개의 레지스터를 동시에 스택에 pop / 함수 끝나면서 현재 상태를 복구
1) 데이터 처리 : ADD, SUB, ORR, LSL, LSR
<Move>
MVN(instruction)은 "Move Not"의 약자로, 대상 레지스터의 비트를 반전시켜서 결과를 저장하는 어셈블리어 명령어입니다. 이 명령어가 필요한 이유는 다음과 같습니다:
1. **비트 반전 및 보수 연산**:
MVN 명령어는 대상 레지스터의 비트를 반전시킵니다. 이는 보수(complement) 연산에 사용될 수 있습니다. 보수 연산은 데이터의 비트를 반전시켜 부호를 바꾸거나, 비트 연산에 사용될 때 유용합니다.
2. **데이터 변환**:
MVN 명령어는 데이터 형식을 변환하는 데 사용될 수 있습니다. 예를 들어, 양의 정수를 보수 형태로 변환하거나, ASCII 문자를 반전시켜 대문자를 소문자로 변환하는 등의 작업에 활용될 수 있습니다.
3. **비트 마스크 작업**:
MVN 명령어는 비트 마스크(mask) 작업에 유용합니다. 특정 비트 패턴을 생성하거나, 비트를 반전시켜 특정 비트를 설정하거나 해제하는 데 사용될 수 있습니다.
4. **제어 흐름 변경**:
MVN 명령어는 제어 흐름을 변경하는 데 사용될 수 있습니다. 특정 조건에 따라 레지스터 값을 반전시켜서 분기 조건을 변경하거나, 논리적으로 반전된 값을 사용하여 제어 흐름을 수정하는 데 활용될 수 있습니다.
따라서 MVN 명령어는 다양한 용도로 활용될 수 있으며, 데이터 조작, 비트 연산, 제어 흐름 변경 등 다양한 작업을 수행하는 데 필요합니다.
<Arithmetic>
Q. signed와 unsigned int에 대해 ADD instruction을 동일하게 사용한다. 그래도 되는걸까?
→ 된다! 그러나 컴파일러가 결과를 판단하기 위한 Flag는 따로 필요하다!
Q. 캐리와 함께 연산을 한다는 게 어떤 의미인가?
→ ADD와 달리 ADC는 carry까지 함께 더해주는데, 4 bit module을 이용해 8bit add 연산을 하는 경우 등에 사용된다.
우씽.. 해석 좀 해보장..
뺐을 때(물론 음수를 더하는 꼴로 표현되겠지만..) carry가 발생하면 빼준 결과 0보다 크거나 같다.
→ RSC에서 아무것도 안해줘
뺐을 때 carry 발생 안하면 빼준 결과가 0보다 작다. (상위 비트에서 가져 와야해!)
→ RSC에서 -1을 해줘(상위 숫자 뺄셈에서 꿔와.....)
조금 이해되는 것 같기도 ㅠㅠ
Q. RSB 같은 경우 왜 사용?
→ Immediate 값이 자리가 정해져 있으므로.. 반대로 계산하고 싶은 경우에 사용한다
<Shift>
LSL 명령어(*2의 제곱수) ↔ LSR
: 왼쪽으로 shifting 하는데, immediate의 경우 32까지만 가능하므로 5bit 할당! shifter만 역할을 하고 프로세서 상에서 ALU는 아무 역할을 하지 않는다! (bypass)
: ADD, SUB 같은 산술 연산 명령어와 함께 사용하기도
ASR 명령어(/2의 제곱)
: LSR과 거의 유사한 방식으로 동작하나, MSB가 1인 경우 오른쪽 비트 시프트를 수행하면서 0으로 바뀌는 비트를 1로 변경(2's complement 바뀌지 않도록 하기 위해)
ROR 명령어
: 지정된 크기만큼 오른쪽으로 bit shift하면서 무시되는 bit가 왼쪽 최상위 비트에 업데이트
<Logical>
EOR - Exclusive OR(XOR)
2) 메모리 연산 : LDR, STR, LDP, STP
<Load, Store>
LDR <Rd>, <addr>
: <addr> 메모리 주소에 있는 데이터를 <Rd>에 저장 (<Rd> = *<addr>)
LDR <Rd>, [Rn, #imm]
: Rn 값에 #imm를 더한 주소에 있는 데이터를 <Rd>에 저장 (<Rd> = *(Rn + #imm))
→ image나 video 같은 큰 데이터를 접근할 때 offset을 이용하여 접근한다!
→ LDR 명령어는 C 언어 기준 포인터 타입으로 선언된 구조체 / 필드에 접근할 때 자주 사용한다 / but 메모리 Abort가 많이 유발되는 명령어 중 하나이다!
STR <Rd>, <addr>
: <Rd> 데이터를<addr> 주소에 저장 (*<addr> = <Rd>)
STR <Rd>, [Rn, #imm]
: <Rd> 데이터를 Rn 값에 #imm를 더한 주소에 저장 (*(Rn + #imm) = <Rd>)
Load(로드)와 Store(스토어) 명령어는 주로 컴퓨터의 메모리와 상호 작용하는 명령어입니다. 이 두 명령어가 접근하는 메모리 영역은 다음과 같습니다:
1. **Data 세그먼트**:
- Load와 Store 명령어는 주로 프로그램에서 사용하는 데이터 세그먼트에 접근합니다. 이 세그먼트에는 초기화된 데이터가 저장되며, 프로그램 실행 중에 데이터에 접근하여 값을 읽고 쓸 수 있습니다. 이 데이터 세그먼트는 주로 전역 변수, 정적 변수 등을 저장하는 데 사용됩니다.
2. **스택(Stack)**:
- 함수 호출과 관련된 데이터는 주로 스택 메모리에 저장됩니다. Load와 Store 명령어는 함수 호출 시 매개변수, 지역 변수, 반환 주소 등을 스택에 로드하거나 스택에서 저장하는 데 사용됩니다.
3. **힙(Heap)**:
- 동적으로 할당된 메모리는 주로 힙 메모리에 저장됩니다. Load와 Store 명령어는 동적으로 할당된 메모리에 접근하여 데이터를 로드하거나 저장하는 데 사용될 수 있습니다.
4. **레지스터(Register)**:
- 프로세서 내부의 레지스터는 메모리가 아니지만, Load와 Store 명령어는 종종 레지스터 간 데이터 이동에 사용됩니다. 예를 들어, 메모리에서 값을 로드하여 레지스터에 저장하거나, 레지스터의 값을 메모리에 저장하는 데 사용됩니다.
따라서 Load와 Store 명령어는 주로 데이터 세그먼트, 스택, 힙 등의 메모리 영역에 접근하여 데이터를 읽고 쓰는 데 사용됩니다.
"data"와 "bss"는 프로그램이 메모리에서 사용하는 데이터의 종류를 나타내는 용어입니다. 이 둘의 주요 차이점은 다음과 같습니다:
1. **Data (데이터)**:
- "Data" 섹션에는 초기화된(global 또는 static) 데이터가 저장됩니다. 이 데이터는 프로그램이 실행될 때 초기값을 갖고 있습니다.
- 예를 들어, 초기값을 명시적으로 할당한 전역 변수나 정적 변수가 여기에 포함됩니다.
- 컴파일 시에 초기화된 데이터의 크기가 결정되므로, 프로그램 실행 전에 이미 값이 할당되어 있습니다.
2. **BSS (Block Started by Symbol)**:
- "BSS" 섹션에는 초기화되지 않은(global 또는 static) 데이터가 저장됩니다. 이 데이터는 프로그램이 실행될 때 초기값을 갖지 않습니다. 대신, 이 영역의 메모리는 0 또는 다른 초기화되지 않은 값으로 채워집니다.
- 예를 들어, 전역 변수나 정적 변수 중 초기값을 명시적으로 주지 않은 경우, 이 변수들은 BSS 섹션에 할당됩니다.
- 컴파일 시에 초기화되지 않은 데이터의 크기만을 저장하며, 프로그램 실행 시에 실제 메모리에 할당됩니다.
따라서 "data"는 초기화된 데이터를 저장하는 데 사용되며, "bss"는 초기화되지 않은 데이터를 저장하는 데 사용됩니다. 프로그래머가 변수를 초기화할 때에는 "data"를 사용하고, 초기화하지 않은 변수를 사용할 때에는 "bss"를 사용합니다.
3) 조건 분기 : B.COND, CBNZ, CBZ, TBNZ, TBZ
Flag를 Control Unit이 Check해서 Processor - Instruction 동작시키도록 함
CBZ 명령어 : Compare and Branch if Zero
CBZ Rt, <label> // Rt의 값이 0이면 label로 브랜치CBNZ 명령어 : Compare and Branch If Non-Zero
CBNZ Rt, <label> // Rt의 값이 0이 아니면 label로 브랜치TBZ : Test bit and Branch if Zero
TBZ Rt, #imm, <label> // Rt 레지스터 값의 #imm 번째 비트가 clear 되었으면(!(Rt&0b#imm)) 지정된 레이블로 분기TBNZ : Test bit and Branch if Non-Zero
TBNZ Rt, #imm, <label> // Rt 레지스터 값의 #imm 번째 비트가 1로 set 되었으면(Rt&0b#imm) 지정된 레이블로 분기CMP 명령어
CMP Rn, Op2 //Rn-Op2의 연산 결과를 CPSR 레지스터의 컨디션 플래그 비트에 업데이트
4) 분기 : B, BL, RET
B 명령어 : label로 지정된 주소로 분기하는데, 서브루틴 콜이나 서브 루틴 리턴이 이뤄지지 않는다.
↔ BL은 R14(리턴 주소)가 업데이트 - 돌아올 곳을 저장해둔다! 서브루틴을 호출하는데, 서브루틴을 호출한 다음에 복귀할 주소가 LR 레지스터에 저장된다!
→ 너무너무 중요한 함수 호출 루틴!! 복귀할 주소를 R14에 업데이트 한 뒤, stack에 푸시, 함수 끝나면 pop해서 PC에 로딩해준다!!
BLR 명령어 : 브랜치 할 주소가 레지스터에 저장되어 있다! (함수 포인터를 통해 함수가 호출되는 경우)
5) 익셉션 처리 : SVC, HVC, SMC, ERET
트랩 : Intentional Exception
- 의도적으로 익셉션을 발생시키는 것
- System call, Breakpoint Trap 등이 해당되는데, 특히 system call은 의도적으로 kernel mode로 진입하는 것.
- Trap을 수행하게 되면 PC의 다음 Instruction을 수행하게 된다.
SVC 명령어 : Supervisor Call ; 유저 applicaiton에서 kernel로 진입
SVC 명령어는 "Supervisor Call"을 수행하는데 사용되는 ARM 아키텍처의 명령어입니다. 이 명령어가 실행되면 다음과 같은 일이 일어납니다:
1. 프로세서는 현재 실행 중인 프로그램의 제어를 예외 처리기(Exception Handler)로 전달합니다. SVC 명령어는 보통 운영 체제(OS)의 서비스나 시스템 호출을 실행하도록 사용되며, 이러한 호출은 특별한 권한(일반적으로 Supervisor 또는 Kernel 권한)이 필요합니다.
2. 예외 처리기는 SVC 명령어의 인자로 지정된 서비스 번호를 확인하여 해당 서비스를 처리합니다. 이를 통해 운영 체제는 프로세스 간 통신(IPC), 메모리 할당과 해제, 파일 입출력 등 다양한 시스템 리소스에 대한 접근을 허용하거나 제어할 수 있습니다.
3. 서비스가 완료되면, 예외 처리기는 처리된 결과를 기반으로 호출자에게 제어를 반환하고, 호출된 프로그램은 실행을 계속합니다.
VBAR(Vector Base Address Register)는 ARM 아키텍처에서 예외 처리기(exception handler)의 기본 주소를 저장하는 데 사용되는 레지스터입니다. 이 레지스터의 값은 예외가 발생할 때 프로세서가 예외 처리기의 위치를 찾는 데 사용됩니다. 따라서 예외 처리기가 SVC 명령어를 처리하는 데 사용되는 경우, VBAR에 저장된 주소를 기반으로 해당 예외 처리기로 제어가 전달됩니다.
이러한 관계로, SVC 명령어가 실행되면 프로세서는 VBAR에 저장된 예외 처리기의 주소로 이동하여 해당 처리기가 SVC 호출을 처리하고, 이후의 동작을 결정합니다. VBAR는 보통 운영 체제가 초기화할 때 설정되며, 예외 처리기들의 베이스 주소를 지정하는 데 사용됩니다.
6) 시스템 레지스터 : MSR, MRS
ARMv7은 ARM 아키텍처의 여러 변형 중 하나로, 다양한 Instruction Set Architecture(ISA)를 지원합니다.
이 중 가장 일반적으로 사용되는 ISA로는 Arm ISA, Thumb2 ISA, Jazelle ISA가 있습니다.
1. **Arm ISA (Arm 명령어 집합 아키텍처)**:
- Arm ISA는 ARM 프로세서의 기본 명령어 집합 아키텍처입니다.
- 이 명령어 집합은 32비트 명령어 세트로 구성되어 있으며, 전통적인 ARM 명령어 형식을 사용합니다.
-Arm ISA는 고성능 애플리케이션에 적합하며, 대부분의 경우 데이터 처리와 관련된 작업을 위해 사용됩니다.
2. **Thumb2 ISA (Thumb 명령어 집합 아키텍처의 확장)**:
- Thumb2 ISA는 ARMv7 아키텍처의 확장된 Thumb 명령어 집합 아키텍처입니다.
- Thumb 명령어는 Arm 명령어에 비해 코드 밀도를 높이고 메모리 사용량을 줄이는 데 중점을 둡니다. 따라서 이는 메모리와 전력 효율성을 향상시키는 데 유용합니다.
- Thumb2 ISA는 16비트 및 32비트 명령어로 구성되어 있으며, 32비트 Thumb 명령어는 Arm 명령어와 유사한 성능을 제공합니다.
3. **Jazelle ISA (Java 가속화 프로세서 확장)**:
- Jazelle ISA는 ARM 프로세서에 내장된 Java 가속화 프로세서의 확장을 나타냅니다.
- 이 ISA는 Java 가상 머신(JVM)에서 직접 Java 바이트코드를 실행하는 데 사용됩니다. 이를 통해 Java 애플리케이션의 성능을 향상시키고 전력 효율성을 높일 수 있습니다.
- Jazelle ISA는 Java 바이트코드를 직접 실행하기 때문에 Java 애플리케이션의 실행 속도가 향상되고, 메모리 사용량이 감소합니다.
이러한 ISA들은 ARMv7 아키텍처에서 다양한 애플리케이션 및 사용 사례에 대한 최적화를 제공합니다. Arm ISA는 고성능 애플리케이션에, Thumb2 ISA는 코드 밀도 및 전력 효율성에 중점을 둔 애플리케이션에, 그리고 Jazelle ISA는 Java 애플리케이션에 각각 최적화되어 있습니다.