在ARM汇编中使用ADDS指令而不是ADD指令的原因是什么?
我的课程笔记总是在ARM代码片段中使用ADD和SUB,而不是像我所期望的那个样使用ADD和SUB。下面是一个这样的片段,例如:在ARM汇编中使用ADDS指令而不是ADD指令的原因是什么?,arm,cortex-m,Arm,Cortex M,我的课程笔记总是在ARM代码片段中使用ADD和SUB,而不是像我所期望的那个样使用ADD和SUB。下面是一个这样的片段,例如: __asm void my_capitalize(char *str) { cap_loop LDRB r1, [r0] // Load byte into r1 from memory pointed to by r0 (str pointer) CMP r1, #'a'-1 // compare it with the character before
__asm void my_capitalize(char *str)
{
cap_loop
LDRB r1, [r0] // Load byte into r1 from memory pointed to by r0 (str pointer)
CMP r1, #'a'-1 // compare it with the character before 'a'
BLS cap_skip // If byte is lower or same, then skip this byte
CMP r1, #'z' // Compare it with the 'z' character
BHI cap_skip // If it is higher, then skip this byte
SUBS r1,#32 // Else subtract out difference to capitalize it
STRB r1, [r0] // Store the capitalized byte back in memory
cap_skip
ADDS r0, r0, #1 // Increment str pointer
CMP r1, #0 // Was the byte 0?
BNE cap_loop // If not, repeat the loop
BX lr // Else return from subroutine
}
例如,这段简单的代码将字符串中的所有小写英语转换为大写。我在这段代码中不理解的是为什么他们没有使用ADD和SUB命令,而不是当前正在使用的ADD和SUB命令。ADDS和SUBS命令afaik将更新APSR标志NZCV,以供以后使用。但是,正如您在上面的代码片段中所看到的,没有使用更新的值。那么,该命令还有其他用途吗?算术指令ADD、SUB等不修改状态标志,这与比较指令CMP、TEQ不同,后者默认情况下会更新条件标志。但是,将S添加到算术指令SADD、SUBS等将根据操作结果更新条件标志。这是在算术指令中使用S的唯一一点,因此如果不检查cf,就没有理由使用ADDS而不是ADD
为了实现不同的目的,有更多的代码附加到指令中,例如CC条件标志C=0,因此:
ADDCC:如果进位状态位设置为0,则执行该操作
ADDCCS:如果进位状态位设置为0,则执行该操作;如果C=1,则更新状态标志,状态标志不被覆盖
从循环的角度来看,更新条件标志与否没有区别。例如,ADDS和ADD将花费1个周期
放弃使用ADD看起来像是一个懒惰的选择,因为ADD在某些情况下非常有用。再进一步考虑这些例子:
SUBS r0, r0, #1
ADDS r0, r0, #2
BNE go_wherever
及
可能会产生不同的行为
正如old_timer所指出的那样,这个问题变得非常相关。谈到统一语言,首选的语法是ADDS,而不是ADD。因此,即使是为了使用UAL组装Thumb和/或ARM,OP的代码也是绝对正确的。算术指令ADD、SUB等不会修改状态标志,这与比较指令CMP、TEQ不同,CMP、TEQ默认情况下会更新条件标志。但是,将S添加到算术指令SADD、SUBS等将根据操作结果更新条件标志。这是在算术指令中使用S的唯一一点,因此如果不检查cf,就没有理由使用ADDS而不是ADD
为了实现不同的目的,有更多的代码附加到指令中,例如CC条件标志C=0,因此:
ADDCC:如果进位状态位设置为0,则执行该操作
ADDCCS:如果进位状态位设置为0,则执行该操作;如果C=1,则更新状态标志,状态标志不被覆盖
从循环的角度来看,更新条件标志与否没有区别。例如,ADDS和ADD将花费1个周期
放弃使用ADD看起来像是一个懒惰的选择,因为ADD在某些情况下非常有用。再进一步考虑这些例子:
SUBS r0, r0, #1
ADDS r0, r0, #2
BNE go_wherever
及
可能会产生不同的行为
正如old_timer所指出的那样,这个问题变得非常相关。谈到统一语言,首选的语法是ADDS,而不是ADD。因此,即使是为了使用UAL组装Thumb和/或ARM,OP的代码也绝对不错。在某些cortex-ms上不提供不带标志更新的ADD。如果您查看ARM文档中的指令集,那么在为非通用用例编写汇编语言时,这始终是一个好主意在armv7-m cortex-m3、cortex-m4、cortex-m7上的thumb2扩展之前可用。cortex-m0和cortex-m0+以及通常使用armv4t或armv6-m的广泛兼容代码没有添加无标志选项。也许这就是原因 另一个原因可能是得到16位指令,而不是32位指令,但这是一个滑坡,因为它更多地进入汇编程序,它们的语法是由汇编程序定义的,汇编程序是处理汇编语言的程序,而不是目标。例如,非统一气体:
.thumb
add r1,r2,r3
Disassembly of section .text:
00000000 <.text>:
0: 18d1 adds r1, r2, r3
但是
所以在这种情况下并不容易,但是使用统一的语法,您开始进入blahw,blah.w,blah,type语法,并且必须回过头来检查您想要的指令是否正在生成。非统一也有自己的游戏,当然所有这些都是特定于汇编程序的
我怀疑他们要么选择了他们唯一的选择,要么使用了更小、更兼容的指令,尤其是如果这是一个类或文本,则越兼容越好。在某些cortex-ms上不提供无标记更新的添加。如果你看一下arm 在为通用用例编写汇编语言时,指令集的文档始终是一个好主意,在armv7-m cortex-m3、cortex-m4、cortex-m7上安装thumb2扩展之前,这些用例是不可用的。cortex-m0和cortex-m0+以及通常使用armv4t或armv6-m的广泛兼容代码没有添加无标志选项。也许这就是原因 另一个原因可能是得到16位指令,而不是32位指令,但这是一个滑坡,因为它更多地进入汇编程序,它们的语法是由汇编程序定义的,汇编程序是处理汇编语言的程序,而不是目标。例如,非统一气体:
.thumb
add r1,r2,r3
Disassembly of section .text:
00000000 <.text>:
0: 18d1 adds r1, r2, r3
但是
所以在这种情况下并不容易,但是使用统一的语法,您开始进入blahw,blah.w,blah,type语法,并且必须回过头来检查您想要的指令是否正在生成。非统一也有自己的游戏,当然所有这些都是特定于汇编程序的
我怀疑他们要么选择了他们唯一的选择,要么使用了更小、更兼容的指令,尤其是如果这是一个类或文本,那么越兼容越好。我想你应该问问编写代码的人。可能那个人使用了一种或多种编码方式,默认情况下总是更新状态标志。@Michael,当然,我会尝试联系编写此代码的人。我想你必须询问编写此代码的人。可能那个人使用了一种或多种编码方式,默认情况下总是更新状态标志。@Michael,当然,我会尝试联系写这篇文章的人。因为您提到了ARMv6-M,所以值得一提的是,在16位thumb编码中,一些组合,如ADD r5,5是不可表达的,在full thumb 2中,指令的大小可能不同,例如ADD r5,5是32位,而ADD r5,5是16位。由于您提到了ARMv6-M,因此值得一提的是,在16位thumb编码中,某些组合(如ADD r5,5)是不可表达的,而在full thumb 2中,指令的大小可能不同,例如,添加r5,5是32位,而添加r5,5是16位。
.syntax unified
.thumb
adds r1,r2,r3
add r1,r2,r3
Disassembly of section .text:
00000000 <.text>:
0: 18d1 adds r1, r2, r3
2: eb02 0103 add.w r1, r2, r3