解释跳转表/分支表

Cou*_*tts 3 arm

我一直在用装配慢慢拾起东西.我正在研究Canon Rebel T1i,这是我想要了解的一小段代码流程图.据我所知,相信相机有一个132MHz的ARM v5处理器:

http://i.imgur.com/PtWC9.png

我搜索谷歌的底部试图了解跳转表是如何工作的,无论我读多少,我都无法将事物连接在一起来理解它.我理解跳转表类似于case语句,但我不明白它是如何在表中移动的.

例如:在这个例子中只有一个CMP操作,所以我不明白它是如何工作的.任何帮助将不胜感激!!

old*_*mer 6

我不认为你在屏幕截图上有足够的信息来了解它如何连接到你的问题.但一般的跳转表......

在C中考虑一系列函数,并且已经初始化了函数数组中的每个元素,稍后您的代码会做出一些决定并使用索引来选择其中一个函数.正如你所提到的情况下发言,可以实现这样但这是例外而不是规则,一切都取决于在开关和case语句的元素的尺寸/宽/自然使用的变量之中.

您已经拿起装配,让您了解寄存器,做数学与寄存器,存储在寄存器中的东西,等程序计数器可以通过许多指令只是另一个寄存器中使用,所不同的是,当你写的东西给它,你改变接下来执行什么指令.

让我们尝试一个case语句示例:

switch(bob&3)
{
   case 0: ted(); break;
   case 1: joe(); break;
   case 2: jim(); bob=2; break;
   case 3: tim(); bob=7; break;
}
Run Code Online (Sandbox Code Playgroud)

你可能(可能不会)做的是:

casetable:
     .word a
     .word b
     .word c
     .word d

    caseentry:
      ldr r1,=bob
      ldr r0,[r1]
      ldr r2,=casetable
      and r0,#3
      ldr pc,[r2,r0,lsl #2] 

    a:
      bl ted
      b caseend
    b:
      bl joe
      b caseend
    c:
      bl jim
      mov r0,#2
      ldr r1,=bob
      str r0,[r1]  
      b caseend
    d:
      bl tim
      mov r0,#7
      ldr r1,=bob
      str r0,[r1]
      b caseend

    caseend:
Run Code Online (Sandbox Code Playgroud)

因此,标签casetable之后的四个字:是每个案例的代码开始的地址,case0从a开始:case1代码从b开始,依此类推.我们需要做的是获取switch语句使用的变量,并以数学方式计算表中项目的地址.然后我们需要将表中的地址加载到程序计数器中.写入程序计数器与执行跳转相同.

因此,C样本是为了简化而精心制作的.首先将bob变量的内容加载到r0中.它与3.跳转表中的项目是32位地址,或4个字节,因此我们需要将r0乘以4以获得表中的偏移量.向左移位2与乘以4相同.我们需要将r0 << 2添加到跳转表的基址.所以基本上我们计算address_of(casetable)+((bob&3)<< 2)在该计算地址处读取存储器并将该值加载到程序计数器中.

用胳膊(你提到这是手臂)你可以在一条指令中做很多事情:

ldr pc,[r2,r0,lsl #2]
Run Code Online (Sandbox Code Playgroud)

加载到寄存器pc中,存储单元的内容为[r2 +(r0 << 2)].r2是casetable的地址,r0是bob&3.

基本上,跳转表归结为以数学方式计算地址表中的偏移量.地址表是您想要跳转/分支到的地址,具体取决于数学运算中使用的一个参数,在上面的示例中,bob就是该变量.地址a,b,c,d是我想根据bob的内容选择的地址选择.有很多有趣和有趣的方法来做这类事情,但这一切都归结为在运行时计算分支到的地址,并以一种导致特定处理器执行的方式将该地址推入程序计数器基本上是跳跃.

注意另一个,也许更容易阅读计算和跳转的方式是我的例子:

   mov r3,r0,lsl #2
   add r3,r2
   bx r3
Run Code Online (Sandbox Code Playgroud)

支持拇指的核心经常使用带有寄存器的bx指令,通常你会看到bx lr从分支链接(子程序)调用返回.bx lr表示pc = lr.bx r3表示pc = r3.

我希望这就是你所问的问题,如果我误解了这个问题,请详细说明.

编辑:

查看屏幕截图上的代码.

cmp r0,#4
addls pc,pc,r0,lsl #2
Run Code Online (Sandbox Code Playgroud)

可选的数学运算(如果更低或相同则添加ADDLS)计算新程序计数器值(跳转表是存储在程序计数器中的计算),基于程序计数器本身加上偏移r0乘以4.对于臂处理器,当时执行时,程序计数器是前面的两个指令.所以,混合这两行代码和我的一部分示例:

cmp r0,#4
addls pc,pc,r0,lsl #2
ldr pc,=a
ldr pc,=b
ldr pc,=c
ldr pc,=d
...
Run Code Online (Sandbox Code Playgroud)

在执行addls时,程序计数器包含ldr pc,= b指令的地址.因此,如果r0包含0然后0 << 2 = 0,则pc加0将分支到ldr pc,= b指令,然后该指令导致分支到b:标签.如果r0在addls时包含1,则接下来执行ldr pc,= c指令,依此类推.你可以用这种方式制作一张桌子.另请注意,由于add是有条件的,如果条件没有发生,你将在addls之后执行第一条指令,所以也许你希望它是一个无条件的分支来分支表,或者向后分支一个循环或者它可能是一个nop让你陷入第一次跳跃,或者我上面所做的是将它分支到其他地方.因此,要了解发生了什么,您需要举例说明addls之后的指令,以确定可能的跳转表目标是什么.