GNU ARM汇编--(十二)arm汇编指令的B真的那么简单吗?

来源:互联网 发布:nginx upstream是什么 编辑:程序博客网 时间:2024/06/05 09:11

             说句题外话,在输入“指令”二字的时候,就想起了google搜索时,提示“令”不能搜索,要我换词汇.如果不能说脏话,我真就无语了.

        在前面对具体芯片的各个基本模块做完了学习后,在上一篇小结中自以为已经具备了自己写个bootloader的条件,但其实错了,我还有很多基本的知识不了解.比如编译链接\gnu的linker script等等.也有很多地方只懂表面,没有做深入的理解.

        在《GNU ARM汇编--(二)汇编编译链接与运行》中,仿照网上的例子做了makefile和linker script,在那篇blog的末尾我写道“根据google,做了上面的总结,对GNU ARM汇编有了认识,并且对系统调用软中断,中断处理,uboot异常向量表等等有了探究的欲望,也对elf格式和编译链接有了兴趣,根据自己的方向和精力,后续对这些内容做一个或深或浅的学习.

        当时看到了《linker and loader》,只是保存了,当时并没有细看,作为一个程序员,其实很多时候我们并不懂程序的细节.就像台湾有个黑客关于“hello world”的分析,当初看了他的"hello world"系列ppt,就发现原来简单的hello world里面有这么多不为人知的细节.

        这些天翻看了《linker and loader》的前面几节,也翻了《程序员的自我修养--链接装载和库》,通读了gnu.org的ld相关文档linker script.自己还对gnu的这个文档的大部分做了翻译,在自己的笔记本上写了好多页,一根笔芯也用了大半,而且让我有了久违写字写到手酸的感觉.觉得收获不少.推荐去看看,值得的.

        废话了这么多,这篇blog我倒不想写linker script或者ELF的一些细节.我想深究一下arm汇编指令中的B指令.

        很多网上的帖子都讨论过arm汇编指令的B和LDR,这里我按照我的思路来:

        首先翻一下《ARM Architecture Reference Manual》这份绝对权威的手册:

        

        

        看完上面的英文,再结合下面的实际例子做个呼应:

代码如下:

_start: breset......reset:        ......


反汇编如下:

10000000 <_start>:10000000: ea00000e b 10000040 <reset>......10000040 <reset>:


对照汇编和反汇编的结果,一切正常.下面我们来看看ea00000e是如何表达b10000040 <reset>的?

31 28     27 26 25       24                  23 0
cond       1 0 1             L                    signed_immed_24

ea00000e转换为二进制后:

31 28     27 26 25       24                  23 0
1110      1    0   1         0                   0x00000e

cond是1110,即是条件执行的ALL,L为0表示指令是B,不是BL.signed_immed_24值为0x00000e.

signed表示有符号数.所以0x00000e就是+15,按照上图的规则:

0x10000000+14<<2+8  =  0x10000040

这里的0x10000000等地址都是VMA(虚拟内存地址),而B跳转的地址是和PC相关的,所以这部分代码是与位置无关的.

注意上面等式中的+8与流水线有关.

B和BL的跳转范围是+-32MB,24bit的有符号数,也就是-2^23--2^23,即-8MB--8MB,因为有那个<<2,所以就是+-32MB了.


可以再看一个例子:

代码如下:

ledloop:ldr r1,=0x1c0str r1,[r2]bl delayldr r1,=0x1a0str r1,[r2]bl delayldr r1,=0x160str r1,[r2]bl delayldr r1,=0x0e0str r1,[r2]bl delayb ledloop


反汇编结果如下:

100002f0 <ledloop>:100002f0: e3a01d07 mov r1, #448; 0x1c0100002f4: e5821000 str r1, [r2]100002f8: ebffffad bl 100001b4 <delay>100002fc: e3a01e1a mov r1, #416; 0x1a010000300: e5821000 str r1, [r2]10000304: ebffffaa bl 100001b4 <delay>10000308: e3a01e16 mov r1, #352; 0x1601000030c: e5821000 str r1, [r2]10000310: ebffffa7 bl 100001b4 <delay>10000314: e3a010e0 mov r1, #224; 0xe010000318: e5821000 str r1, [r2]1000031c: ebffffa4 bl 100001b4 <delay>10000320: eafffff2 b 100002f0 <ledloop>


同样的:0x10000320+8+(-14)<<2 = 0x1000002f0

结合官方文档和两个实例,才能真正明白B指令的一些细节.而不是一些中文书上所说的正确的但是表面的内容.


        这么深入的分析指令B并不太麻烦,但是arm汇编有很多指令,不可能一一去分析.这里分析指令B,只是因为跳转指令在bootloader中很重要.而这里给出了一个方法,如果对LDR这种指令不清楚的话,可以用同样的方法来分析.

    

原创粉丝点击