【问题标题】:Switch statement AVR-GCC切换语句 AVR-GCC
【发布时间】:2013-01-31 18:45:11
【问题描述】:

嘿,这只是我用 c 编写的一个简单程序,在 avr-gcc 下编译。 对应的汇编代码也贴出来了。

仍然无法理解 switch 语句的汇编代码在做什么,任何帮助都会很棒。谢谢。

int main()
{

char myinput;

printf("Which option will you choose:\n");
printf("a) Program 1 \n");
printf("b) Program 2 \n");
scanf("%c", &myinput);

switch (myinput)
    {
                case 'a':
                printf("Run program 1\n");
                break;
        case 'b':
            {
                printf("Run program 2\n");
                printf("Please Wait\n");
                break;
            }
        default:
                printf("Invalid choice\n");
                break;
    }
    return 0;

返回 0;

}

汇编代码:

    switch (myinput)
+00000147:   900F        POP       R0             Pop register from stack
+00000148:   900F        POP       R0             Pop register from stack
+00000149:   900F        POP       R0             Pop register from stack
+0000014A:   900F        POP       R0             Pop register from stack
+0000014B:   8189        LDD       R24,Y+1        Load indirect with displacement
+0000014C:   3681        CPI       R24,0x61       Compare with immediate
+0000014D:   F019        BREQ      PC+0x04        Branch if equal
+0000014E:   3682        CPI       R24,0x62       Compare with immediate
+0000014F:   F459        BRNE      PC+0x0C        Branch if not equal
+00000150:   C003        RJMP      PC+0x0004      Relative jump
22:                         printf("Run program 1\n");
+00000151:   E38D        LDI       R24,0x3D       Load immediate
+00000152:   E092        LDI       R25,0x02       Load immediate
+00000153:   C009        RJMP      PC+0x000A      Relative jump
26:                         printf("Run program 2\n");
+00000154:   E48B        LDI       R24,0x4B       Load immediate
+00000155:   E092        LDI       R25,0x02       Load immediate
+00000156:   940E02A9    CALL      0x000002A9     Call subroutine
27:                         printf("Please Wait\n");
+00000158:   E589        LDI       R24,0x59       Load immediate
+00000159:   E092        LDI       R25,0x02       Load immediate
+0000015A:   C002        RJMP      PC+0x0003      Relative jump
31:                         printf("Invalid choice\n");
+0000015B:   E685        LDI       R24,0x65       Load immediate
+0000015C:   E092        LDI       R25,0x02       Load immediate
+0000015D:   940E02A9    CALL      0x000002A9     Call subroutine
38:       }
+0000015F:   E080        LDI       R24,0x00       Load immediate
+00000160:   E090        LDI       R25,0x00       Load immediate
+00000161:   900F        POP       R0             Pop register from stack
+00000162:   91CF        POP       R28            Pop register from stack
+00000163:   91DF        POP       R29            Pop register from stack
+00000164:   9508        RET                      Subroutine return

谢谢大家。

【问题讨论】:

标签: assembly switch-statement avr avr-gcc


【解决方案1】:

以下是这些行的含义的详细解释:

+0000014B:   8189        LDD       R24,Y+1        Load indirect with displacement

这里 myinput 的值从内存复制到寄存器 r24。在内存中,它位于地址 Y+1。 Y 中的值是 myinput 字符之前的字节地址。

+0000014C:   3681        CPI       R24,0x61       Compare with immediate
+0000014D:   F019        BREQ      PC+0x04        Branch if equal

这里将 myinput 的值(在 r24 中)与 0x61='a'(在 ascii 中)进行比较。如果它们相等(myinput=='a'),则继续执行+00000151:(0x14D+0x4=0x0x151)。否则继续执行下一条指令。

+0000014E:   3682        CPI       R24,0x62       Compare with immediate
+0000014F:   F459        BRNE      PC+0x0C        Branch if not equal
+00000150:   C003        RJMP      PC+0x0004      Relative jump

这里再次将 myinput 的值(在 r24 中)与 0x62='b'(在 ASCII 中)进行比较,但现在只有当它们 NOT 相等(默认情况)时才会继续执行+0000015B: (0x14F+0xC=0x0x15B)。否则 (myinput=='b') 下一条指令是跳转到 +00000154: (0x150+0x4=0x0x154)。

22:                         printf("Run program 1\n");
+00000151:   E38D        LDI       R24,0x3D       Load immediate
+00000152:   E092        LDI       R25,0x02       Load immediate
+00000153:   C009        RJMP      PC+0x000A      Relative jump

在“a”情况下,printf 命令的参数(实际上是字符串的内存地址)存储在 r25:r24 中。然后执行分支到+0000015D:处的switch语句结束之前的最后一个printf调用。

26:                         printf("Run program 2\n");
+00000154:   E48B        LDI       R24,0x4B       Load immediate
+00000155:   E092        LDI       R25,0x02       Load immediate
+00000156:   940E02A9    CALL      0x000002A9     Call subroutine
27:                         printf("Please Wait\n");
+00000158:   E589        LDI       R24,0x59       Load immediate
+00000159:   E092        LDI       R25,0x02       Load immediate
+0000015A:   C002        RJMP      PC+0x0003      Relative jump

在 'b'-case 中,与之前类似,要打印的字符串的地址存储在 r25:r24 中。然后执行调用位于内存地址0x000002A9 的 printf 子例程。然后将第二个字符串的地址加载到 r25:r24 并执行跳转到 switch 语句结束之前的最后一次 printf 调用+0000015E:

这里可以很好地看到,字符串存储在内存中,因为第一个字符串是 14 (0xE) 字节 (chars) 长,位于 0x3D02;下一个字符串位于0x3D02+0xE=0x4D02!!

31:                         printf("Invalid choice\n");
+0000015B:   E685        LDI       R24,0x65       Load immediate
+0000015C:   E092        LDI       R25,0x02       Load immediate
+0000015D:   940E02A9    CALL      0x000002A9     Call subroutine

在默认情况下,和以前一样,字符串被加载到 r25:r24 并调用 printf。

38:       }
+0000015F:   E080        LDI       R24,0x00       Load immediate
+00000160:   E090        LDI       R25,0x00       Load immediate
+00000161:   900F        POP       R0             Pop register from stack
+00000162:   91CF        POP       R28            Pop register from stack
+00000163:   91DF        POP       R29            Pop register from stack
+00000164:   9508        RET                      Subroutine return

清理并返回...

我希望这可以帮助你一点(即使很晚),如果没有,它可以帮助有人在搜索中找到这篇文章,同时遇到类似的问题!

【讨论】:

    【解决方案2】:

    偏移量 0000014C 将“myInput”与“a”(ASCII 97,十六进制 0x61)进行比较,如果相等则跳转到偏移量 00000151(在 BREQ 点为 PC+4,偏移量 0000014D,因为管道的 FETCH 部分是在执行部分之前)。

    如果比较失败,则与“b”(偏移量 0000014E)进行比较,并相应地再次分支。

    如果失败,我们跳到最后一种情况。

    请注意,我们如何调用 printf (CALL 0x2A9) 以及它返回的位置有一些微妙之处。

    【讨论】:

      猜你喜欢
      • 2013-01-14
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多