Chinaunix首页 | 论坛 | 博客
  • 博客访问: 937243
  • 博文数量: 173
  • 博客积分: 3436
  • 博客等级: 中校
  • 技术积分: 1886
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-07 09:29
文章分类

全部博文(173)

文章存档

2016年(6)

2015年(10)

2014年(14)

2013年(8)

2012年(36)

2011年(63)

2010年(19)

2009年(17)

分类: LINUX

2011-03-27 16:01:33

应用程序命令行宏定义方式实现 
 
 
在u-boot开发过程中,发现u-boot命令添加非常方便,在任何编译的.c文件里面增加u_boot_CMD类似的一个命令定义,并实现命令函数,就能在命令行执行该命令。对于这点一直觉得很神奇,也按照这个格式增加了很多命令,但不知道怎么实现的。
  现在想自己写个控制台程序,也想使用这种方式方便增加自己的命令,于是参照u-boot研究了一下。发现u-boot宏定义了一个“.u_boot_cmd”的Section,在command.h文件:
  extern cmd_tbl_t __u_boot_cmd_start;
  extern cmd_tbl_t __u_boot_cmd_end;
  #define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
  在u-boot.lds文件又有这段描述:
   . = .;
   __u_boot_cmd_start = .;
   .u_boot_cmd : { *(.u_boot_cmd) }
   __u_boot_cmd_end = .;
  看起来,__u_boot_cmd_start和__u_boot_cmd_end是在lds文件里面定义出来的,所以命令结构通过预处理,存放到了“.u_boot_cmd”的Section里面。
 
那么在应用程序中,如何通过lds文件实现上述功能?
步骤:
1) 生成lds文件,方法:
     ld --verbose得到默认的ld script
   去掉头部和尾部,这里保存为cmd.ld文件。 注意:如果arm交叉编译的话,ld前面要加 arm-linux-ld --verbose > cmd.lds
生成的lds文件有头,不符合lds文件语法,需要屏蔽掉。
 
2) 在Makefile中通过:
    $(GCC) -T$(LDSCRIPT) -o $@ $^
指定链接时使用的lds文件,如果不指定则用默认的lds文件;
(此步骤,验证生成的lds文件是合法的,起到作用的)
 
3)在SECTIONS增加新的端定义,添加位置在
  __bss_start = .;
  __bss_start__ = .;之前

 . = .;
 __u_boot_cmd_start = .;
 .u_boot_cmd : { *(.u_boot_cmd) }
 __u_boot_cmd_end = .;  
 
    -T指定连接文件,这样“u_boot_cmd”Section就生效了
 

 gcc等编译器内置有缺省的连接脚本。如果采用缺省脚本,则生成的目标代码需要操作系统才能加载运行。为了能在嵌入式系统上直接运行,需要编写自己的连接脚本文件。编写连接脚本,首先要对目标文件的格式有一定了解。GNU编译器生成的目标文件缺省为elf格式。elf文件由若干段(section)组成,如不特殊指明,由C源程序生成的目标代码中包含如下段:.text(正文段)包含程序的指令代码;.data(数据段)包含固定的数据,如常量、字符串;.bss(未初始化数据段)包含未初始化的变量、数组等。C++源程序生成的目标代码中还包括.fini(析构函数代码)和.init(构造函数代码)等。有关elf文件格式,读者可自行参考相关资料。连接器的任务就是将多个目标文件的.text.data.bss等段连接在一起,而连接脚本文件是告诉连接器从什么地址开始放置这些段。例如笔者的引导程序连接文件link.lds为:

ENTRY(begin)

SECTION

{ .=0x00300000;

.text : { *(.text) }

.data: { *(.data) }

.bss: { *(.bss) }

}

  其中,ENTRY(begin)指明程序的入口点为begin标号;.=0x00300000指明目标代码的起始地址为0x00300000,这一段地址为MX1的片内RAM.text : { *(.text) }表示从0x00300000开始放置所有目标文件的代码段,随后的.data: { *(.data) }表示数据段从代码段的末尾开始,再后是.bss段。

 
注意makefile:
all:后面跟的是要生成的目标文件。all可以有一个或者多个目标文件。
 
all: $(TARGET)
%.o:%.c
 $(CC) -c $(CFLAGS) $< -o $@
 
$(TARGET):  main.o console.o command.o cmd_date.o
# $(GCC) $(CFLAGS) -o $@ $^
 $(GCC) -T$(LDSCRIPT) -o $@ $^
 
all是个伪目标,是所有目标的目标,其功能是编译所有的目标。
如果makefile中不写all的话,则默认遇到makefile中第一个目标为默认目标。
C/C++ code
.PHONY:all all:prog1 prog2 prog3 prog4

要编译prog1 prog2 prog3 prog4 四个目标,我们可以使用 make all 命令来编译所有的目标。
也可以 make prog3单独编译 prog3 目标。
 
阅读(3191) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~