在 ARM 汇编中使用 ADDS 指令而不是 ADD 指令的原因是什么?
What would be a reason to use ADDS instruction instead of the ADD instruction in ARM assembly?
我的课程笔记总是在他们的 ARM 代码片段中使用 ADDS 和 SUBS,而不是我期望的 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 '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 命令而不是当前使用的 ADDS 和 SUBS。 ADDS 和 SUBS 命令,afaik,更新 APSR 标志 NZCV,供以后使用。但是,正如您在上面的代码片段中看到的那样,更新后的值没有被使用。那么这个命令还有其他的用处吗?
算术指令(ADD
、SUB
等)不修改状态标志,这与更新条件的比较指令(CMP
、TEQ
)不同默认情况下的标志。但是,将 S
添加到算术指令(ADDS
、SUBS
等)将根据运算结果更新条件标志。这是对算术指令使用 S
的唯一要点,因此如果不检查 cf,则没有理由使用 ADDS
而不是 ADD
.
有更多代码附加到指令(link),以达到不同的目的,例如CC
(条件标志C=0),因此:
ADDCC
:如果进位状态位设置为0则执行操作
ADDCCS
:如果进位状态位设置为0,则执行操作,然后更新状态标志(如果C=1,则状态标志不被覆盖)。
从循环的角度来看,是否更新条件标志没有区别。以ARMv6-M为例,ADDS
和ADD
需要1个周期。
放弃使用 ADD
可能看起来像是一个懒惰的选择,因为 ADD
在某些情况下非常有用。更进一步,考虑这些例子:
SUBS r0, r0, #1
ADDS r0, r0, #2
BNE go_wherever
和
SUBS r0, r0, #1
ADD r0, r0, #2
BNE go_wherever
可能会产生不同的行为。
正如 old_timer 指出的那样,UAL becomes quite relevant on this topic. Talking about the unified language, the preferred syntax is ADDS
, instead of ADD
(link)。因此,如果目的是为 Thumb and/or ARM(使用 UAL)进行组装,则 OP 的代码绝对可以(甚至推荐)。
不带标志更新的 ADD 在某些 cortex-ms 上不可用。如果您查看指令集的 arm 文档(在使用汇编语言时总是一个好主意)用于通用用例,直到 armv7-m(cortex-m3、cortex-m4、cortex-m7)上的 thumb2 扩展才可用). cortex-m0 和 cortex-m0+ 以及一般广泛的兼容性代码(将使用 armv4t 或 armv6-m)没有 add without flags 选项。所以也许这就是原因。
另一个原因可能是获得 16 位指令而不是 32 位指令,但这是一个滑坡,因为它更多地涉及汇编器及其语法(语法由汇编器定义,汇编器是处理汇编的程序语言,而不是目标)。例如不是语法统一 gas:
.thumb
add r1,r2,r3
Disassembly of section .text:
00000000 <.text>:
0: 18d1 adds r1, r2, r3
反汇编程序知道现实,但汇编程序不知道:
so.s: Assembler messages:
so.s:2: Error: instruction not supported in Thumb16 mode -- `adds r1,r2,r3'
但是
.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
所以在这种情况下并不滑,但是使用统一语法你开始进入 blahw,blah.w,blah,键入语法并且必须回头检查以查看你想要的指令是正在生成。非统一也有自己的游戏,当然所有这些都是特定于汇编程序的。
我怀疑他们要么选择他们唯一的选择,要么使用更小、更兼容的指令,尤其是如果这是 class 或文本,越兼容越好。
我的课程笔记总是在他们的 ARM 代码片段中使用 ADDS 和 SUBS,而不是我期望的 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 '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 命令而不是当前使用的 ADDS 和 SUBS。 ADDS 和 SUBS 命令,afaik,更新 APSR 标志 NZCV,供以后使用。但是,正如您在上面的代码片段中看到的那样,更新后的值没有被使用。那么这个命令还有其他的用处吗?
算术指令(ADD
、SUB
等)不修改状态标志,这与更新条件的比较指令(CMP
、TEQ
)不同默认情况下的标志。但是,将 S
添加到算术指令(ADDS
、SUBS
等)将根据运算结果更新条件标志。这是对算术指令使用 S
的唯一要点,因此如果不检查 cf,则没有理由使用 ADDS
而不是 ADD
.
有更多代码附加到指令(link),以达到不同的目的,例如CC
(条件标志C=0),因此:
ADDCC
:如果进位状态位设置为0则执行操作
ADDCCS
:如果进位状态位设置为0,则执行操作,然后更新状态标志(如果C=1,则状态标志不被覆盖)。
从循环的角度来看,是否更新条件标志没有区别。以ARMv6-M为例,ADDS
和ADD
需要1个周期。
放弃使用 ADD
可能看起来像是一个懒惰的选择,因为 ADD
在某些情况下非常有用。更进一步,考虑这些例子:
SUBS r0, r0, #1
ADDS r0, r0, #2
BNE go_wherever
和
SUBS r0, r0, #1
ADD r0, r0, #2
BNE go_wherever
可能会产生不同的行为。
正如 old_timer 指出的那样,UAL becomes quite relevant on this topic. Talking about the unified language, the preferred syntax is ADDS
, instead of ADD
(link)。因此,如果目的是为 Thumb and/or ARM(使用 UAL)进行组装,则 OP 的代码绝对可以(甚至推荐)。
不带标志更新的 ADD 在某些 cortex-ms 上不可用。如果您查看指令集的 arm 文档(在使用汇编语言时总是一个好主意)用于通用用例,直到 armv7-m(cortex-m3、cortex-m4、cortex-m7)上的 thumb2 扩展才可用). cortex-m0 和 cortex-m0+ 以及一般广泛的兼容性代码(将使用 armv4t 或 armv6-m)没有 add without flags 选项。所以也许这就是原因。
另一个原因可能是获得 16 位指令而不是 32 位指令,但这是一个滑坡,因为它更多地涉及汇编器及其语法(语法由汇编器定义,汇编器是处理汇编的程序语言,而不是目标)。例如不是语法统一 gas:
.thumb
add r1,r2,r3
Disassembly of section .text:
00000000 <.text>:
0: 18d1 adds r1, r2, r3
反汇编程序知道现实,但汇编程序不知道:
so.s: Assembler messages:
so.s:2: Error: instruction not supported in Thumb16 mode -- `adds r1,r2,r3'
但是
.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
所以在这种情况下并不滑,但是使用统一语法你开始进入 blahw,blah.w,blah,键入语法并且必须回头检查以查看你想要的指令是正在生成。非统一也有自己的游戏,当然所有这些都是特定于汇编程序的。
我怀疑他们要么选择他们唯一的选择,要么使用更小、更兼容的指令,尤其是如果这是 class 或文本,越兼容越好。