CMP / BEQ无法正常工作总是分支(ARM)

时间:2014-11-08 00:31:50

标签: if-statement assembly arm

我对此非常生气,无法弄清楚为什么我的BEQ语句总是被执行。 程序应该替换位于内存中的char(RO中的地址)

_ should become +
C should become A
A should become B
B should become C

这是我到目前为止(对不起法国评论):

  MOV R11, #0                   ; Initialise le nombe de copie fait
  MOV R10, #43                  ; R10 = +
  MOV R9, #'_'                  ; R9 = _
  MOV R8, #'A'                  ; R8 = A
  MOV R7, #'B'                  ; R7 = B
  MOV R6, #'C'                  ; R6 = C



  TOP:                          
      LDRB R5, [R0, R11]         ; Copie element X dans R5

      CMP R5, R9
      BEQ PLUS

      CMP R5, R8
      BEQ A

      CMP R5, R7
      BEQ B

      CMP R5, R6
      BEQ C

      PLUS:                             ; Branchement si _
           STRB R10, [R0, R11]  
      A:                                ; Branchement si A
           STRB R8, [R0, R11]                                   
      B:                                ; Branchement si B
           STRB R7, [R0, R11]     
      C:                                ; Branchement si C
           STRB R6, [R0, R11]     

      ADDS R11, R11, #1           ; ++nbcopiefait
      CMP R11, R1                 ; Validation de la condition
  BNE TOP

2 个答案:

答案 0 :(得分:2)

显然不仅是C&#39 {s} switch()让人感到困惑...... 所以,你目前正在做的是相当于

for (size_t i = 0; i < n; i++)
{
  switch(chararray[i])
    {
      default:
      case '_': chararray[i] = '+';
      case 'C': chararray[i] = 'A';
      case 'A': chararray[i] = 'B';
      case 'B': chararray[i] = 'C';
    }
}

您在break;之后错过了case 编辑,因为我似乎必须让它变得非常明显:

for (size_t i = 0; i < n; i++)
{
  switch(chararray[i])
    {
      default:
        break;
      case '_': chararray[i] = '+';
        break;
      case 'C': chararray[i] = 'A';
        break;
      case 'A': chararray[i] = 'B';
        break;
      case 'B': chararray[i] = 'C';
        break;                     //unnecessary, but I put it in for regularity
    }
}

答案 1 :(得分:0)

要扩展EOF's answer,您可以通过逐个示例执行指令跟踪来查看正在发生的事情 - 调试器始终有帮助,但这很容易手动完成。让我们考虑几种不同的情况:

      Instruction            case char=='A'         case char=='Z'
      -------------------------------------------------------------------
      ...
      LDRB R5, [R0, R11]     executes, r5='A'       executes, r5='Z'
      CMP R5, R9             executes, flags=ne     executes, flags=ne
      BEQ PLUS               flags!=eq, not taken   flags!=eq, not taken
      CMP R5, R8             executes, flags=eq     executes, flags=ne
      BEQ A                  flags==eq, taken       flags!=eq, not taken
      CMP R5, R7                      /             executes, flags=ne
      BEQ B                          /              flags!=eq, not taken
      CMP R5, R6                    /               executes, flags=ne
      BEQ C                        /                flags!=eq, not taken
PLUS: STRB R10, [R0, R11]         V                 executes: oops!
A:    STRB R8, [R0, R11]     executes               executes: oops!
B:    STRB R7, [R0, R11]     executes: oops!        executes: oops!
C:    STRB R6, [R0, R11]     executes: oops!        executes: oops!
      ADDS R11, R11, #1      executes               executes
      ...

所以无论发生什么事,无论如何,一切都以“C”结束! (注意'A','B'和'C'有一个寄存器混合 - 如果你匹配r8,你跳转到存储r8等等。)实现等效的break是一个确保说明的情况当希望它们执行时跳过:

      ...
      CMP R5, R6
      BEQ C
      B LOOP             ; no match, skip everything
PLUS: STRB R10, [R0, R11]
      B LOOP             ; we've stored '_', skip 'B', 'C', and 'A'
A:    STRB R7, [R0, R11]
      B LOOP             ; we've stored 'B', skip 'C' and 'A'
B:    STRB R6, [R0, R11]
      B LOOP             ; we've stored 'C', skip 'A'
C:    STRB R8, [R0, R11] ; nothing to skip, just fall through to the loop
LOOP: ADDS R11, R11, #1
      ...

但请注意,与大多数体系结构不同,ARM的条件执行适用于大多数指令。因此,给定少量简单例程(1-3条指令)的另一种方法是实际删除所有分支,并让条件执行处理它:

...
LDRB R5, [R0, R11]
CMP R5, R9
STRBEQ R10, [R0, R11]
CMP R5, R8
STRBEQ R7, [R0, R11]
CMP R5, R7
STRBEQ R6, [R0, R11]
CMP R5, R6
STRBEQ R8, [R0, R11]
ADDS R11, R11, #1
...

这样,一切都会被“执行”,但任何未通过条件检查的商店都不会做任何事情。