이번 시간에는 ARM 프로세서 말하는 프로그래밍 모델에 대해서 설명을 하겠습니다.
ARM 프로세서란 용어를 들으면 이 단어를 듣는 사람들의 입장에 따라 각자 다르게 해석합니다.
일반 대중들은 ARM 프로세서란 용어를 들으면 그냥 컴퓨터나 CPU의 종류라고 생각할 것입니다.
하지만 개발자들의 입장에서는 조금 다릅니다. 만약 여러분이 SoC 시스템을 설계하거나 하드웨어를 디자인하는 개발자나 학자라면 ARM 프로세서를 마이크로프로세서 아키텍처 관점으로 바라볼 겁니다. 즉, ARM 프로세서를 어떤 하드웨어 로직으로 설계했는지 머리 속으로 그려보겠죠.
그런데 저와 같은 SW 개발자는 ARM 프로세서를 보면 ARM 어셈블리 명령어, 레지스터 세트, 코프로세서 그리고 익셉션을 떠올릴 것입니다.
정리하면 ARM 프로세서는 2가지 관점으로 바라볼 수 있습니다.
* 마이크로프로세서 설계 관점
* SW 프로그래머 관점
프로그래머 모델이란 무엇인가?
프로그래머 모델을 설명하기 위해 간단한 예제 코드와 함께 실습을 해보겠습니다.
다음은 라즈베리 파이에서 작성한 간단한 코드입니다.
#include <stdio.h>
int main()
{
printf("Hello ARM Processor! \n", mode);
return 0;
}
위 코드를 작성한 후 다음과 같이 Makefile을 하나 작성한 후 컴파일을 합니다.
hello_arm: main.c
gcc -g -o hello_arm main.c
이제 리눅스에서 제공하는 GDB를 실행해 보겠습니다.
root@raspberrypi:/home/pi# gdb hello_arm
GNU gdb (Raspbian 8.2.1-2) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from raspbian_fork...done.
화면을 보니 GDB가 제대로 실행됐음을 확인할 수 있습니다.
이어서 main 함수에 브레이크 포인트를 걸고 실행해 보겠습니다.
(gdb) break main
Breakpoint 1 at 0x1040c: file main.c, line 5.
(gdb) r
Starting program: /home/pi/hello_arm
Breakpoint 1, main () at main.c:5
5 printf("Hello ARM Processor!\n");
이번에는 disassemble 명령어를 입력해 ARM 어셈블리 명령어를 같이 확인해봅시다.
(gdb) disassemble
Dump of assembler code for function main:
0x00010404 <+0>: push {r11, lr}
0x00010408 <+4>: add r11, sp, #4
=> 0x0001040c <+8>: ldr r0, [pc, #12] ; 0x10420 <main+28>
0x00010410 <+12>: bl 0x102e4 <puts@plt>
0x00010414 <+16>: mov r3, #0
0x00010418 <+20>: mov r0, r3
0x0001041c <+24>: pop {r11, pc}
0x00010420 <+28>: muleq r1, r4, r4
End of assembler dump.
이제 'stepi' 명령어를 입력해 'ldr r0, [pc, #12]' 명령어를 실행해봅시다.
(gdb) stepi
0x00010410 5 printf("Hello ARM Processor!\n");
이 명령어를 실행한 결과 r0 레지스터가 업데이트됐겠네요.
이번에는 레지스터 세트를 확인해보겠습니다.
(gdb) info reg
r0 0x10494 66708
r1 0xbefff6e4 3204445924
r2 0xbefff6ec 3204445932
r3 0x10404 66564
r4 0x0 0
r5 0x10424 66596
r6 0x10314 66324
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0xb6fff000 3070226432
r11 0xbefff594 3204445588
r12 0xbefff610 3204445712
sp 0xbefff590 0xbefff590
lr 0xb6e6b718 -1226393832
pc 0x10410 0x10410 <main+12>
cpsr 0x60000010 1610612752
fpscr 0x0 0
레지스터 r0가 0x10494 데이터를 저장하고 있네요.
이번에는 0x10494 주소의 정체를 확인해볼까요?
(gdb) x/s 0x10494
0x10494: "Hello ARM Processor!"
0x10494 주소에는 "Hello ARM Processor!" 문자열이 있는데, 레지스터 r0은 이 주소를 담고 있습니다.
이 내용을 ARM 프로세서 관점과 더불어 아닌 프로그래밍 관점으로 같이 해석하면 printf() 함수에 전달되는 인자인 "Hello ARM Processor!" 문자열을 r0 레지스터가 담고 있다고 해석할 수 있습니다. 참고로, ARM 프로세서의 함수 호출 규약에 따르면 함수에 전달되는 인자는 r0~r3 레지스터에 전달됩니다.
이번에는 'stepi 500' 명령어를 실행해 500번 ARM 어셈블리 명령어를 실행하겠습니다.
(gdb) stepi 500
0xb6fd7d5c 541 dl-lookup.c: No such file or directory.
현재 어떤 상태인지 콜 스택을 확인해 보겠습니다.
(gdb) bt
#0 0xb6fd7d5c in do_lookup_x (undef_name=0x7c9c7b11 <error: Cannot access memory at address 0x7c9c7b11>,
undef_name@entry=0x1023b "puts", new_hash=3069940312, new_hash@entry=2090629905, old_hash=0x1023b, old_hash@entry=0xbefff4f4,
ref=0x3e4e3d8, result=<optimized out>, result@entry=0xbefff4fc, scope=0xb6fffad8, i=<optimized out>, version=<optimized out>,
version@entry=0xbefff594, flags=1, flags@entry=-1224763368, skip=skip@entry=0x0, type_class=1, type_class@entry=-1224877484,
undef_map=undef_map@entry=0xb6fff978) at dl-lookup.c:541
#1 0xb6fd88b4 in _dl_lookup_symbol_x (undef_name=0x1023b "puts", undef_map=undef_map@entry=0xb6fff978, ref=0xbefff554,
ref@entry=0xbefff54c, symbol_scope=0x1, version=0xb6ff9818, type_class=type_class@entry=1, flags=1, skip_map=skip_map@entry=0x0)
at dl-lookup.c:814
#2 0xb6fdda54 in _dl_fixup (l=0xb6fff978, reloc_arg=<optimized out>) at dl-runtime.c:112
#3 0xb6fe3b44 in _dl_runtime_resolve () at ../sysdeps/arm/dl-trampoline.S:57
#4 0x00010414 in main () at main.c:5
라즈베리 파이는 ARM 코어의 갯수가 4개이니, 위에서 본 레지스터 세트와 콜 스택이 각각 코어 별로 4개가 있습니다.
이와 같이 SW 프로그램 관점에서 보이는 레지스터 세트와 콜 스택과 같은 내용을 프로그램 모델이라고 부릅니다.
'시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리' 카테고리의 다른 글
[ARM] ARM technical referenece document (0) | 2023.06.09 |
---|---|
[ARM] ARMv8(Aarch64) 아키텍처 기반 프로젝트가 대세인가? (0) | 2023.06.09 |
[ARM][ARMv7 아키텍처] 성능: 사이클(cycle) 정보 얻어오기 - [1] (0) | 2023.06.09 |
[ARM] ARM사의 라이센스 방식: 소프트 매크로/하드 매크로 (0) | 2023.06.09 |
[ARM] const static 키워드로 변수를 선언: 코드 크기 최적화 (0) | 2023.06.09 |