在ARM汇编中使用ADDS指令而不使用ADD指令的原因是什么?

时间:2019-01-29 09:35:47

标签: arm cortex-m

我的课程笔记始终在其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,以供以后使用。但是,如您在上面的片段中所见,未使用更新的值。那么该命令还有其他实用程序吗?

2 个答案:

答案 0 :(得分:4)

与比较指令(ADDSUB)不同,算术指令(CMPTEQ等)不会修改状态标志,而比较指令(SADDS)则通过默认。但是,将SUBS添加到算术指令(SADDS等)将根据运算结果更新条件标志。那是对算术指令使用ADD的唯一目的,因此,如果不检查cf,则没有理由使用CC代替ADDCC


为了实现不同的目的,有更多代码要附加到指令(link)上,例如ADDCCS(条件标志C = 0),因此:

ADDS:如果进位状态位设置为0,则执行操作。

ADD:如果进位状态位设置为0,然后执行操作,然后更新状态标志(如果C = 1,则状态标志不会被覆盖)。


从循环的角度来看,更新条件标志与否之间没有区别。以ARMv6-M为例,ADDADD将花费1个周期。


丢弃 SUBS r0, r0, #1 ADDS r0, r0, #2 BNE go_wherever 似乎是一个懒惰的选择,因为在某些情况下 SUBS r0, r0, #1 ADD r0, r0, #2 BNE go_wherever 很有用。更进一步,请考虑以下示例:

ADDS

ADD

可能会产生不同的行为。


正如old_timer所指出的,UAL在此主题上变得非常相关。关于统一语言,首选语法是date_filter = date.today() - relativedelta(months=3) courses = Course.objects.filter(models.Q(courseday__date__gt=date_filter) | models.Q(courseday__isnull=True)).distinct() courses = list(courses) courses.sort(key=lambda x: (x.get_first_date() is None, x.custom_id), reverse=True) ,而不是SELECT id, values FROM ( SELECT *, row_number() OVER (PARTITION BY id ORDER BY values DESC) FROM table ) s WHERE row_number = 2 link)。因此,如果要为Thumb和/或ARM(使用UAL)进行汇编,则OP的代码绝对正确(甚至推荐)。

答案 1 :(得分:3)

没有标记更新的ADD在某些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

反汇编程序了解现实,但汇编程序却不知道:

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,键入语法的状态,并且不得不回头查看所生成的指令。非统一也有自己的游戏,当然,所有这些都是特定于汇编程序的。

我怀疑他们要么选择唯一的选择,要么使用更小,更兼容的指令,尤其是如果是类或文本,则兼容性越好越好。