解释跳转表/分支表

时间:2011-07-08 16:17:36

标签: arm

我一直在慢慢装配装配。我正在研究Canon Rebel T1i,这是我想要了解的一小段代码流程图。据我所知,我相信这款相机配备了132MHz ARM v5处理器:

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

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

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

1 个答案:

答案 0 :(得分:6)

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

在C中考虑一系列函数,并且已经初始化了函数数组中的每个元素,稍后您的代码会做出一些决定并使用索引来选择其中一个函数。正如你提到的一个case语句,可以用那种方式实现,但这将是异常而不是规则,所有这些都取决于switch中使用的变量以及case语句中元素的大小/宽度/性质。

你一直在拾取汇编,所以你理解寄存器,用寄存器进行数学运算,将东西存储在寄存器中等等。程序计数器可以被许多指令用作另一个寄存器,不同之处在于当你写一些东西时,你改变接下来执行的指令。

让我们尝试一个案例陈述示例:

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

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

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:

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

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

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

ldr pc,[r2,r0,lsl #2]

将寄存器pc的内容加载到寄存器pc中[r2 +(r0 <&lt; 2)]。 r2是casetable的地址,r0是bob&amp; 3.

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

注意另一个,在我的例子中计算和跳转的方法可能更容易:

   mov r3,r0,lsl #2
   add r3,r2
   bx r3

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

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

编辑:

查看屏幕截图中的代码。

cmp r0,#4
addls pc,pc,r0,lsl #2

可选的数学运算(ADDLS add if if lower或same)根据程序计数器本身加上偏移r0乘以4计算新程序计数器值(跳转表是存储在程序计数器中的计算)。对于arm处理器,在执行时,程序计数器是前面的两个指令。所以,混合这两行代码和我的一部分示例:

cmp r0,#4
addls pc,pc,r0,lsl #2
ldr pc,=a
ldr pc,=b
ldr pc,=c
ldr pc,=d
...

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