我正在尝试为检查练习注释反汇编块。以下是我到目前为止所做的事情:
00000190 <mystery>:
190: 2300 movs r3, #0 // move address 190 (offset 0) into r3 ?
192: e004 b.n 19e <mystery+0xe> // if 19e then branch to mystery
194: f010 0f01 tst.w r0, #1 ; 0x1 // update flags to 1 in status register
198: bf18 it ne // if 198 not equal to ??? then ???
19a: 3301 addne r3, #1 // add to r3 if not equal to 19a offset 1?
19c: 1040 asrs r0, r0, #1 // shift r0 right one spot (leave it in r0)
19e: 2800 cmp r0, #0 // compare contents of r0 against 0 ?
1a0: d1f8 bne.n 194 <mystery+0x4> // branch to 194 if not equal to something at line 194?
1a2: 4618 mov r0, r3 // move r3 wholecloth into r0
1a4: 4770 bx lr // branch(return from the mystery function)
1a6: bf00 nop // No operation
所以我的评论非常简陋,而且可能非常不正确,但最重要的是我真的不明白190或19a那些指令是什么意思。只有两个参数而不是三个,所以它们如何工作?
以身作为例
19a: 3301 addne r3, #1
到目前为止,我对此的解释是:如果不等于X,那么将Y添加到r3?什么是X和Y?我应该使用上一行的结果吗?如果是这样,它取代了哪个(标准的三个)?
布拉赫!
我愿意接受我不知道自己在做什么,完全误解了一切。
请发送帮助!
答案 0 :(得分:3)
190: 2300 movs r3, #0 // assign the value 0 to R3, affecting
// the status flags (the S suffix)
19a: 3301 addne r3, #1 // add 1 to r3 IF the previous comparison was
// Not Equal to 0
ne
后缀检查先前由movs
指令设置的状态标志。
答案 1 :(得分:3)
1) TST 指令与 ANDS 基本相同,只是它不会更改第一个操作数。因此,TST r0, #1
根据(r0&amp; 1)的结果设置标志。具体来说,如果结果为零,它将设置Z(零)标志,即没有设置r0的第0位。
2) IT 代表"If-Then"。它检查指示的条件,并有条件地执行最多4条以下指令。在您的示例中,您只有一条条件指令,反汇编程序通过IT指令帮助提供了NE后缀(后缀未在Thumb-2的指令本身中编码)。 NE意味着“不相等”,但在这种情况下没有比较,那么是什么给出了?诀窍是等式检查检查Z标志,因此您可以将此视为“非零”。因此,如果未设置Z标志,则执行ADD,即r0 设置了位0。
3)围绕 CMP / BNE 发生类似情况。 CMP基本上减去操作数并根据结果设置标志。在我们的例子中,如果r0等于0,它将设置Z.接下来,BNE将测试Z标志和分支(如果没有设置)(即r0 等于0)。
将它全部转换为伪C,我们得到:
r3 = 0
goto test_loop;
loop:
Z = (r0 & 1) == 0;
if (!Z)
r3 += 1;
r0 = r0 >> 1
test_loop:
Z = (r0 - 0) == 0;
if (!Z) goto loop;
r0 = r3;
return;
或者,在“正常”C:
r3 = 0;
while ( r0 != 0 )
{
if ( r0 & 1 )
r3++;
r0 >>= 1;
}
return r3;
看起来它正在计算r0中的位。
查看条件代码表以及它们检查的标志here。 This描述了标志的设置方式和时间。
编辑:我只是重新阅读您的问题,并意识到您的困惑的一个来源。像这样:
b.n 19e <mystery+0xe>
有一个操作数,而不是两个。反汇编程序试图提供帮助,不仅显示绝对目标地址(19e),而且还显示它与最近符号的偏移量(神秘度为190,因此19e是神秘的+ 0xe)。
您需要意识到的另一件事是,在ARM(以及许多其他处理器)中,设置标志和使用标志通常在单独的指令中完成。这就是你首先做TST或CMP(或其他标志设置指令),然后使用条件指令,IT或条件分支的原因。
答案 2 :(得分:2)
如果你看看ARM ARM(ARM架构参考手册),它有一个关于标志的前面部分。与许多其他指令集不同,如果你看一下ARM指令,特别是ARM风格(不是拇指),每条指令的前四位都是条件位。与大多数其他处理器不同,使用arm可以有条件地执行任何指令,大多数其他处理器只允许条件分支。条件代码ne,nz,cs,nc等列在条件代码的早期部分中。因此,如果零标志清除则添加将是addne。与大多数其他处理器不同,ARM(在arm模式下)允许您选择何时销毁/写入标志。大多数其他人总是会更新添加的标志,例如,只有你添加s时才会更新,而添加不会添加。将条件执行和其他修饰符组合到指令时会变得棘手,例如它是addsne还是addnes?需要反复试验来解决问题。我会猜想addnes,但我很少使用这样的组合,我没有记住它。
如前所述,反汇编程序会创建一些不可组合的东西,输出上还有其他项目可帮助您解码指令。
看起来你正在看thumb2代码,它是ARM和拇指的frankenstein混合物。所以你将拥有一些手臂功能和一些拇指功能,至少与binutils一些令人讨厌的binutils-isms(没有一个手臂工具链可以比较)。例如,即使我们知道很多拇指指令修改标志而不是一个选项,并且反汇编程序通过添加而不是添加来显示这个,你不能使用添加r1,r2作为拇指模式,因为它抱怨,它希望你使用即使您正在修改标志,也要添加r1,r2。 ARM正在努力推动统一的arm / thumb汇编语法,这可能已经适用于他们的工具链,但必须看看gnu工具会发生什么。
因此,我不希望能够采用反汇编输出并重新组装该语法,原因有两个。额外的东西可以帮助您理解编码的特定指令。