ARM Linux中断向量表搬移设计过程
_svc@3 (SVC_26 / SVC_32)
。。。
.long__pabt_invalid@f
/*
* Undef instr entry dispatcher
* Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
*/
vector_stubund, UND_MODE
.long__und_usr@0 (USR_26 / USR_32)
.long__und_invalid@1 (FIQ_26 / FIQ_32)
.long__und_invalid@2 (IRQ_26 / IRQ_32)
.long__und_svc@3 (SVC_26 / SVC_32)
。。。
.long__und_invalid@f
.align5
vector_fiq:
disable_fiq
subspc, lr, #4
vector_addrexcptn:
bvector_addrexcptn
/*
* We group all the following data together to optimise
* for CPUs with separate I & D caches.
*/
.align5
.LCvswi:
.wordvector_swi
.globl__stubs_end
__stubs_end:
.equstubs_offset, __vectors_start + 0x200 - __stubs_start
.globl__vectors_start
__vectors_start:
swiSYS_ERROR0
bvector_und + stubs_offset
ldrpc, .LCvswi + stubs_offset
bvector_pabt + stubs_offset
bvector_dabt + stubs_offset
bvector_addrexcptn + stubs_offset
bvector_irq + stubs_offset
bvector_fiq + stubs_offset
.globl__vectors_end
__vectors_end:
为了让大家看得更清,我把代码的结构再次简化成这样:
.globl__stubs_start
__stubs_start:
.align5
vector_irq:
[code part]//展开代码
[jump table part]//地址跳转表
。。。
.align5
vector_dabt:
[code part]
[jump table part]
。。。
.align5
vector_ pabt:
[code part]
[jump table part]
。。。
.align5
vector_und:
[code part]
[jump table part]
。。。
.align5
vector_fiq:
。。。
.globl__stubs_end
__stubs_end:
.globl__vectors_start
__vectors_start:
swiSYS_ERROR0
bvector_und + stubs_offset
ldrpc, .LCvswi + stubs_offset
bvector_pabt + stubs_offset
bvector_dabt + stubs_offset
bvector_addrexcptn + stubs_offset
bvector_irq + stubs_offset
bvector_fiq + stubs_offset
.globl__vectors_end
__vectors_end:
在这里我不花过多的篇幅去解释代码的意思,这不是本文的目的,只要你把结构看清,就达到目的了。但我会花点时间研究一下展开代码部分(蓝色)的特征,这部分代码是与位置无关的代码,我们稍微研究一下,它为什么会这么写。
.align5
vector_irq:
[code part]//展开代码
[jump table part]//地址跳转表
。。。
首先这部分代码大致都是一样的结构,前面是一些代码,后面跟着一个跳转表。跳转表里面定义了一些地址。我们截取这部分看
。。。
@ the branch table must immediately follow this code
@
andlr, lr, #0x0f(1)// lr中当前存储了上一个状态寄存器的值,对后几位做与,
//就是取在中断前处在用户态还是核心态,这个值用作跳
//转表的索引
movr0, sp(2)//用做他用,sp值当第一个参数传给后面函数
ldrlr, [pc, lr, lsl #2](3)// pc是当前执行指令地址加8,即跳转表的基地址,lr是索引
//很好的技巧,取pc找当前地址什么时候都没错
movpc, lr@ branch to handler in SVC mode
[jump table]
.long__irq_usr@0(USR_26 / USR_32)
.long__irq_invalid@1(FIQ_26 / FIQ_32)
.long__irq_invalid@2(IRQ_26 / IRQ_32)
.long__irq_svc@3(SVC_26 / SVC_32)
真正的跳转在最后一句完成,大家都看得很清楚。跳到哪里去了,如果中断以前是svc模式,就会跳到__irq_svc。我们发现这里不会直接用b(bl,bx等)个,
ü一是b跳转后面是个偏移,而这个偏移是有限制的,不能太大
ü二是b跳转后面的偏移你不知道在代码拷贝后还是不是那个样子,因为我们要搬移代码,所以如果你不能确定搬移后的偏移不变,那你就用绝对地址,而上面的代码前三句就是算出绝对地址来,然后用绝对地址赋值给pc直接完成跳转。
这些都是一些技巧,总之你要注意的是写位置无关的代码时涉及到跳转部分,用b跳转还是直接赋成绝对地址(通过跳转表实现),如果你不能保证搬移后的偏移一致,写这部分就要注意了,要用一些技巧的。
大家可以去用gcc的-fPIC和-S选项汇编一个小的函数看看,fPIC就是与位置无关选项,相信编译过动态库的人都熟悉,看看它是怎么做的。你会发现异曲同工。
Scenario 3第三场景大搬移
我用一个章节来介绍大搬移的过程,以及一些在搬移中Linux出现的问题及解决方案。我把整个的搬移过程做成一张图里,然后讨论了一些技术细节。我们看到这是一个巨大无比的图,我们这章节的所阐述的内容都在图里。
我们将搬移前的代码组织称为Code/Load视图,因为这是代码中的(或image中的)组织情况,把搬移后的代码组织称为Exec视图,反映的是代码执行时代码在内存中的情况。
ARMLinux中断向量 相关文章:
- ARM Linux 中断向量表建立流程(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)