arch 1

    通过对makefile的分析,对整一个依赖关系有一个大致的了解。接下来准备对每一个模块进行分析。首先看第一个子目录arch。

    arch目录是针对不同目标开发板设计的,存放着处理器架构相关的代码,比如可能针对的是s3c2440,s3c2410等,不同的处理器架构有着不一样的硬件模块。而整个vivi启动包括两个部分,第一部分就是完成含依赖于CPU的体系结构硬件初始化的代码,包括禁止中断、初始化串口、复制自身到RAM等。这部分代码需要根据不同的处理器来编写,该目录下就保存了针对不同处理器的第一阶段的代码。(后面的讨论针对2440来进行)

     打开该文件夹可以看到:def-configs,s3c2440,config.in,Makefile,vivi.lds.in.

     同样我们也从Makefile开始看起。

     1、Makefile:

     通过Makefile中开头的注释我们就可以大概知道Makefile中的内容了:# Select CPU dependent flags.  Note that order of declaration is important;# the options further down the list override previous items.依赖于CPU的相关选项的设置,比如编译的时候需要指定的跟CPU相关的选项,根据CPU相关的SDRAM的地址来指定程序运行地址等。其中在写法上保持了OPTION-y这样的写法(在vivi Makefile中由配置决定的优化选项好象基本用了这种写法,我个人觉得这个写法是很好的),

    按照CPU体系结构的配置信息追加了一些编译选项:

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

         。。。。。。

 

    从名称就可以看出,与连接脚本是密切相关的(我们在看总Makefile的时候看到LINKFLAGS = -Tarch/vivi.lds -Bstatic ),但是是.lds后缀的,所以估计下面要在LDSCRIPT    = arch/vivi.lds.in这个上做文章来产生这个.lds脚本。

    LDSCRIPT    = arch/vivi.lds.in(等下会分析这个小文件的内容)

    又比如我的开发板是2440:

    ifeq ($(CONFIG_ARCH_S3C2440),y)
    MACHINE        = s3c2440
      ifeq ($(CONFIG_S3C2440_NAND_BOOT),y)
        TEXTADDR    = 0x33f00000
      else
        TEXTADDR    = 0x00000000
      endif
    endif

 

    ifeq ($(CONFIG_VIVI_ADDR),y)
    TEXTADDR    = 0x$(CONFIG_VIVI_TEXTADDR)
    endif

 

    export    MACHINE PROCESSOR TEXTADDR

 

    其中CONFIG_ARCH_S3C2440 CONFIG_VIVI_ADDR等是在配置过程中产生的(这可以从同目录下的config.in的选项看到,后面将对config.in进行讨论,配置结果最后保存在.config中,.config被总Makefile包含)。最后的地址将由我们的设定值和配置结果决定。对于具体的地址我们可以按照自己的实际情况来设定。比如我最后只配置了CONFIG_ARCH_S3C2440,那么最后我指定的连接的运行地址是0x33f00000,这个值将传递给连接脚本,可以看到在该Makefile中(后面一点的部分):

    arch/vivi.lds: $(LDSCRIPT) dummy
        @sed s/TEXTADDR/$(TEXTADDR)/ $(LDSCRIPT) >$@

 

    定义了HEAD := arch/$(MACHINE)/head.o,这就是我们总Makefile(include了这个Makefile)中用到的HEAD的定义。不过我认为这句是不是应该放在下面那段的后面,或者是在下面那个ifeq里面,因为这个目录还在进行判断是否存在,这里却在用了?

 

    然后我们看到:

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

    如果我们在看总Makefile时还纠结于为什么vivi依赖文件里面vivi: include/version.h $(CONFIGURATION) init/main.o init/version.o linuxsubdirs没有直接看到head.o后者说head.o为什么没有被作为CORE_FILES的话,那么这里就清晰了,在主Makefile中因为                      linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
                                           $(patsubst %, _dir_%, $(SUBDIRS)) : include/version.h
                                                 $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@)


此时的SUBDIRS已经+= $(MACHDIR),在按照SUBDIRS目录执行子makefile的时候同样也执行了arch/s3c2440目录下的Makefile,生成head.o文件。可以猜想head.o和其他SUBDIRS包含的文件对应的.o文件可能都是用这种办法形成的(如果在主Makefile中没有出现在任何以来中的话)。(那么那些文件夹里面应该有一个Makefile,并且需要有实现规则,这个规则可能是借用调用Rules.make来实现。暂时的猜想。)

 

    CLEAN_FILES += arch/vivi.lds

    也许应该继续往下看来分析为什么可以删除这个连接脚本(当然它肯定是要删除的,因为连接的内容是根据每一次配置而不同的,如运行地址),不过其实我们先面已经分析过了这个规则(红色部分),当然在这个Makefile中这部分其实是放在下面的。由此我们可以知道删除它自然有生成它的办法。这个也是黄色部分的解答。


    # Configuration targets.  Use these to select a
    # configuration for your architecture
    %_config:
        @( /
        CFG=$(@:_config=); /
        if [ -f arch/def-configs/$$CFG ]; then /
          [ -f .config ] && mv -f .config .config.old; /
          cp arch/def-configs/$$CFG .config; /
          echo "*** Default configuration for $$CFG installed"; /
          echo "*** Next, you may run 'make oldconfig'"; /
        else /
          echo "$$CFG does not exist"; /
        fi; /
        )   ----------------------------------------------------------------------这里有些符号我还需要弄清楚。
    这部分提供CREAT一个自己的定义的配置文件并成为.config文件,因为在总Makefile中我们已经知道配置方式有config,oldconfig,menuconfig等,其中config将逐个询问配置选项默认值,这样在没有.config时相当于询问了全部选择,而存在.config时就根据它来设置默认值;而oldconfig则是询问.config里面还没有配置的选项,当然它需要一个已经存在的.config文件。menuconfig 是图形化了的询问方式,如果.config存在那么用该文件配置默认值。这些都是跟LINUX内核配置方式一致的。

    所以如果我们需要用基于自己定义的文件来进一步配置,则需要将其替换存在的.config文件,并执行make oldconfig进一步配置。上一次在分析总Makefile的时候,最后也是有一个:

    %: ./arch/def-configs/%
       $(MAKE) distclean
        cp arch/def-configs/$* ./.config -f
        $(MAKE) oldconfig
        $(MAKE)

    我觉得原理差不多,这里相当于包括了CREAT了.config并且自动运行了整个Makefile。另外这些配置文件都需要放在arch/def-configs这个地方。

    这样这个Makefile就分析完了,回头想想,主要做了3件事情:完成一些CPU体系相关的选项和定义的追加,定义了运行域并以次CREAT了一个连接脚本,提供了一个用自己的配置文件来生成.config文件的途径。

    可能有一个疑问,到目前只出现了head.o,但是并没有生成它的规则。我想这个我们应该去看arch/s3c2440文件夹的内容(也就是所谓的MACHDIR 或者arch/$(MACHINE)),看看要生成head.o到底需要那些依赖以及操作再下定论。而且因为现在已经把这个目录追加到了SUBDIRS中,这就保证了运行其中的Makefile,并且CORE_FILES 也追加了$(MACHDIR)/$(MACHINE).o(也就是head.o),不过这在vivi的连接过程中好象有点重复,因为里面已经有对HEAD的连接了。 不过这之前先分析一下:config.in和 vivi.lds.in,因为前面的过程依赖于它们。

 

    2、config.in   (怎么自己写这个文件其中的语法还需要学习)

    在分析总Makefile的时候,已经接触了这个配置选项的文件,大概知道里面是对一些配置选项的罗列,提示以及操作。

    打开看一下,提示了Documentation/kbuild/config-language.txt,这应该是LINUX下的参考文件,以后可以按照这个学学习一下config的语法。

    如果按照2440的思路来,一种选择将包括:

                                         ARM system type ------>CONFIG_ARCH_S3C2440

                                         Platform------------------>CONFIG_S3C2440_SMDK

                                         General setup----------->CONFIG_VIVI_ADDR(未选),因为根据前面的Makefile中可知道,这将影响TEXTADDR的最后取值,这里没有选中。

                                         CACHE Enable  没有打开任何一个cache

                                            接下来的都没有选择。。。

    其他还调入了其他一些文件夹下的config.in文件,因为这里只是根据CPU和开发平台选择的一些配置。

    根据交互时选择的配置,生成的信息将存入.config文件。

 

 

    3、vivi.lds.in    (连接脚本的书写格式)

                SECTIONS {
                        . = TEXTADDR;
                        .text          : { *(.text) }
                        .data ALIGN(4) : { *(.data) }
                        .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
                                   }

 

          三个段和起始地址,第二行用了通配符*表示所有字符,这里的意思就是说指定的每个目标文件的text section的内容都放到同一个.text中。第三行表示指定的每个目标文件的data section的内容都放到同一个.data中,而且要四字节边界对齐。第四行表示指定的每个目标文件的bss section的内容都放到同一个.bss中,所有的普通符号都放到COMMON中,而且要四字节边界对齐。涉及到的这些段在以前分析linker&loader时已经接触过,可以参考。根据前面的配置信息,在Makefile中产生的TEXTADDR的值将用于此。生成vivi的连接操作就按照这个文件生成的.lds脚本进行。

         因为linux是需要MMU的,所以这将被作为VMA,关于虚拟地址,转换后的虚拟地址,物理地址这些需要去研究MMU和上下文切换

 

 

    4、s3c2440

     现在终于要看这个文件夹了,我们很早已经知道它里面存放着一个关键文件head.S。一上来这里就有讲究:.S。这个知识点是根据编译器而来,因为打开这个文件来看,可以发现它并不只有汇编的语法,还有预处理信息。这样我们就需要用到预处理工具:cpp.查看GNU的as手册:You can use the gnu C compiler driver to get other “CPP” style preprocessing, by giving the input file a ‘.S’ suffix.

 或者查看gcc manue:file.S file.sx Assembler code which must be preprocessed. 等等。这样就很明白了。

    题外话:熟悉GNU工具是非常有挑战但是非常非常重要的,比如在as手册中也简单介绍了ld,详细介绍了Sections and Relocation,这些就是就是后面理解linker&loader的基础。再去看ld手册那么就很清楚了。我想这些对于嵌入式linux开发都是致关重要的。

    不过同样首先打开Makefile看了一下:

            O_TARGET    := s3c2440.o

            obj-y :=

            ifeq ($(CONFIG_S3C2440_NAND_BOOT),y)
            obj-y += nand_read.o
            endif
            obj-y += mmu.o proc.o
            obj-$(CONFIG_S3C2440_SMDK) += smdk.o
            ifeq ($(CONFIG_S3C2440_SMDK),y)
            obj-$(CONFIG_TEST) += smdk2440_test.o
            endif

           include $(TOPDIR)/Rules.make

    初看只是定义了两个变量,而第二个变量的追加内容对应的就是该文件夹下的除head.S以外的其他文件的目标文件。但是定义这两个变量到底用在哪,最后一句include给出了解释,看了一下Rules.make,确实在里面有O_TARGET等的规则定义:$(O_TARGET): $(obj-y)。这样看来这些文件一起生成了一个s3c2440.o文件。而这些(obj-y中的.o文件在成为依赖的同时,也将由Rules.make中的相应规则所产生。

    那么s3c2440.o这个文件到底有什么用,继续看Rules.make内容:all_targets: $(O_TARGET) $(L_TARGET),是与另外一个L_TARGET一起成为all_targets的依赖,并且没有命令,定位all_targets:                            first_rule: sub_dirs
                                                                                                                                    $(MAKE) all_targets

是first_rule的执行命令,可见这条命令的唯一作用就是生成$(O_TARGET) $(L_TARGET)这两个文件。具体first_rule是用来什么的,sub_dirs指什么,以后将专门来分析Rules.make时具体分析。因为我认为Rules.make在整个vivi中的角色非常重要。

 

    可见,Rules.make定义了很多通用的规则,用以各种源文件生成目标文件。由此想到我们的总Makefile中也是include了这个文件,并且head.o在总Makefile中已经成为依赖(在上一层的Makefile中实现),加上head.o并未在其他地方定义生成规则,所以可能也是用这种方法生成的,那么来看一下head.S的内容(这个文件将在专门一篇文章中分析):首先include了3个头文件,然后就是一系列汇编指令,因此需要一个预编译和一个编译来实现。要由.S文件编译生成.o文件,可以先由cpp变成.s,再由as变成.o实现;或者直接由gcc来实现。而按照Rules.make中提供的编译选项,两种方式都能实现。这里的一个问题是到底由哪种方式生成,我不是很清楚,因为两种生成方式会相差一个中间结果head.s。这里还可以分析的是include的头文件并不与head.s在同一个目录下,因此这肯定需要在编译预处理的时候指示这些头文件的搜索目录,看到无论哪种编译方式,编译选项里面都有$(AFLAGS),定位到总Makefile中这个便宜选项的定义AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS),再定位到预编译选项CPPFLAGS,顺利发现包含两个搜索目录:CPPFLAGS := -I$(VIVIPATH) -I$(LINUX_INCLUDE_DIR),其中VIVIPATH = $(TOPDIR)/include,这些头文件确实在这个目录下,因此对上了,至于另一个LINUX_INCLUDE_DIR    = /usr/local/arm/2.95.3/include我想应该是预编译类似arm linux类似文件时候用到的搜索路径,这里只编译vivi的文件的话,应该是用不到的,但是我想有一种情况如果是将内核跟vivi一起来编译,可能有用,这个以后再研究。顺便看一下另外一个编译选项-D__ASSEMBLY__:

                    -D Ignored. This option is accepted for script compatibility with calls to other assemblers.
                    --defsym sym=value
                    Define the symbol sym to be value before assembling the input file. value must be an integer constant. As in C, a leading ‘0x’ indicates a hexadecimal value, and a leading ‘0’ indicates an octal value.我的理解是相当于定义了
__ASSEMBLY__,但并不影响编译。而且在调用的头文件linkage.h中可以看到:

                                                                                      #ifdef __ASSEMBLY__

                                                                                       #define ALIGN __ALIGN
                                                                                       #define ALIGN_STR __ALIGN_STR

                                                                                        #define ENTRY(name) /
                                                                                        .globl SYMBOL_NAME(name); /
                                                                                         ALIGN; /
                                                                                         SYMBOL_NAME_LABEL(name)

                                                                                          #endif                    

我想这应该就是这个定义的作用,这些在专门分析head.S的时候来具体分析。分析到此:head.o由Rules.make的规则编译生成。这样所有arch文件夹里的文件对应生成的.o文件,都由Rules.make实现。

 

    5、def-configs

    这个文件夹也不陌生了。

    a、总Makefile分析的时候,知道了它存放着默认的配置文件,打开可以看到一个smdk2440文件,如果这个文件的配置信息可以满足需要,那么通过make smdk2440自动完成vivi的生成。回顾一下:

                       %: ./arch/def-configs/%
                             $(MAKE) distclean
                             cp arch/def-configs/$* ./.config -f
                             $(MAKE) oldconfig
                             $(MAKE)

    b、在前面分析arch文件夹中的Makefile中也有一段使用自己定义的配置信息文件做母板,通过make %_config加上make oldconfig来CREAT新的.config文件的定义,这个母板也需要存放在这里,这个前面已经分析过。

    又一次提到.config文件,想到另外一个内容相同的文件include/autoconfig.h文件。但是我认为这两个的作用又有点区别。因为正好在head.S文件中通过逐层的包含关系涉及到了这个文件,所以干脆在那个时候去分析了。

 

    到这里为止,已经把arch文件夹的结构理了一遍,接下来就详细分析里面几个重要文件的内容了。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值