uboot中的start.S文件开头的这段代码:
00000000 [0xea000012] b 0x50
00000004 [0xe59ff014] ldr pc,0x00000020 ; = #0x33f80140
00000008 [0xe59ff014] ldr pc,0x00000024 ; = #0x33f801a0
0000000c [0xe59ff014] ldr pc,0x00000028 ; = #0x33f80200
00000010 [0xe59ff014] ldr pc,0x0000002c ; = #0x33f80260
00000014 [0xe59ff014] ldr pc,0x00000030 ; = #0x33f802c0
00000018 [0xe59ff014] ldr pc,0x00000034 ; = #0x33f80320
0000001c [0xe59ff014] ldr pc,0x00000038 ; = #0x33f80380
00000020 [0x33f80140] mvnccs r0,#0x10 ; ? rn = 0x8
00000024 [0x33f801a0] mvnccs r0,#0x28 ; ? rn = 0x8
00000028 [0x33f80200] mvnccs r0,#0, 4 ; ? rn = 0x8
0000002c [0x33f80260] mvnccs r0,#6 ; ? rn = 0x8
00000030 [0x33f802c0] mvnccs r0,#0xc ; ? rn = 0x8
00000034 [0x33f80320] mvnccs r0,#0x80000000 ; ? rn = 0x8
00000038 [0x33f80380] mvnccs r0,#2 ; ? rn = 0x8
0000003c [0xdeadbeef] cdple p14,0xa,c11,c13,c15,7
现在来简单的分析一下这一段代码,代码中的七个ldr指令就是使程序进入到不同的模式中,因为ARM对应有7个不同的模式。一直很让人弄不明白的就是经过这样的代码,比如现在要FIQ中断产生了,pc会被强制赋值为ldr pc, _fiq这条指定的地址,这个时候pc的值会指向_fiq标号处,最终pc里面将会被赋为fiq标号的值。首先补充一下ARM的中断向量表:ARM要求中断向量表必须放置在从0地址开始,连续8×4字节的空间内(ARM720T和ARM9、ARM10也支持从0xFFFF0000开始的高地址向量表)。具体如下图所示:
我理解到这里的时候心里面一直有两个问题想不明白:
1.为什么pc的值被赋值为_fiq: .word fiq指令的地址后,fiq的值就会被赋到pc中?
2.为什么要做这样两次的跳转?为什么不直接使用一次跳转就跳转到fiq的位置,比如使用b指令跳转或者ldr pc,=_fiq这种方式呢?
这两个问题查了很久也没有找到确切的答案,但是以下的意见可以提供参考:
.word fiq这是.word伪指令的使用方法,伪指令的处理并不是由处理器来执行,处理器也没有与之相对应的指令码。这个.word伪指令的作用就是将fiq的运行地址的值取出来,存放到当前的内存单元中,从反汇编代码可以看出来这个地址占了4个字节,其值为0x33f80380,虽然反汇编代码将这个值解释出来了一个指令,但是这个指令是没有意义的!这里需要使用的是0x33f80380而并非需要把它当做一个操作码。所以整个7个.word构成的可以看做是跳转的第二级的表格,当pc被赋值为这个表格中的一个地址时,由于什么机制(可能硬件默认第二次就是取跳转的值,并不会将取到的数据当做指令来解释,这个当然是一种猜测)就直接会将这个内存单元中的值赋值给pc。
当时看ldr伪指令的操作的时候,如果使用ldr pc,=_fiq这种使用方法,当跳转范围不能够使用一个立即数来表示的时候,编译器将会借助于内存来完成跳转的赋值操作,这里相当于就把这个功能直接写出来,而并不是让编译器去做。因为从反汇编指令可以看出,ldr pc, _undefined_instruction,给pc赋的值为0x00000020。要这样两级跳转的目的是不是防止跳转范围过大超出立即数的表示范围呢?这个问题先这样假设,如果有了新的证据再来修改这里的文章。
.balign是意思是:以当前地址为开始开始,找到第一次出现的以第一个参数为整数倍的地址,并将其作为结束地址,在这个结束地址前面存储一个字节长度的数据,存储内容正是第二个参数。如果当前地址正好是第一个参数的倍数,则没有数据被写入到内存。
ldr伪指令
ldr r1,=0x2000014 ;将0x2000014付给r1.
ldr r1,=label ;把label这个 地址值赋给r1
.globl _start
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
.balignl 16,0xdeadbeef
对应的反汇编的结果:
00000000 [0xea000012] b 0x50
00000004 [0xe59ff014] ldr pc,0x00000020 ; = #0x33f80140
00000008 [0xe59ff014] ldr pc,0x00000024 ; = #0x33f801a0
0000000c [0xe59ff014] ldr pc,0x00000028 ; = #0x33f80200
00000010 [0xe59ff014] ldr pc,0x0000002c ; = #0x33f80260
00000014 [0xe59ff014] ldr pc,0x00000030 ; = #0x33f802c0
00000018 [0xe59ff014] ldr pc,0x00000034 ; = #0x33f80320
0000001c [0xe59ff014] ldr pc,0x00000038 ; = #0x33f80380
00000020 [0x33f80140] mvnccs r0,#0x10 ; ? rn = 0x8
00000024 [0x33f801a0] mvnccs r0,#0x28 ; ? rn = 0x8
00000028 [0x33f80200] mvnccs r0,#0, 4 ; ? rn = 0x8
0000002c [0x33f80260] mvnccs r0,#6 ; ? rn = 0x8
00000030 [0x33f802c0] mvnccs r0,#0xc ; ? rn = 0x8
00000034 [0x33f80320] mvnccs r0,#0x80000000 ; ? rn = 0x8
00000038 [0x33f80380] mvnccs r0,#2 ; ? rn = 0x8
0000003c [0xdeadbeef] cdple p14,0xa,c11,c13,c15,7
现在来简单的分析一下这一段代码,代码中的七个ldr指令就是使程序进入到不同的模式中,因为ARM对应有7个不同的模式。一直很让人弄不明白的就是经过这样的代码,比如现在要FIQ中断产生了,pc会被强制赋值为ldr pc, _fiq这条指定的地址,这个时候pc的值会指向_fiq标号处,最终pc里面将会被赋为fiq标号的值。首先补充一下ARM的中断向量表:ARM要求中断向量表必须放置在从0地址开始,连续8×4字节的空间内(ARM720T和ARM9、ARM10也支持从0xFFFF0000开始的高地址向量表)。具体如下图所示:
我理解到这里的时候心里面一直有两个问题想不明白:
1.为什么pc的值被赋值为_fiq: .word fiq指令的地址后,fiq的值就会被赋到pc中?
2.为什么要做这样两次的跳转?为什么不直接使用一次跳转就跳转到fiq的位置,比如使用b指令跳转或者ldr pc,=_fiq这种方式呢?
这两个问题查了很久也没有找到确切的答案,但是以下的意见可以提供参考:
.word fiq这是.word伪指令的使用方法,伪指令的处理并不是由处理器来执行,处理器也没有与之相对应的指令码。这个.word伪指令的作用就是将fiq的运行地址的值取出来,存放到当前的内存单元中,从反汇编代码可以看出来这个地址占了4个字节,其值为0x33f80380,虽然反汇编代码将这个值解释出来了一个指令,但是这个指令是没有意义的!这里需要使用的是0x33f80380而并非需要把它当做一个操作码。所以整个7个.word构成的可以看做是跳转的第二级的表格,当pc被赋值为这个表格中的一个地址时,由于什么机制(可能硬件默认第二次就是取跳转的值,并不会将取到的数据当做指令来解释,这个当然是一种猜测)就直接会将这个内存单元中的值赋值给pc。
当时看ldr伪指令的操作的时候,如果使用ldr pc,=_fiq这种使用方法,当跳转范围不能够使用一个立即数来表示的时候,编译器将会借助于内存来完成跳转的赋值操作,这里相当于就把这个功能直接写出来,而并不是让编译器去做。因为从反汇编指令可以看出,ldr pc, _undefined_instruction,给pc赋的值为0x00000020。要这样两级跳转的目的是不是防止跳转范围过大超出立即数的表示范围呢?这个问题先这样假设,如果有了新的证据再来修改这里的文章。
.balign是意思是:以当前地址为开始开始,找到第一次出现的以第一个参数为整数倍的地址,并将其作为结束地址,在这个结束地址前面存储一个字节长度的数据,存储内容正是第二个参数。如果当前地址正好是第一个参数的倍数,则没有数据被写入到内存。
补充:上面的困惑终于有点眉目了,感谢chinaunix上的网友帮助,补充内容如下:
ldr伪指令
ldr r1,=0x2000014 ;将0x2000014付给r1.
ldr r1,=label ;把label这个 地址值赋给r1