Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>
ARM 리눅스 Makefile 분석

4.3. ARM 리눅스 Makefile 분석

2장에서 분석한 것과 같이 ARM 리눅스의 Makefile도 i386의 것과 비슷하다. 그러나 부팅하는 과정 등의 일부가 PC가 아닌 다른 시스템이기 때문에 많이 다르다. 그럼에도 불구하고 대부분 비슷한 방법으로 만들어지고 실행된다.

arch/arm 이하의 것만 제외한다면 나머지는 i386의 것과 동일하므로 2장을 참조하고 나머지 ARM 리눅스에 관련된 부분만 다룬다.

4.3.1. $(TOPDIR)/arch/arm/Makefile

Assabet 보드용 기본 설정에 해당하는 .Config file의 내용은 아래와 같다. 이를 참조해 아래 Makefile 분석을 좇아가기 바란다. 세팅된 것만 추리고 나머지는 버렸다.

#
# Automatically generated by make menuconfig: don't edit
#
CONFIG_ARM=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y

#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y

#
# Loadable module support
#
CONFIG_MODULES=y

#
# System Type
#
CONFIG_ARCH_SA1100=y

#
# SA11x0 Implementations
#
CONFIG_SA1100_ASSABET=y
CONFIG_SA1100_USB=m
CONFIG_SA1100_USB_NETLINK=m

CONFIG_CPU_32=y
CONFIG_CPU_32v4=y
CONFIG_CPU_SA1100=y
CONFIG_DISCONTIGMEM=y

#
# General setup
#
# CONFIG_PCI is not set
CONFIG_ISA=y
CONFIG_CPU_FREQ=y
CONFIG_HOTPLUG=y

#
# PCMCIA/CardBus support
#
CONFIG_PCMCIA=y
CONFIG_PCMCIA_PROBE=y
CONFIG_PCMCIA_SA1100=y
CONFIG_NET=y
CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
CONFIG_FPE_NWFPE=y
CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
CONFIG_PM=y
CONFIG_CMDLINE="root=1f04 mem=32M"
CONFIG_LEDS=y
CONFIG_LEDS_TIMER=y
CONFIG_LEDS_CPU=y
CONFIG_ALIGNMENT_TRAP=y

#
# Memory Technology Devices (MTD)
#
CONFIG_MTD=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y

#
# RAM/ROM/Flash chip drivers
#
CONFIG_MTD_CFI=y
CONFIG_MTD_GEN_PROBE=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_NOSWAP=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CFI_B4=y
CONFIG_MTD_CFI_I2=y
CONFIG_MTD_CFI_INTELEXT=y

#
# Mapping drivers for chip access
#
CONFIG_MTD_SA1100=y

#
# Block devices
#
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y

#
# Networking options
#
CONFIG_UNIX=y
CONFIG_INET=y

#
# Network device support
#
CONFIG_NETDEVICES=y

#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y

#
# PCMCIA network device support
#
CONFIG_NET_PCMCIA=y
CONFIG_PCMCIA_PCNET=y

#
# IrDA (infrared) support
#
CONFIG_IRDA=m
CONFIG_IRLAN=m

#
# Infrared-port device drivers
#
CONFIG_SA1100_FIR=m

#
# ATA/IDE/MFM/RLL support
#
CONFIG_IDE=y

#
# IDE, ATA and ATAPI Block devices
#
CONFIG_BLK_DEV_IDE=y
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_BLK_DEV_IDECS=y

#
# Character devices
#
CONFIG_VT=y

#
# Serial drivers
#
CONFIG_SERIAL_SA1100=y
CONFIG_SERIAL_SA1100_CONSOLE=y
CONFIG_SA1100_DEFAULT_BAUDRATE=38400
CONFIG_SERIAL_8250=m
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=32

#
# L3 serial bus support
#
CONFIG_L3=y
CONFIG_L3_ALGOBIT=y
CONFIG_L3_BIT_SA1100_GPIO=y
CONFIG_BIT_SA1100_GPIO=y

#
# Watchdog Cards
#
CONFIG_SA1100_RTC=y

#
# PCMCIA character devices
#
CONFIG_PCMCIA_SERIAL_CS=m

#
# File systems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_TMPFS=y
CONFIG_PROC_FS=y
CONFIG_DEVPTS_FS=y
CONFIG_EXT2_FS=y

#
# Network File Systems
#
CONFIG_NFS_FS=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y

#
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
CONFIG_MSDOS_PARTITION=y
CONFIG_NLS=y

#
# Native Language Support
#
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y

#
# Console drivers
#
CONFIG_PC_KEYMAP=y

#
# Frame-buffer support
#
CONFIG_FB=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_FB_SA1100=y
CONFIG_FBCON_CFB2=y
CONFIG_FBCON_CFB4=y
CONFIG_FBCON_CFB8=y
CONFIG_FBCON_CFB16=y
CONFIG_FBCON_FONTWIDTH8_ONLY=y
CONFIG_FBCON_FONTS=y
CONFIG_FONT_8x8=y

#
# Sound
#
CONFIG_SOUND=y
CONFIG_SOUND_SA1100=y
CONFIG_SOUND_UDA1341=y
CONFIG_SOUND_ASSABET_UDA1341=y

#
# Multimedia Capabilities Port drivers
#
CONFIG_MCP=y
CONFIG_MCP_SA1100=y
CONFIG_MCP_UCB1200=y
CONFIG_MCP_UCB1200_AUDIO=m
CONFIG_MCP_UCB1200_TS=y

#
# Kernel hacking
#
CONFIG_DEBUG_USER=y

#
# arch/arm/Makefile
#
# This file is subject to the terms and conditions of the GNU General Public
# License.  See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (C) 1995-2001 by Russell King

LINKFLAGS	:=-p -X -T arch/arm/vmlinux.lds
GZFLAGS		:=-9
CFLAGS		+=-fno-common -pipe

ifneq ($(CONFIG_NO_FRAME_POINTER),y)
CFLAGS		:=$(CFLAGS:-fomit-frame-pointer=)
endif

ifeq ($(CONFIG_DEBUG_INFO),y)
CFLAGS		+=-g
endif

# Select CPU dependent flags.  Note that order of declaration is important;
# the options further down the list override previous items.
#
# Note!  For APCS-26 YOU MUST HAVE AN APCS-26 LIBGCC.A
#
apcs-y				:=-mapcs-32
apcs-$(CONFIG_CPU_26)		:=-mapcs-26 -mcpu=arm3 -Os

(1)
# This selects which instruction set is used.
arch-y				:=
arch-$(CONFIG_CPU_32v3)		:=-march=armv3
arch-$(CONFIG_CPU_32v4)		:=-march=armv4
arch-$(CONFIG_CPU_32v5)		:=-march=armv5

(2)
# This selects how we optimise for the processor.
tune-y				:=
tune-$(CONFIG_CPU_ARM610)	:=-mtune=arm610
tune-$(CONFIG_CPU_ARM710)	:=-mtune=arm710
tune-$(CONFIG_CPU_ARM720T)	:=-mtune=arm7tdmi
tune-$(CONFIG_CPU_ARM920T)	:=-mtune=arm9tdmi
tune-$(CONFIG_CPU_ARM922T)	:=-mtune=arm9tdmi
tune-$(CONFIG_CPU_ARM926T)	:=-mtune=arm9tdmi
tune-$(CONFIG_CPU_SA110)	:=-mtune=strongarm110
tune-$(CONFIG_CPU_SA1100)	:=-mtune=strongarm1100

CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
AFLAGS		+=$(apcs-y) $(arch-y) -mno-fpu -msoft-float

ifeq ($(CONFIG_CPU_26),y)
PROCESSOR	 = armo
  ifeq ($(CONFIG_ROM_KERNEL),y)
    DATAADDR	 = 0x02080000
    TEXTADDR	 = 0x03800000
    LDSCRIPT	 = arch/arm/vmlinux-armo-rom.lds.in
  else
    TEXTADDR	 = 0x02080000
    LDSCRIPT	 = arch/arm/vmlinux-armo.lds.in
  endif
endif

(3)
ifeq ($(CONFIG_CPU_32),y)
PROCESSOR	 = armv
TEXTADDR	 = 0xC0008000
LDSCRIPT	 = arch/arm/vmlinux-armv.lds.in
endif

ifeq ($(CONFIG_ARCH_ARCA5K),y)
MACHINE		 = arc
endif

ifeq ($(CONFIG_ARCH_RPC),y)
MACHINE		 = rpc
endif

ifeq ($(CONFIG_ARCH_EBSA110),y)
MACHINE		 = ebsa110
endif

ifeq ($(CONFIG_ARCH_CLPS7500),y)
MACHINE		 = clps7500
INCDIR		 = cl7500
endif

ifeq ($(CONFIG_FOOTBRIDGE),y)
MACHINE		 = footbridge
INCDIR		 = ebsa285
endif

ifeq ($(CONFIG_ARCH_CO285),y)
TEXTADDR	 = 0x60008000
MACHINE		 = footbridge
INCDIR		 = ebsa285
endif

ifeq ($(CONFIG_ARCH_FTVPCI),y)
MACHINE		 = ftvpci
INCDIR		 = nexuspci
endif

ifeq ($(CONFIG_ARCH_TBOX),y)
MACHINE		 = tbox
endif

ifeq ($(CONFIG_ARCH_SHARK),y)
MACHINE		 = shark
endif

(4)
ifeq ($(CONFIG_ARCH_SA1100),y)
ifeq ($(CONFIG_SA1111),y)
# SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory
TEXTADDR	 = 0xc0208000
endif
MACHINE		 = sa1100
endif

ifeq ($(CONFIG_ARCH_L7200),y)
MACHINE		 = l7200
endif

ifeq ($(CONFIG_ARCH_INTEGRATOR),y)
MACHINE		 = integrator
endif

ifeq ($(CONFIG_ARCH_CAMELOT),y)
MACHINE          = epxa10db
endif

ifeq ($(CONFIG_ARCH_CLPS711X),y)
TEXTADDR	 = 0xc0028000
MACHINE		 = clps711x
endif

ifeq ($(CONFIG_ARCH_FORTUNET),y)
TEXTADDR	 = 0xc0008000
endif

ifeq ($(CONFIG_ARCH_ANAKIN),y)
MACHINE		 = anakin
endif

export	MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT

# Only set INCDIR if its not already defined above
# Grr, ?= doesn't work as all the other assignment operators do.  Make bug?
ifeq ($(origin INCDIR), undefined)
INCDIR		:= $(MACHINE)
endif

ifeq ($(origin DATAADDR), undefined)
DATAADDR	:= .
endif

(5)
# If we have a machine-specific directory, then include it in the build.
MACHDIR		:= arch/arm/mach-$(MACHINE)
ifeq ($(MACHDIR),$(wildcard $(MACHDIR)))
SUBDIRS		+= $(MACHDIR)
CORE_FILES	:= $(MACHDIR)/$(MACHINE).o $(CORE_FILES)
endif

(6)
HEAD		:= arch/arm/kernel/head-$(PROCESSOR).o \
		   arch/arm/kernel/init_task.o
SUBDIRS		+= arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe
CORE_FILES	:= arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
LIBS		:= arch/arm/lib/lib.a $(LIBS)

ifeq ($(CONFIG_FPE_NWFPE),y)
LIBS		:= arch/arm/nwfpe/math-emu.o $(LIBS)
endif

# Only include fastfpe if it is part of the kernel tree.
FASTFPE		:= arch/arm/fastfpe
ifeq ($(FASTFPE),$(wildcard $(FASTFPE)))
SUBDIRS		+= $(FASTFPE)
ifeq ($(CONFIG_FPE_FASTFPE),y)
LIBS		:= arch/arm/fastfpe/fast-math-emu.o $(LIBS)
endif
endif

ifeq ($(findstring y,$(CONFIG_ARCH_CLPS7500) $(CONFIG_ARCH_L7200)),y)
SUBDIRS		+= drivers/acorn/char
DRIVERS		+= drivers/acorn/char/acorn-char.o
endif

MAKEBOOT	 = $(MAKE) -C arch/$(ARCH)/boot
MAKETOOLS	 = $(MAKE) -C arch/$(ARCH)/tools

# The following is a hack to get 'constants.h' up
# to date before starting compilation

$(patsubst %,_dir_%, $(SUBDIRS)): maketools
$(patsubst %,_modsubdir_%,$(MOD_DIRS)): maketools

symlinks: archsymlinks

archsymlinks:
	$(RM) include/asm-arm/arch include/asm-arm/proc
	(cd include/asm-arm; ln -sf arch-$(INCDIR) arch; ln -sf proc-$(PROCESSOR) proc)

vmlinux: arch/arm/vmlinux.lds

(7)
arch/arm/vmlinux.lds: $(LDSCRIPT) dummy
	@sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@

arch/arm/kernel arch/arm/mm arch/arm/lib: dummy
	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)

bzImage zImage zinstall Image bootpImage install: vmlinux
	@$(MAKEBOOT) $@

CLEAN_FILES	+= \
	arch/arm/vmlinux.lds

MRPROPER_FILES	+= \
	include/asm-arm/arch \
	include/asm-arm/proc \
	include/asm-arm/constants.h* \
	include/asm-arm/mach-types.h

# We use MRPROPER_FILES and CLEAN_FILES now
archmrproper:
	@/bin/true

archclean:
	@$(MAKEBOOT) clean

archdep: scripts/mkdep archsymlinks
	@$(MAKETOOLS) dep
	@$(MAKEBOOT) dep

# we need version.h
maketools: checkbin include/linux/version.h
	@$(MAKETOOLS) all

# Ensure this is ld "2.9.4" or later
NEW_LINKER	:= $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?)

ifneq ($(NEW_LINKER),0)
checkbin:
	@echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.'
	@echo '*** Please upgrade your binutils to 2.9.5.'
	@false
else
checkbin:
	@true
endif

# My testing targets (that short circuit a few dependencies)
zImg:;	@$(MAKEBOOT) zImage
Img:;	@$(MAKEBOOT) Image
i:;	@$(MAKEBOOT) install
zi:;	@$(MAKEBOOT) zinstall
bp:;	@$(MAKEBOOT) bootpImage

(8)
#
# Configuration targets.  Use these to select a
# configuration for your architecture
%_config:
	@( \
	CFG=$(@:_config=); \
	if [ -f arch/arm/def-configs/$$CFG ]; then \
	  [ -f .config ] && mv -f .config .config.old; \
	  cp arch/arm/def-configs/$$CFG .config; \
	  echo "*** Default configuration for $$CFG installed"; \
	  echo "*** Next, you may run 'make oldconfig'"; \
	else \
	  echo "$$CFG does not exist"; \
	fi; \
	)

(1)
ARM 프로세서의 종류에 따라 컴파일러에게 사용할 아키텍쳐를 알려준다. SA1110은 armv4를 사용한다.

ARM 아키텍쳐에서 아키텍쳐에(v6포함) 대한 자세한 정보를 얻기 바란다. 간단히 정리하면 다음과 같다.

  • v3

    32 비트 어드레싱 시작, 아래와 같은 종류가 있다.

    • T

      Thumb 코드 실행

    • M

      long multiply 지원, 이것은 v4에서 기본이 됐다.

  • v4

    halfword load, store 지원

  • v5

    개선된 ARM, Thumb 동작. CLZ 명령 지원. 종류는

    • E

      개선된 DSP 명령

    • J

      JAVA 지원

(2)
선정된 아키텍쳐에 속하는 변종들 중에 정확한 것을 지정한다.
(3)
SA1110의 경우 필요한 변수 들을 설정한다. .text를 0xC0008000에 맞추고 링크 스크립트를 그에 맞는 것을 사용하도록 한다.
(4)
MACHINE은 arch/arm 디렉토리 밑에 있는 많은 하위 디렉토리 중에 현재 선택된 시스템이 어떤 것인지에 따라 변경되는 내용을 담은 것을 선택하도록 한다.
(5)
MACHINE에서 선택된 것을 사용해 필요한 디렉토리를 선택한다.
(6)
ARM 프로세서의 종류에 따라 처음 실행되는 코드가 달라져야한다. 그 것을 선택한다.
(7)
링크에 사용될 스크립트인 vmlinux.lds를 만들기 위해 vmlinux.*.lds.in에서 필요한 몇 가지 변수를 조정해 vmlinux.lds를 만든다.
(8)
ARM 커널을 만들 때 'make assabet_config'를 실행한 것을 기억하는가? 보드에 따라 기본 설정을 세팅할 때 사용하는 명령에 따라 알맞은 설정을 복사하도록 한다.

arch/arm/def-config에 가능한 모든 정보가 들어있다.

4.3.2. $(TOPDIR)/arch/arm/vmlinux.lds

ARM 프로세서 커널의 링크에 사용되는 링크 스크립트 vmlinux.lds를 분석해보자. 4.3.1절에서 본 것 처럼 vmlinux.lds는 설정된 아키텍쳐에따라 만들어진 것이다.

/* ld script to make ARM Linux kernel
 * taken from the i386 version by Russell King
 * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
 */
(1)
OUTPUT_ARCH(arm)
(2)
ENTRY(stext)
SECTIONS
{
(3)
	. = 0xC0008000;
(4)
	.init : {			/* Init code and data		*/
		_stext = .;
		__init_begin = .;
			*(.text.init)

		__proc_info_begin = .;
			*(.proc.info)
		__proc_info_end = .;
		__arch_info_begin = .;
			*(.arch.info)
		__arch_info_end = .;
		__tagtable_begin = .;
			*(.taglist)
		__tagtable_end = .;
			*(.data.init)
		. = ALIGN(16);
		__setup_start = .;
			*(.setup.init)
		__setup_end = .;
		__initcall_start = .;
			*(.initcall.init)
		__initcall_end = .;
		. = ALIGN(4096);
		__init_end = .;
	}

(5)
	/DISCARD/ : {			/* Exit code and data		*/
		*(.text.exit)
		*(.data.exit)
		*(.exitcall.exit)
	}

(6)
	.text : {			/* Real text segment		*/
		_text = .;		/* Text and read-only data	*/
			*(.text)
			*(.fixup)
			*(.gnu.warning)
			*(.rodata)
			*(.rodata.*)
			*(.glue_7)
			*(.glue_7t)
		*(.got)			/* Global offset table		*/

		_etext = .;		/* End of text section		*/
	}

	.kstrtab : { *(.kstrtab) }

	. = ALIGN(16);
	__ex_table : {			/* Exception table		*/
		__start___ex_table = .;
			*(__ex_table)
		__stop___ex_table = .;
	}

	__ksymtab : {			/* Kernel symbol table		*/
		__start___ksymtab = .;
			*(__ksymtab)
		__stop___ksymtab = .;
	}

(7)
	. = ALIGN(8192);

	.data : {
		/*
		 * first, the init task union, aligned
		 * to an 8192 byte boundary.
		 */
		*(.init.task)

		/*
		 * then the cacheline aligned data
		 */
		. = ALIGN(32);
		*(.data.cacheline_aligned)

		/*
		 * and the usual data section
		 */
		*(.data)
		CONSTRUCTORS

		_edata = .;
	}

	.bss : {
		__bss_start = .;	/* BSS				*/
		*(.bss)
		*(COMMON)
		_end = . ;
	}
					/* Stabs debugging sections.	*/
	.stab 0 : { *(.stab) }
	.stabstr 0 : { *(.stabstr) }
	.stab.excl 0 : { *(.stab.excl) }
	.stab.exclstr 0 : { *(.stab.exclstr) }
	.stab.index 0 : { *(.stab.index) }
	.stab.indexstr 0 : { *(.stab.indexstr) }
	.comment 0 : { *(.comment) }
}

(1)
최종 출력의 아키텍쳐를 지정한다.
(2)
stext는 arch/arm/kernel/head-armv.S에 정의되어 있다.
(3)
그림 4-8을 참조하면 0xc0008000은 DRAM Bank 0의 일부분이다. 실제 Bank 0는 0xc0000000부터 시작하지만 앞부분 얼마는 Angel이 사용하기 때문에 여기서 부터 올려져 실행되도록 만들어진다.

그림 4-8. SA-1110 메모리 맵

(4)
각종 초기화 코드만 따로 모은다. ENTRY가 stext이고 커널 이미지의 제일 앞이 .text.init부터 시작되므로 실행은 stext가 위치한 arch/arm/kernel/head-armv.S부터 실행된다.
(5)
만들어지긴 하지만 실제 커널 이미지엔 포함되지 않는 코드다. 커널이 exit할 일은 없기 때문이다.
(6)
진짜 text 세그먼트와 읽기 전용 데이터가 위치한다.
(7)
한 프로세스의 스택이 8KB 단위로 작동되도록 만들어지므로 init task union은 8KB 단위로 정렬 되야 제대로 동작할 수 있다. init_task는 task_union이란 union type으로 만들어져 있고 $(TOPDIR)/include/linux/sched.h에 정의되어 있다.
union task_union {
	struct task_struct task;
	unsigned long stack[INIT_TASK_SIZE/sizeof(long)];
};
							
위에서 보듯이 task_union은 struct task_struct task;와 unsigned long stack[];으로 이뤄져 있다. 또 stack은 2048*sizeof(long)의 길이만큼을 차지하는데 SA1100에선 8192 바이트가 된다. 스택이 제대로 동작하려면 각 태스크는 적어도 8KB 단위로 정렬되야 제대로 동작할 수 있게 된다.

4.3.3. $(TOPDIR)/arch/arm/boot/compressed/vmlinux.lds

/*
 *  linux/arch/arm/boot/compressed/vmlinux.lds.in
 *
 *  Copyright (C) 2000 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
OUTPUT_ARCH(arm)
(1)
ENTRY(_start)
SECTIONS
{
(2)
  . = 0xc0008000;
  _load_addr = .;

  . = 0xc0008000;
  _text = .;

(3)
  .text : {
    _start = .;
    *(.start)
    *(.text)
    *(.fixup)
    *(.gnu.warning)
    *(.rodata)
    *(.rodata.*)
    *(.glue_7)
    *(.glue_7t)
    input_data = .;
    piggy.o
    input_data_end = .;
    . = ALIGN(4);
  }

  _etext = .;

  .data : {
    *(.data)
  }

  _edata = .;

  . = ALIGN(4);
  __bss_start = .;
  .bss : {
    *(.bss)
  }
  _end = .;

(4)
  .stack : {
    *(.stack)
  }

  .stab 0 : { *(.stab) }
  .stabstr 0 : { *(.stabstr) }
  .stab.excl 0 : { *(.stab.excl) }
  .stab.exclstr 0 : { *(.stab.exclstr) }
  .stab.index 0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment 0 : { *(.comment) }
}
(1)
최종 커널의 실행 시작점은 _start가 된다.
(2)
메모리에 올려지는 시작 위치는 0xc0008000. SA-1110의 메모리 맵에 의하면 램은 0xc0000000부터 시작하지만 angel이 앞부분 얼마를 사요하므로 여기에 일단 읽어 올려놓고 실행한다.
(3)
엔트리로 지정된 _start의 위치를 지정한다. 즉 실행코드의 시작이되고 .start 부터 시작하므로 head.S의 start에서 부터 커널이 실행된다.
(4)
스택의 뒤에 있는 exit 코드 들은 사실 필요 없으므로 무시되고 stack의 바로 뒤부터 해서 남은 메모리 영역에 커널의 압축이 풀린다.

4.3.4. Log 분석

아래 Log는 vmlinux가 만들어지는 과정을 생략하고 vmlinux의 ld가 실행되는 것과 그 이후의 과정만을 실었다. i386에서 추적했던 것과 비슷하게 만들어진다.

...

(1)
/usr/local/arm/bin/arm-linux-ld -p -X -T arch/arm/vmlinux.lds arch/arm/kernel/head-armv.o arch/arm/kernel/init-task.o init/main.o init/version.o \
	--start-group \
	arch/arm/kernel/kernel.o arch/arm/mm/mm.o arch/arm/mach-sa1100/sa1100.o kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o \
	 drivers/l3/l3.o drivers/serial/serial.o drivers/char/char.o drivers/block/block.o drivers/misc/misc.o drivers/net/net.o drivers/media/media.o drivers/ide/idedriver.o drivers/sound/sounddrivers.o drivers/mtd/mtdlink.o drivers/pcmcia/pcmcia.o drivers/net/pcmcia/pcmcia-net.o drivers/video/video.o \
	net/network.o \
	arch/arm/nwfpe/math-emu.o arch/arm/lib/lib.a /devel/arm/assabet/linux-2.4.17/lib/lib.a \
	--end-group \
	-o vmlinux
/usr/local/arm/bin/arm-linux-nm vmlinux | grep -v '\(compiled\)\|\(\.o$\)\|\( [aUw] \)\|\(\.\.ng$\)\|\(LASH[RL]DI\)' | sort > System.map
make[1]: 들어감 `/devel/arm/assabet/linux-2.4.17/arch/arm/boot' 디렉토리
make[2]: 들어감 `/devel/arm/assabet/linux-2.4.17/arch/arm/boot/compressed' 디렉토리
(2)
/usr/local/arm/bin/arm-linux-gcc -D--ASSEMBLY-- -D--KERNEL-- -I/devel/arm/assabet/linux-2.4.17/include -mapcs-32 -march=armv4 -mno-fpu -msoft-float -traditional -c head.S
/usr/local/arm/bin/arm-linux-gcc -D--KERNEL-- -I/devel/arm/assabet/linux-2.4.17/include -O2 -DSTDC-HEADERS -mapcs-32 -march=armv4 -mtune=strongarm1100 -mshort-load-bytes -msoft-float -D--KERNEL-- -I/devel/arm/assabet/linux-2.4.17/include  -c -o misc.o misc.c
(3)
/usr/local/arm/bin/arm-linux-gcc -D--ASSEMBLY-- -D--KERNEL-- -I/devel/arm/assabet/linux-2.4.17/include -mapcs-32 -march=armv4 -mno-fpu -msoft-float   -c -o head-sa1100.o head-sa1100.S
(4)
/usr/local/arm/bin/arm-linux-objcopy -O binary -R .note -R .comment -S /devel/arm/assabet/linux-2.4.17/vmlinux piggy
gzip -9 < piggy > piggy.gz
/usr/local/arm/bin/arm-linux-ld -r -o piggy.o -b binary piggy.gz
rm -f piggy piggy.gz
(5)
/usr/local/arm/bin/arm-linux-ld -p -X -T vmlinux.lds head.o misc.o head-sa1100.o piggy.o /usr/local/arm/lib/gcc-lib/arm-linux/2.95.3/libgcc.a -o vmlinux
make[2]: 나감 `/devel/arm/assabet/linux-2.4.17/arch/arm/boot/compressed' 디렉토리
(6)
/usr/local/arm/bin/arm-linux-objcopy -O binary -R .note -R .comment -S compressed/vmlinux zImage
make[1]: 나감 `/devel/arm/assabet/linux-2.4.17/arch/arm/boot' 디렉토리
(1)
$(TOPDIR)/vmlinux와 System.map을 만든다.
(2)
i386과 마찬가지로 초기화를 담당하는 head와 압축을 풀어주는 misc를 컴파일한다.
(3)
SA1100에 관계된 특정 명령을 수행한다. 우선 command line으로 입력된 것을 0xc0000000에 복사하고 캐시 관계된 일을 처리하고 시리얼로 연결된 호스트에 터미널 프로그램이 뜰 동안 좀 기다려준다. 4.2절에서 처럼 커널과 램디스크 이미지를 다운로드한 다음에 터미널을 실행하는데 기다려주지 않으면 터미널로는 초기부팅 과정에 대한 것을 볼 수 없게 된다.
(4)
$(TOPDIR)/vmlinux를 바이너리로 만들고 압축한다. 그리고 다른 것과 링킹할 수 있도록 해놓는다.
(5)
이제 head, misc, head-sa1100 piggy를 합쳐 커널 이미지를 만들어낸다.
(6)
최종 커널 이미지를 만들어 낸다.