이전까지 각 모드마다 스택 설정, 메모리 배치가 끝났으므로 main으로 진입 해보자.
C언어에서 main으로 들어가기 위해선 Entry.S 에서 main으로 점프 해야 한다.
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_SYS
MSR cpsr, r1
LDR sp, =USRSYS_STACK_TOP
BL main
이전에 작성했던 Reset Handler 에서 마지막 Branch Main으로 점프 한다.
점프를 할려면 점프 대상 레이블이 같은 파일에 있어야한다. 다른 파일에 있다면 링커가 링킹할 수 있도록 자동으로 접근할 수 있는 전역 심벌로 만들어야한다. 전역 심벌은 어셈블리어에서는 .global, C언어에서는 extern으로 선언한다.
main.c를 만들면서 다음과 같은 tree 구조를 가진다.
.
├── boot
│ ├── Entry.S
│ └── Main.c
├── include
│ ├── ARMv7AR.h
│ └── MemoryMap.h
├── Makefile
└── navilos.ld
main.c는 다음과 같이 만들었다.
#include "stdint.h"
void main(void)
{
uint32_t* dummyAddr = (uint32_t*)(1024*1024*100);
*dummyAddr = sizeof(long);
}
dummyAddr 이라는 포인터 변수를 선언한다음 이 변수위치를 0x6400000 로 설정한다.
이 변수 주소 값에 long의 크기를 저장하게 되므로 (uint32_t*)0x6400000 = 0x00000004 가 된다.
makefile은 다음과 같이 수정한다.
ARCH = armv7-a
MCPU = cortex-a8
CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
OC = arm-none-eabi-objcopy
LINKER_SCRIPT = ./navilos.ld
MAP_FILE = build/navilos.map
ASM_SRCS = $(wildcard boot/*.S)
ASM_OBJS = $(patsubst boot/%.S, build/%.os, $(ASM_SRCS))
C_SRCS = $(wildcard boot/*.c)
C_OBJS = $(patsubst boot/%.c, build/%.o, $(C_SRCS))
INC_DIRS =-I include
navilos = build/navilos.axf
navilos_bin = build/navilos.bin
.PHONY: all clean run debug gdb
all: $(navilos)
clean:
# 책에는 rm -fr 로 되어있는데 오타인거 같아 rm -rf로 수정함 #
@rm -rf build
run: $(navilos)
qemu-system-arm -M realview-pb-a8 -kernel $(navilos)
debug: $(navilos)
qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4
gdb:
gdb-multiarch
$(navilos): $(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT)
$(LD) -n -T $(LINKER_SCRIPT) -o $(navilos) $(ASM_OBJS) $(C_OBJS) -Map=$(MAP_FILE)
$(OC) -O binary $(navilos) $(navilos_bin)
build/%.os: $(ASM_SRCS)
mkdir -p $(shell dirname $@) #mkdir -p build 실행 됨 #
$(CC) -march=$(ARCH) -mcpu=$(MCPU) $(INC_DIRS) -c -g -o $@ $<
#$(AS) 에서 $(CC)로 수정 include "~~.h" 는 c언어 문법이므로#
build/%.o: $(C_SRCS)
mkdir -p $(shell dirname $@)
$(CC) -march=$(ARCH) -mcpu=$(MCPU) $(INC_DIRS) -c -g -o $@ $<
이 Makefile에서 keypoint는 Linker 구문이다. Linker에 심벌에 할당된 메모리주소를 map 파일에 기록하고
Compile 된 object를 LD에 추가 함으로써 main에 점프 할 수 있게 된다.(주황색 강조)
terminal에 make all 을 하게 되면 정상적으로 컴파일을 하게 되고 gdb에서 main 함수에 breakpoint를 걸게 되면
break가 잡히는 거와 앞서 작성했던 코드가 정상적으로 작동하는 걸 볼 수 있다.
(gdb) b main
Breakpoint 1 at 0xe0: file boot/Main.c, line 5.
(gdb) c
Continuing.
Breakpoint 1, main () at boot/Main.c:5
5 uint32_t* dummyAddr = (uint32_t*)(1024*1024*100);
(gdb) si
0x000000e4 5 uint32_t* dummyAddr = (uint32_t*)(1024*1024*100);
(gdb) p dummyAddr
$1 = (uint32_t *) 0x0 <vector_start>
(gdb) si
6 *dummyAddr = sizeof(long);
(gdb) p dummyAddr
$2 = (uint32_t *) 0x6400000
(gdb) n
7 p dummyAddr
$3 = (uint32_t *) 0x6400000
(gdb) p *dummyAddr
$4 = 4
(gdb)
'Firmware > RTOS' 카테고리의 다른 글
임베디드 OS 개발 프로젝트 7(Uart Interrupt) (0) | 2020.02.15 |
---|---|
임베디드 OS 개발 프로젝트 6(UART 송수신) (0) | 2020.01.27 |
임베디드 OS 개발 프로젝트 A-1 (2) | 2020.01.25 |
임베디드 OS 개발 프로젝트 4 (0) | 2020.01.25 |
임베디드 OS 개발 프로젝트 3 (0) | 2020.01.18 |