Uboot 命令是如何被使用的?

有什么问题请 发邮件至syyxy@outlook.com, 欢迎交流~  

 

在uboot代码中命令的模式是这个样子:

 

 

 

这样是如何和命令行交互的呢?

 

在command.h 中, 我们可以看到如下宏定义

 

将其拆分出来:

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

         U_BOOT_CMD_COMPLETE(name,maxargs, rep,cmd,usage,help,NULL)

我们可以看到

U_BOOT_CMD(

         md,  3,      1,      do_mem_md,

         "memory display",

         "[.b, .w, .l] address [# of objects]"

);

 被define成了:

U_BOOT_CMD_COMPLETE(

         md,  3,      1,      do_mem_md,

         "memory display",

         "[.b, .w, .l] address [# of objects]",NULL

);

 

继续:

 

#define U_BOOT_CMD_COMPLETE(name,maxargs,rep,cmd,usage,help,comp) \

         cmd_tbl_t __u_boot_cmd_##name Struct_Section = \

                   U_BOOT_CMD_MKENT_COMPLETE(name,maxargs,rep,cmd,usage,help,comp)

 

其中,##name 意思是 使用 name 替换 ##name

 

由此可见,上述被define成了:

cmd_tbl_t   __u_boot_cmd_md  Struct_Section = \

U_BOOT_CMD_MKENT_COMPLETE(md,      3,      1,      do_mem_md, "memory display","[.b, .w, .l] address [# of objects]",NULL);

 

 

继续:

 

#define U_BOOT_CMD_MKENT_COMPLETE(name,maxargs,rep,cmd,usage,help,comp) \

 

         {#name, maxargs, rep, cmd, usage, _CMD_HELP(help) _CMD_COMPLETE(comp)}

 

 

 

其中,#的作用是字符串化,意思是将 name 转化成一个字符串。

 

具体## 和 # 请参阅如下文档。

 

https://wenku.baidu.com/view/56ed000216fc700abb68fcdd.html

 

 

 

可以看到,U_BOOT_CMD_MKENT_COMPLETE(md,         3,      1,      do_mem_md, "memory display","[.b, .w, .l] address [# of objects]");   被define成了

{“md”, 3, 1, do_mem_md, "memory display", _CMD_HELP("[.b, .w, .l] address [# of objects]")   _CMD_COMPLETE(NULL)}

 

因此 U_BOOT_CMD_COMPLETE被定义成了:

cmd_tbl_t   __u_boot_cmd_md  Struct_Section = \

{

“md”,

 3,

1,

 do_mem_md,

 "memory display",

 _CMD_HELP("[.b, .w, .l] address [# of objects]")  _CMD_COMPLETE(NULL)

}

 

继续:

由于 #define Struct_Section  __attribute__((unused, section(".u_boot_cmd"), aligned(4))),而

# define _CMD_COMPLETE(x)   x,

# define _CMD_HELP(x)   x,

(注意最后都有一个逗号) , 因此 上述被定义成了

cmd_tbl_t  __u_boot_cmd_md  __attribute__((unused, section(".u_boot_cmd"), aligned(4))) =

{

“md”,

 3,

1,

 do_mem_md,

 "memory display",

 "[.b, .w, .l] address [# of objects]",

 NULL

}

上述是我们的分析,接下来 通过将cmd_mem.c 预编译得到

cmd_tbl_t __u_boot_cmd_md __attribute__((unused, section(".u_boot_cmd"), aligned(4))) =

{"md",

 3,

 1,

do_mem_md,

 "memory display",

"[.b, .w, .l] address [# of objects]",

((void *)0),};

完全一致,因此上述分析正确。

=================================我是分割线===================================

 

接下来第二步,这些命令是如何被使用的?

首先分析我们在第一步得到的结构体:

 

cmd_tbl_t __u_boot_cmd_md  __attribute__((unused, section(".u_boot_cmd"), aligned(4))) =

{"md",

 3,

 1,

do_mem_md,

 "memory display",

"[.b, .w, .l] address [# of objects]",

((void *)0),};

 

__attribute__((unused, section(".u_boot_cmd"), aligned(4))) 说明,将这个结构体放到 .u_boot_cmd 段中,该段4字节对其,unused 代表 告诉编译器 该函数或者变量可能不使用,GGC不要对其报警告。

请注意, 这里是将该结构体放到编译出来的.o 文件的 .u_boot_cmd段,   没有放到输出文件的.u_boot_cmd。当链接的时候才能放到 输出文件的 .u_boot_cmd段。

我们知道 GCC 默认的段中没有 .u_boot_cmd 这个段,那么就要手动创建这个段。Uboot通过链接脚本创建的这个段, 图片截取自u-boot.lds

 

 

 

既然说在会将指令放到 .u_boot_cmd 这个段,那么能不能证明呢?

以澜起平台为例,找到生成的中间文件 u-boot 通过objdump –t 找到symbol table 然后 grep 出u_boot_cmd使用如下指令,

/opt/Montage-tech/mips-4.3/bin/mips-linux-gnu-objdump  -t u-boot |grep u_boot_cmd >~/u-boot.txt

可以得到 如下cmd , 其中加红 的是我们上述 md 命令 :8017964c l    d  .u_boot_cmd  00000000 .u_boot_cmd80179b70 g     O .u_boot_cmd 0000001c __u_boot_cmd_nf80179b1c g     O .u_boot_cmd 0000001c __u_boot_cmd_macmode801799e8 g     O .u_boot_cmd 0000001c __u_boot_cmd_cpu80179dbc g     O .u_boot_cmd 0000001c __u_boot_cmd_freeze_with_dioff80179c6c g     O .u_boot_cmd 0000001c __u_boot_cmd_sspi80179a90 g     O .u_boot_cmd 0000001c __u_boot_cmd_macinit8017964c g     O .u_boot_cmd 0000001c __u_boot_cmd_runapp801798d0 g     O .u_boot_cmd 0000001c __u_boot_cmd_mm80179b8c g     O .u_boot_cmd 0000001c __u_boot_cmd_env80179da0 g     O .u_boot_cmd 0000001c __u_boot_cmd_av_launch801797b8 g     O .u_boot_cmd 0000001c __u_boot_cmd_fatls8017987c g     O .u_boot_cmd 0000001c __u_boot_cmd_loady80179d14 g     O .u_boot_cmd 0000001c __u_boot_cmd_version80179b54 g     O .u_boot_cmd 0000001c __u_boot_cmd_ntt80179cf8 g     O .u_boot_cmd  0000001c __u_boot_cmd_usbboot80179748 g     O .u_boot_cmd 0000001c __u_boot_cmd_coninfo80179be0 g     O .u_boot_cmd 0000001c __u_boot_cmd_setenv80179d68 g     O .u_boot_cmd 0000001c __u_boot_cmd_tsi80179940 g     O .u_boot_cmd 0000001c __u_boot_cmd_cp801796bc g     O .u_boot_cmd 0000001c __u_boot_cmd_reset80179ca4 g     O .u_boot_cmd 0000001c __u_boot_cmd_false80179994 g     O .u_boot_cmd 0000001c __u_boot_cmd_loop80179a04 g     O .u_boot_cmd 0000001c __u_boot_cmd_nand801796d8 g     O .u_boot_cmd 0000001c __u_boot_cmd_bootm80179a58 g     O .u_boot_cmd 0000001c __u_boot_cmd_mpw80179978 g O .u_boot_cmd 0000001c __u_boot_cmd_base 80179bc4 g O .u_boot_cmd 0000001c __u_boot_cmd_printenv 80179c34 g O .u_boot_cmd 0000001c __u_boot_cmd_snf 801799cc g O .u_boot_cmd 0000001c __u_boot_cmd_sleep 80179ac8 g O .u_boot_cmd 0000001c __u_boot_cmd_macrx 80179c18 g O .u_boot_cmd 0000001c __u_boot_cmd_sf 80179d84 g O .u_boot_cmd 0000001c __u_boot_cmd_show_logo 80179764 g O .u_boot_cmd 0000001c __u_boot_cmd_echo 8017980c g O .u_boot_cmd 0000001c __u_boot_cmd_help 80179844 g O .u_boot_cmd 0000001c __u_boot_cmd_itest 80179df4 g .u_boot_cmd 00000000 __u_boot_cmd_end 80179d4c g O .u_boot_cmd 0000001c __u_boot_cmd_secure 80179780 g O .u_boot_cmd 0000001c __u_boot_cmd_exit 801796a0 g O .u_boot_cmd 0000001c __u_boot_cmd_goo 80179bfc g O .u_boot_cmd 0000001c __u_boot_cmd_run 80179c88 g O .u_boot_cmd 0000001c __u_boot_cmd_test 80179828 g O .u_boot_cmd 0000001c __u_boot_cmd_question_mark 80179908 g O .u_boot_cmd 0000001c __u_boot_cmd_mw 80179dd8 g O .u_boot_cmd 0000001c __u_boot_cmd_jpeg_logo 80179d30 g O .u_boot_cmd 0000001c __u_boot_cmd_vid 80179a3c g O .u_boot_cmd 0000001c __u_boot_cmd_mpr 80179ae4 g O .u_boot_cmd 0000001c __u_boot_cmd_bootp 80179ba8 g O .u_boot_cmd 0000001c __u_boot_cmd_editenv 80179898 g O .u_boot_cmd 0000001c __u_boot_cmd_loadimg 80179924 g O .u_boot_cmd 0000001c __u_boot_cmd_cmp 8017972c g O .u_boot_cmd 0000001c __u_boot_cmd_iminfo 80179860 g O .u_boot_cmd 0000001c __u_boot_cmd_loadb 801798ec g O .u_boot_cmd 0000001c __u_boot_cmd_nm 801797f0 g O .u_boot_cmd 0000001c __u_boot_cmd_fatwrite 801799b0 g O .u_boot_cmd 0000001c __u_boot_cmd_mtest 8017995c g O .u_boot_cmd 0000001c __u_boot_cmd_crc32 80179b38 g O .u_boot_cmd 0000001c __u_boot_cmd_dhcp 8017979c g O .u_boot_cmd 0000001c __u_boot_cmd_fatload 801797d4 g O .u_boot_cmd 0000001c __u_boot_cmd_fatinfo 80179cc0 g O .u_boot_cmd 0000001c __u_boot_cmd_true  801798b4 g O .u_boot_cmd 0000001c __u_boot_cmd_md 80179c50 g O .u_boot_cmd 0000001c __u_boot_cmd_source 80179aac g O .u_boot_cmd 0000001c __u_boot_cmd_mactx 80179cdc g O .u_boot_cmd 0000001c __u_boot_cmd_usb 80179b00 g O .u_boot_cmd 0000001c __u_boot_cmd_tftpboot 80179668 g O .u_boot_cmd 0000001c __u_boot_cmd_bdinfo 80179710 g O .u_boot_cmd 0000001c __u_boot_cmd_bootd 80179a20 g O .u_boot_cmd 0000001c __u_boot_cmd_nboot 8017964c g .u_boot_cmd 00000000 __u_boot_cmd_start 801796f4 g O .u_boot_cmd 0000001c __u_boot_cmd_boot 80179684 g O .u_boot_cmd 0000001c __u_boot_cmd_go 80179a74 g O .u_boot_cmd 0000001c __u_boot_cmd_macfilter 

如上,就是定义的结构如何被使用, 并且得到了证明。

=================================我是分割线===================================

接下来是最后一步,我们从命令行输入指令是是如何和我们的 .u_boot_cmd 段连接起来的?

 

在 command.c 中的 num command_ret_t cmd_process(int flag, int argc, char * const argv[],

                                   int *repeatable) 函数中 调用了 find_cmd, 以下为其实现。

cmd_tbl_t *find_cmd (const char *cmd)

{

         int len = &__u_boot_cmd_end - &__u_boot_cmd_start;

         return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);

}

 

其中 __u_boot_cmd_end 和 __u_boot_cmd_start 为在u-boot.lds 中定义的字段

.u_boot_cmd : {

 __u_boot_cmd_start = .;

 *(.u_boot_cmd)

 __u_boot_cmd_end = .;

 }

 

等号后面的 ' . ' 代表链接后的当前位置。在上一步中我们查到了 __u_boot_cmd_start 位置为 0x8017964c , __u_boot_cmd_end 位置为 0x80179df4。Len = 0x7A8

 

当我们输入一个存在的指令后,  find_cmd_tbl(cmd, &__u_boot_cmd_start, len); 会得到该指令的地址,  然后调用 cmd_call 执行, 具体请看command.c 下的cmd_process 函数。

=================================我是分割线===================================

 

至此,Uboot 命令的流程已经说明白了。

 

=================================我是分割线===================================

此外, 对Uboot 有所研究的朋友在makefile 中发现了这么一句话:

 

GEN_UBOOT = \
UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
  sed -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
  cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $$UNDEF_SYM $(__OBJS) \
  --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
  -Map u-boot.map -o u-boot

这句话解析如下 :

首先 在Makefile中,  ` ` 代表 执行shell代码, 让我们把该代码拿出来 :

$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
  sed -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq 

$(OBJDUMP)  代表 objdump 工具,  $(LIBBOARD)  $(LIBS) 明显代表一些库文件, $(SYM_PREFIX) 代表前缀,这些对我们分析问题无关紧要 ,这里我们将其简化。于是上述代码简化成了:

objdump -x libtest.a | sed -n -e  's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq 

objudmp -x  libtest.a  可以得到 libtest.a 库中所有的 symbol, 包括函数,数组,文件等,这里我们简称为符号 .

然后将得到的符号通过"管道" 传递给sed 进行编辑。接下来对sed 进行分析:

sed -n -e  's/.*\(__u_boot_cmd_.*\)/-u\1/p' 

sed -n -e 代表使用 silent 模式,以及直接在命令行进行编辑动作。

'   '  两个单引号之间表示将要进行的动作 。 

标记成黑色的 s 代表会进行替换操作('s/要被取代的字串/新的字串/').

p 代表打印出来。

因此上面的表达式的最浅显的意思是:

将   .*\(__u_boot_cmd_.*\)  替换为  -u\1    

并且由于sed 支持正则表达式, 在正则表达式中括号()代表分组, 使用 \1 \2 \3 获取第一个分组,第二个分组, 第三个分组。因此上述表达式进一步被理解为:

将   .*__u_boot_cmd_.*  替换为  -u.*__u_boot_cmd_.*  

请注意,  上面的字符串和上上面字符串的不同。

在正则表达式中 . 代表任意字符(不包括空格), 代表任意个, 因此我们将上述语句按照汉语翻译一遍:

使用 objdump -x  解析   libtest.a 得到一些符号,将这些符号使用sed 进行处理, 处理方式是: 找到符号中有__u_boot_cmd_字段的那一部分, 然后在这些字段前面加上-u。

接下来 |sort|uniq  就比较好理解了,就是进行排序和消除重复。

然后将其赋值给  UNDEF_SYM . 至此 

UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
  sed -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;  这一部分分析完毕, 总结来说就是 找到一些字段,在字段前面加上-u ,最后赋值给 UNDEF_SYM 这个变量。

 

接下来分析:

cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $$UNDEF_SYM $(__OBJS) \
  --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
  -Map u-boot.map -o u-boot

其实这一点没什么好说的, 无非就是执行ld 链接,然后生成u-boot这个文件, 这里需要注意的是 在其中使用了  UNDEF_SYM 变量,UNDEF_SYM 代表-uxxx__u_boot_cmd_xxx ,这是什么意思呢? 

通过 man ld 可以找到 :

  -u symbol--undefined=symbolForce symbol to be entered in the output file as an undefined symbol.  Doing this may, for example, trigger linking of additional modules from standard libraries.  -u may be repeated with different option argumentsto enter additional undefined symbols.  This option is equivalent to the "EXTERN" linker script command.

 


也就是说在可执行文件中通过-u可以插入未定义变量。

 这样一来, 也就明白了 这段代码的目的是u_boot_cmd 变量插入到可执行文件中。 

 

接下来继续最开始的问题:  既然u-boot 使用 __attribute__((unused, section(".u_boot_cmd"), aligned(4)))  的方式将uboot 的指令插入到 输出文件的  .u_boot_cmd  段, 那  GEN_UBOOT  这个 ‘函数' 的意义是什么呢? 将重复的工作在做一遍吗 ?

 

这个问题也困扰了我很久,直到本篇文档写完也没有头绪, 我的分析过程简单的说一下, 

使用ld -u 插入符号, 一般都会在  .strtab   这个段中,  可以通过 readelf -S test.out,可以找到   .strtab   这个段的index ,比如说是 38, 然后通过 readelf  -x38  test.out ,查看源文件。可以清楚的看到这些字段。

但是使用   __attribute__((unused, section(".u_boot_cmd"), aligned(4)))   的方式链接器会自动的将 我们定义的变量的字段系写入到    .strtab  这个section 中(大家可以写一个简单的小程序验证下,我之前验证过,但是代码没有保存下来)。 这样看来 就重复了。 因此从目前来看, GEN_UBOOT  是没有什么用的。当然, 如果果有哪位朋友知道原因,请发邮件给我 syyxy@outlook.com 或者评论一下,感激不尽。

 

转载于:https://www.cnblogs.com/syyxy/p/8992446.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/389737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据可视化应用_在数据可视化中应用种族平等意识

大数据可视化应用The following post is a summarized version of the article accepted to the 2020 Visualization for Communication workshop as part of the 2020 IEEE VIS conference to be held in October 2020. The full paper has been published as an OSF Preprint…

Windows10电脑系统时间校准

有时候新安装电脑系统,系统时间不对,需要主动去校准系统时间。1、点击时间 2、日期和时间设置 3、其他日期、时间和区域设置 4、设置时间和日期 5、Internet 时间 6、点击立即更新,如果更新失败就查电脑是否已联网,重试点击立即更…

pd种知道每个数据的类型_每个数据科学家都应该知道的5个概念

pd种知道每个数据的类型意见 (Opinion) 目录 (Table of Contents) Introduction 介绍 Multicollinearity 多重共线性 One-Hot Encoding 一站式编码 Sampling 采样 Error Metrics 错误指标 Storytelling 评书 Summary 摘要 介绍 (Introduction) I have written about common ski…

xgboost keras_用catboost lgbm xgboost和keras预测财务交易

xgboost kerasThe goal of this challenge is to predict whether a customer will make a transaction (“target” 1) or not (“target” 0). For that, we get a data set of 200 incognito variables and our submission is judged based on the Area Under Receiver Op…

2017. 网格游戏

2017. 网格游戏 给你一个下标从 0 开始的二维数组 grid ,数组大小为 2 x n ,其中 grid[r][c] 表示矩阵中 (r, c) 位置上的点数。现在有两个机器人正在矩阵上参与一场游戏。 两个机器人初始位置都是 (0, 0) ,目标位置是 (1, n-1) 。每个机器…

HUST软工1506班第2周作业成绩公布

说明 本次公布的成绩对应的作业为: 第2周个人作业:WordCount编码和测试 如果同学对作业成绩存在异议,在成绩公布的72小时内(截止日期4月26日0点)可以进行申诉,方式如下: 毕博平台的第二周在线答…

币氪共识指数排行榜0910

币氪量化数据在今天的报告中给出DASH的近期买卖信号,可以看出从今年4月中旬起到目前为止,DASH_USDT的价格总体呈现出下降的趋势。 转载于:https://www.cnblogs.com/tokpick/p/9621821.html

走出囚徒困境的方法_囚徒困境的一种计算方法

走出囚徒困境的方法You and your friend have committed a murder. A few days later, the cops pick the two of you up and put you in two separate interrogation rooms such that you have no communication with each other. You think your life is over, but the polic…

Zookeeper系列四:Zookeeper实现分布式锁、Zookeeper实现配置中心

一、Zookeeper实现分布式锁 分布式锁主要用于在分布式环境中保证数据的一致性。 包括跨进程、跨机器、跨网络导致共享资源不一致的问题。 1. 分布式锁的实现思路 说明: 这种实现会有一个缺点,即当有很多进程在等待锁的时候,在释放锁的时候会有…

resize 按钮不会被伪元素遮盖

textarea默认有个resize样式,效果就是下面这样 读 《css 揭秘》时发现两个亮点: 其实这个属性不仅适用于 textarea 元素,适用于下面所有元素:elements with overflow other than visible, and optionally replaced elements repre…

平台api对数据收集的影响_收集您的数据不是那么怪异的api

平台api对数据收集的影响A data analytics cycle starts with gathering and extraction. I hope my previous blog gave an idea about how data from common file formats are gathered using python. In this blog, I’ll focus on extracting the data from files that are…

前端技术周刊 2018-09-10:Redux Mobx

前端快爆 在 Chrome 10 周年之际,正式发布 69 版本,整体 UI 重新设计,同时iOS 版本重新将工具栏放置在了底部。API 层面,支持了 CSS Scroll Snap、前端资源锁 Web Lock API、WebWorker 里面可以跑的 OffscreenCanvas API、toggleA…

逻辑回归 概率回归_概率规划的多逻辑回归

逻辑回归 概率回归There is an interesting dichotomy in the world of data science between machine learning practitioners (increasingly synonymous with deep learning practitioners), and classical statisticians (both Frequentists and Bayesians). There is gener…

sys.modules[__name__]的一个实例

关于sys.modules[__name__]的用法,百度上阅读量比较多得一个帖子是:https://www.cnblogs.com/robinunix/p/8523601.html 对于里面提到的基础性的知识点这里就不再重复了,大家看原贴就好。这里为大家提供一个详细的例子,帮助大家更…

ajax不利于seo_利于探索移动选项的界面

ajax不利于seoLately, my parents will often bring up in conversation their desire to move away from their California home and find a new place to settle down for retirement. Typically they will cite factors that they perceive as having altered the essence o…

C#调用WebKit内核

原文:C#调用WebKit内核版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013564470/article/details/80255954 系统要求 Windows与.NET框架 由于WebKit库和.NET框架的要求,WebKit .NET只能在Windows系统上运行。从…

数据分析入门:如何训练数据分析思维?

本文由 网易云 发布。 作者:吴彬彬(本篇文章仅限知乎内部分享,如需转载,请取得作者同意授权。) 我们在生活中,会经常听说两种推理模式,一种是归纳 一种是演绎,这两种思维模式能够帮…

559. N 叉树的最大深度

559. N 叉树的最大深度 给定一个 N 叉树,找到其最大深度。 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。 示例 1: 输入&#…

el表达式取值优先级

不同容器中存在同名值时,从作用范围小到大的顺序依次尝试取值:pageContext->request->session->application 转载于:https://www.cnblogs.com/wrencai/p/9006880.html

数据探索性分析_探索性数据分析

数据探索性分析When we hear about Data science or Analytics , the first thing that comes to our mind is Modelling , Tuning etc. . But one of the most important and primary steps before all of these is Exploratory Data Analysis or EDA.当我们听到有关数据科学或…