익셉션은 ARM 프로세서의 핵심 기능 중 하나입니다. 이번 절에서는 ARM 아키텍처에서 적용된 익셉션의 개념을 소개하고, ARM 프로세서에서 익셉션이 어떤 방식으로 동작하는지 설명합니다. 이후 소프트웨어 관점으로 익셉션이 무엇인지 살펴보겠습니다.
익셉션은 ARM 프로세서의 핵심 기능 중 하나입니다. 이번 절에서는 CPU 아키텍처에서 적용된 익셉션의 개념을 소개하고, ARM 프로세서에서 익셉션이 어떤 방식으로 동작하는지 설명합니다.
익셉션(Exception)이란 무엇일까요? 익셉션을 한 문장으로 정의 내리기는 어렵지만 다른 용어와 함께 설명하기는 어렵진 않습니다. 그럼 같이 다음 문장을 읽어볼까요?
❑ 익셉션이 발생하면 ARM의 동작 모드가 변경됩니다.
❑ 익셉션이 발생하면 프로세스는 하던 일을 멈춥니다.
먼저 익셉션은 ARM 동작 모드가 변경되는 원인입니다. 인터럽트 익셉션이 발생하면 ARM 동작 모드는 IRQ 모드로 진입하고, 어보트 익셉션이 발생하면 어보트 익셉션 모드로 진입합니다. 이처럼 익셉션은 ARM 동작 모드와 연관된 동작이므로 ARM의 동작 모드와 함께 배워야 하는 개념입니다.
그리고 소프트웨어 관점으로 익셉션은 "익셉션이 발생하면 프로세스는 하던 일을 멈추게 됩니다"라고 설명드릴 수 있습니다. 어떤 프로세스가 실행하다가 익셉션이 발생하면 ARM 프로세서는 익셉션의 종류 별로 정의된 주소로 프로그램 카운터를 변경하게 되기 때문입니다.
그런데 이 내용이 익셉션을 배우다가 가장 낯설고 어렵다고 느끼는 부분입니다.
예외 상황이 발생하면 특정 미션을 수행하는 예시
“익셉션이 발생하면 익셉션의 종류 별로 지정된 주소로 프로그램 카운터가 변경된다”라는 동작 원리에 대한 이해를 돕기 위해 한 가지 예를 들겠습니다. 먼저 다음 그림을 보겠습니다.

그림 7.4 미션을 수행하는 세부 단계
중요한 미션을 수행하는 첩보 요원이 있는데, 미션을 수행하기 위해 세부 행동 지침의 단계를 나타낸 것입니다. 요원은 "특정 위치에 있는 미션을 확인"하고 "미션의 내용을 해석"한 다음에 "미션을 실행”합니다.
이 과정을 반복해 미션을 수행하다가 "특정 위치에 있는 미션 확인을 할 수 없는 상황"에 직면했습니다. 참 난감한 상황입니다. 가끔은 "특정 위치에 있는 미션을 확인"하는데 성공했는데, "미션의 내용을 해석 못하는 상황"에 처했습니다. 마지막으로 미션의 내용까지 제대로 확인했는데, 도저히 미션의 내용으로 보아 도저히 미션을 실행할 수 없는 상황입니다. 예를 들면, '지구 상에 존재하지 않는 위치(위도, 경도)에 가서 중요한 정보를 가져오라"는 내용입니다.
첩보 요원은 이런 상황에서는 어떻게 대응 해야 할까요?
"특정 위치에 있는 미션 확인을 할 수 없는 상황"에 대해 생각해봅시다. 첩보 요원에게 "특정 위치에 있는 미션을 다시 확인하라"는 지침을 미리 줄 수 있습니다. 이 지침에 따라 요원은 "특정 위치에 있는 미션을 다시 확인"했지만 미션이 없다는 것을 확인했습니다. 더 난감한 상황입니다.
이번에는 "특정 위치에 있는 미션을 확인"하는데 성공했는데, "미션의 내용을 해석 못하는 상황"입니다. 이 상황에서는 아예 "미션의 내용을 다시 해석해보라"는 지침을 내릴 수도 있습니다. 이 지침에 따라 요원은 "미션을 다시 해석"했는데 가끔 제대로 해석을 하지만 해석을 못할 때가 많았습니다. 역시 난감한 상황입니다.
마지막으로, 미션의 내용까지 제대로 확인했는데, 도저히 미션의 내용으로 보아 도저히 "미션을 실행할 수 없는 상황"에 대해 생각해봅시다. 이번에는 요원에게 지시를 지침을 내리기도 어렵습니다. 또한 다시 "미션의 내용을 해석"하라고 하기도 어렵습니다.
차라리, 3가지 경우를 직면했을 때 요원들에게 다음과 같은 지시를 내리는 게 훨씬 효율적이란 생각을 하게 됩니다.
❑ "미션을 재시도" 하지 말고 아예 새로운 위치에 와서 후속 조치를 취해라.
그래서 다음 그림과 같은 지침을 내립니다.

그림 7.5 각 미션을 수행하는 단계에서 실패했을 때 예외 처리 조치
그림 7.5를 보면 미션을 수행하는 단계에서 실패를 하면 ‘특정 위치로 이동해 후속 조치를 받아라’라는 지침을 확인할 수 있습니다.
첩보 요원은 미션을 수행하다가 실패하면 이미 약속된 특정 위치로 바로 이동을 합니다. 그 위치에서 미션을 수행하다가 실패한 원인을 파악하고 후속 조치를 취하는 것입니다. 첩보 요원은 이런 골치 아픈 상황에서 명확한 지침을 받아 미션을 수행하니 더 효율적으로 목표를 이루게 됩니다.
ARM 아키텍처에서 익셉션이 발생하면 지정한 주소로 브랜치를 하는 이유
ARM 프로세서의 익셉션도 유사한 방식으로 설계됐다고 볼 수 있습니다. 다음 그림을 보면서 익셉션의 동작 원리를 설명하겠습니다.

그림 7.6 ARM 프로세서가 명령어를 처리하는 단계에서 실패했을 때 처리 방식
ARM 프로세서는 명령어를 실행하는 과정에서 메모리에서 명령어를 가져오고 명령어를 디코딩한 다음에 명령어를 실행하는 단계를 거칩니다.
그런데 메모리에서 명령어를 가져올 수 없는 상황을 생각해 봅시다. 이 때 다시 메모리에서 명령어를 다시 패치하면 명령어를 가져올 수 있을까요? 확신할 수는 없지만 많은 경우 메모리에서 명령어를 가져올 수 없는 상황을 겪습니다.
이번에는 메모리에서 명령어를 가져왔는데, 명령어를 해석 못하는 상황입니다. 이 경우 다시 명령어를 해석하면 명령어를 제대로 해석할 수 있을까요? 대부분의 경우 해석하지 못한 명령어를 다시 해석해도 결과는 마찬가지입니다.
마지막으로 ARM 프로세서가 명령어를 실행할 수 없는 상황에 대해 생각해봅시다. 예를 들어, ARM 프로세서(내부 MMU)가 접근할 수 없는 "0xDEADBEEF" 주소에 어떤 데이터를 저장하라는 명령어는 실행이 불가능합니다.
ARM이란 CPU를 설계하는 개발자 입장에서 다양한 방식을 생각해 이 상황에 대한 예외 처리를 생각해 볼 수 있습니다. ARM 프로세서가 명령어를 실행하는 3단계 과정에서 실패를 하면 복구(Recovery)를 하도록 시스템을 설계할 수 있습니다. 하지만 시스템의 구조가 굉장히 복잡해져 효율적이지 못합니다.
대신 그림 7.6의 아랫 부분과 같이 명령어를 처리하다가 실패하면 ARM 프로세서가 특정 주소로 프로그램 카운터로 이동하도록 설계할 수 있습니다. 각각 단계에서 명령어를 처리하지 못한 이유를 레지스터에 저장해 그 원인을 프로그래머에게 알려주는 게 더 효율적이라고 생각한 것입니다. 그래서 ARM를 설계하는 개발자는 다음의 원칙에 따라 익셉션을 설계한 것입니다.
❑ 익셉션이 발생하면 익셉션의 종류에 따라 프로그램 카운터를 브랜치하자
ARM 프로세서 뿐만 아니라 다른 대부분의 CPU 아키텍처에서도 이와 같은 상황에서 이미 지정된 주소로 프로그램 카운터를 변경하는 방식으로 처리합니다.
익셉션이 발생하면 지정한 주소로 브랜치를 하는 동작이 낯선 이유
이번에는 소프트웨어 관점으로 익셉션을 생각해봅시다.
익셉션이 발생하면 프로세스 입장에서 하던 일을 멈추게 됩니다. 어떤 프로세스가 실행하다가 익셉션이 발생하면 ARM 프로세서는 익셉션의 종류 별로 정의된 주소로 프로그램 카운터를 변경하게 되는데, 소프트웨어를 실행하는 프로세스 입장에서는 역시나 가장 낯설고 어렵다고 느끼는 부분입니다.
이 부분에 대한 이해를 돕기 위해 한 가지 예를 들어 설명하겠습니다. 먼저 다음 코드를 같이 봅시다.
add_func();
bl add_func;
아주 간단한 코드인데, add_func() 함수를 호출하는 동작입니다. "bl add_func" 명령어를 ARM 코어는 어떻게 해석해 실행할까요? 다음과 같은 단계로 실행합니다.
[1]: ARM 코어는 add_func() 함수의 주소로 프로그램 카운터를 변경한다.
[2]: R14(링크) 레지스터는 add_func() 함수를 호출한 주소를 저장한다.
[3]: add_func() 함수의 앞 부분에서는 자신을 호출한 함수의 정보가 담겨 있는 정보를
스택 공간에 푸시(저장)한다.
위 내용을 읽으면 너무나 당연한 동작이라 왜 이런 걸 설명하면서 지면 수를 채우는 지 납득이 안 갈 겁니다. 하지만 이 동작은 조금 더 생각해보면 굉장히 난해한 동작입니다. 먼저 "bl add_func" 명령어가 실행되면 ARM 코어의 프로그램 카운터가 add_func() 함수의 주소로 왜 바뀌는지 생각해본 적이 있나요? 그리 많지는 않을 텐데, 당연히 이렇게 동작한다고 여길 것입니다. add_func() 함수의 시작 주소로 프로그램 카운터가 바뀌면 ARM 코어는 R14 레지스터의 값을 add_func() 함수를 호출한 주소로 변경합니다.
난해한 동작이지만 평소 소프트웨어 개발자들이 이런 패턴의 명령어를 자주 접하고 분석했기 때문에 낯설게 느끼지 않습니다. 그렇다면 ARM 코어에서 익셉션이 발생하면 어떤 단계로 실행될까요? 다음 단계를 같이 확인해봅시다.
❑ ARM 코어가 익셉션을 감지하면 익셉션의 종류 별로 지정된 주소로 프로그램을 변경한다.
❑ R14_<mode> 레지스터는 익셉션이 발생하기 직전에 실행했던 코드의 주소를 저장한다.
❑ 익셉션이 발생하기 직전에 실행했던 레지스터 세트를 스택에 푸시(저장)한다.
"ARM 코어가 익셉션을 감지하면 익셉션의 종류 별로 지정된 주소로 프로그램을 변경"하는 동작 이외에 함수가 호출되는 동작과 매우 유사합니다. 이 동작은 ARM 코어에서 하드웨어적으로 처리되는 것입니다.
---
"이 포스팅이 유익하다고 생각되시면 공감 혹은 댓글로 응원해주시면 감사하겠습니다.
"혹시 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답변 올려드리겠습니다!"
Thanks,
Guillermo Austin Kim(austindh.kim@gmail.com)
---
Reference: ARM 프로세서 익셉션 소개
익셉션이란?
익셉션의 주요 개념
❑ 익셉션의 타입 소개
익셉션과 같이 배워야 하는 운영체제 지식
Written by <디버깅을 통해 배우는 리눅스 커널의 구조와 원리> 저자
최근 덧글