打印
[STM32F1]

keil中查看C语言对应汇编语言问题

[复制链接]
7221|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nikiski|  楼主 | 2015-6-16 19:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在keil上运行一段GPIO的程序,查看C语言及对应的汇编程序如下:
0x0800028A 2120      MOVS     r1,#0x20
0x0800028C 4811      LDR      r0,[pc,#68]  ; @0x080002D4
0x0800028E F000F935  BL.W     GPIO_ResetBits (0x080004FC)
    17:                 GPIO_SetBits(GPIOD,GPIO_Pin_3);
0x08000292 2108      MOVS     r1,#0x08
0x08000294 480E      LDR      r0,[pc,#56]  ; @0x080002D0
0x08000296 F000F92F  BL.W     GPIO_SetBits (0x080004F8)
    18:                 delay(6000000);//0.5s
0x0800029A 480F      LDR      r0,[pc,#60]  ; @0x080002D8
0x0800029C F000F81E  BL.W     delay (0x080002DC)
    19:                 GPIO_ResetBits(GPIOD,GPIO_Pin_6);
0x080002A0 2140      MOVS     r1,#0x40
0x080002A2 480B      LDR      r0,[pc,#44]  ; @0x080002D0
0x080002A4 F000F92A  BL.W     GPIO_ResetBits (0x080004FC)
    20:             GPIO_SetBits(GPIOB,GPIO_Pin_5);
0x080002A8 2120      MOVS     r1,#0x20
0x080002AA 480A      LDR      r0,[pc,#40]  ; @0x080002D4
0x080002AC F000F924  BL.W     GPIO_SetBits (0x080004F8)
    21:                 delay(6000000);
0x080002B0 4809      LDR      r0,[pc,#36]  ; @0x080002D8
0x080002B2 F000F813  BL.W     delay (0x080002DC)
    22:                 GPIO_ResetBits(GPIOD,GPIO_Pin_3);
0x080002B6 2108      MOVS     r1,#0x08
0x080002B8 4805      LDR      r0,[pc,#20]  ; @0x080002D0
0x080002BA F000F91F  BL.W     GPIO_ResetBits (0x080004FC)
    23:                 GPIO_SetBits(GPIOD,GPIO_Pin_6);
0x080002BE 2140      MOVS     r1,#0x40
0x080002C0 4803      LDR      r0,[pc,#12]  ; @0x080002D0
0x080002C2 F000F919  BL.W     GPIO_SetBits (0x080004F8)
    24:                 delay(6000000);//0.5s
0x080002C6 4804      LDR      r0,[pc,#16]  ; @0x080002D8
0x080002C8 F000F808  BL.W     delay (0x080002DC)
0x080002CC E7DD      B        0x0800028A
0x080002CE 0000      MOVS     r0,r0
0x080002D0 1400      ASRS     r0,r0,#16
0x080002D2 4001      ANDS     r1,r1,r0
0x080002D4 0C00      LSRS     r0,r0,#16
0x080002D6 4001      ANDS     r1,r1,r0
0x080002D8 8D80      LDRH     r0,[r0,#0x2C]
0x080002DA 005B      LSLS     r3,r3,#1
     7:         for(;nCount!=0;nCount--);
0x080002DC E000      B        0x080002E0
0x080002DE 1E40      SUBS     r0,r0,#1
0x080002E0 2800      CMP      r0,#0x00
0x080002E2 D1FC      BNE      0x080002DE
     8: }
0x080002E4 4770      BX       lr
0x080002E6 0000      MOVS     r0,r0
    71: {
    72:   /* Check the parameters */
    73:   assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    74:   
0x080002E8 B510      PUSH     {r4,lr}
0x080002EA 4604      MOV      r4,r0
    75:   if (GPIOx == GPIOA)
    76:   {
0x080002EC 48C7      LDR      r0,[pc,#796]  ; @0x0800060C
0x080002EE 4284      CMP      r4,r0
0x080002F0 D108      BNE      0x08000304
    77:     RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, ENABLE);
0x080002F2 2101      MOVS     r1,#0x01
0x080002F4 2004      MOVS     r0,#0x04
0x080002F6 F000FB1B  BL.W     RCC_APB2PeriphResetCmd (0x08000930)
    78:     RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, DISABLE);
    79:   }
0x080002FA 2100      MOVS     r1,#0x00
0x080002FC 2004      MOVS     r0,#0x04
0x080002FE F000FB17  BL.W     RCC_APB2PeriphResetCmd (0x08000930)
0x08000302 E046      B        0x08000392
    80:   else if (GPIOx == GPIOB)
    81:   {
0x08000304 48C2      LDR      r0,[pc,#776]  ; @0x08000610
0x08000306 4284      CMP      r4,r0
0x08000308 D108      BNE      0x0800031C
    82:     RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, ENABLE);
0x0800030A 2101      MOVS     r1,#0x01
0x0800030C 2008      MOVS     r0,#0x08
0x0800030E F000FB0F  BL.W     RCC_APB2PeriphResetCmd (0x08000930)
    83:     RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, DISABLE);
    84:   }
0x08000312 2100      MOVS     r1,#0x00
0x08000314 2008      MOVS     r0,#0x08
0x08000316 F000FB0B  BL.W     RCC_APB2PeriphResetCmd (0x08000930)
0x0800031A E03A      B        0x08000392
有几个问题还请大神解答
1. 汇编格式问题:每条汇编语句均由0x08000XXX XXXX(XXXX)构成,前面的8位16进制地址是否就是指令的存储位置?后面的4位(有时是8位)16进制是不是机器码?
2. 比如
17:                 GPIO_SetBits(GPIOD,GPIO_Pin_3);
0x08000292 2108      MOVS     r1,#0x08
0x08000294 480E      LDR      r0,[pc,#56]  ; @0x080002D0
0x08000296 F000F92F  BL.W     GPIO_SetBits (0x080004F8)

执行LDR      r0,[pc,#56]  时,pc的值是否为0x08000294?之后的注释@0x080002D0这个地址代表什么含义?0x080002D0+(#56)=0x080002CC,相差了4个地址。R0执行完这条语句后其中的值是多少呢?
3. 凡是执行delay(6000000);汇编代码对应会跳到delay (0x080002DC),是否跳到0x080002DC执行相应语句?
0x080002DC E000      B        0x080002E0
0x080002E0 2800      CMP      r0,#0x00 执行delay函数时,R0的初值是在哪条语句被赋值的?

求大神解答!

沙发
icecut| | 2015-6-16 20:33 | 只看该作者
看一下 arm 的汇编 指令代码

@后面是结果啊....

使用特权

评论回复
板凳
diweo| | 2015-6-16 21:47 | 只看该作者
本帖最后由 diweo 于 2015-6-16 21:52 编辑

  这不是很清楚的么? 。
18:                 delay(6000000);//0.5s
0x0800029A 480F      LDR      r0,[pc,#60]  ; @0x080002D8
0x0800029C F000F81E  BL.W     delay (0x080002DC)

0x080002D8那里其实只是个数值,那条指令其实不是指令。那这个数值是多少呢?要结合0x080002DA看。0x005B8D80=6000000




使用特权

评论回复
地板
wowow| | 2015-6-16 22:10 | 只看该作者
C编译成机器码的结果都是一小段代码+一小段数据,这一小段代码中用到的常量,例如delay(6000000)里的6000000,就会集中放在代码段之后,引用时用类似如下指令加载到寄存器中使用:
LDR      r0,[pc,#60]  ; @0x080002D8
反汇编没那么智能,会将这些数据错反汇编成指令,但这些“指令”会被跳过去的,不会被执行的。有些反汇编工具会区分出代码与数据。
至于为什么0x080002D0+(#56)=0x080002CC,相差了4个地址,是因为执行到当前指令时,PC的值已经增加了4,也就是说PC指向下一条指令,而非当前指令。
详细信息还是要看汇编指令集的文档。

使用特权

评论回复
5
nikiski|  楼主 | 2015-6-17 11:35 | 只看该作者
diweo 发表于 2015-6-16 21:47
这不是很清楚的么? 。
18:                 delay(6000000);//0.5s
0x0800029A 480F      LDR      r0, ...

那是不是r0加载的就是0x080002D8的数据?和程序段里的Ldrh r0,[r0,#0x2c]这句指令有关系吗?

使用特权

评论回复
6
nikiski|  楼主 | 2015-6-17 12:13 | 只看该作者
diweo 发表于 2015-6-16 21:47
这不是很清楚的么? 。
18:                 delay(6000000);//0.5s
0x0800029A 480F      LDR      r0, ...

是不是可以理解为 汇编语句和这行所对应的8位16进制地址是没有关系的,汇编语句并没有存到这些地址中?

使用特权

评论回复
7
diweo| | 2015-6-17 18:31 | 只看该作者
本帖最后由 diweo 于 2015-6-17 18:36 编辑

同样是0x8D80,关键在于怎么处理它。
在这里,它就是数据,只不过它刚好和 LDRH     r0,[r0,#0x2C]对应的代码是一样的。
4楼说的蛮清楚了,之所以把它显示成指令形式,只不过是Keil自带的反汇编工具还不够智能化。

简单来说,不管程序怎么运行,PC指针永远不会指向它,因为它是数据,而不是指令。

*****************************************
0x080002D8 8D80      LDRH     r0,[r0,#0x2C]
0x080002DA 005B      LSLS     r3,r3,#1
*****************************************
0x0800029A 480F      LDR      r0,[pc,#60]  ; @0x080002D8
LDR会加载 0x080002D8为起始地址的4个字节,其实就是0x005B8D80,就是6000000.

使用特权

评论回复
8
nikiski|  楼主 | 2015-6-17 21:19 | 只看该作者
diweo 发表于 2015-6-17 18:31
同样是0x8D80,关键在于怎么处理它。
在这里,它就是数据,只不过它刚好和 LDRH     r0,[r0,#0x2C]对应的代 ...

恩 多谢解答
还有一个问题:
    17:                 GPIO_SetBits(GPIOD,GPIO_Pin_3);
0x08000292 2108      MOVS     r1,#0x08
0x08000294 480E      LDR      r0,[pc,#56]  ; @0x080002D0
0x08000296 F000F92F  BL.W     GPIO_SetBits (0x080004F8)
18:                 delay(6000000);//0.5s
0x0800029A 480F      LDR      r0,[pc,#60]  ; @0x080002D8
0x0800029C F000F81E  BL.W     delay (0x080002DC)
19:                 GPIO_ResetBits(GPIOD,GPIO_Pin_6);
0x080002A0 2140      MOVS     r1,#0x40
0x080002A2 480B      LDR      r0,[pc,#44]  ; @0x080002D0
0x080002A4 F000F92A  BL.W     GPIO_ResetBits (0x080004FC)

    20:             GPIO_SetBits(GPIOB,GPIO_Pin_5);
0x080002A8 2120      MOVS     r1,#0x20
0x080002AA 480A      LDR      r0,[pc,#40]  ; @0x080002D4
0x080002AC F000F924  BL.W     GPIO_SetBits (0x080004F8)
    21:                 delay(6000000);
0x080002B0 4809      LDR      r0,[pc,#36]  ; @0x080002D8
0x080002B2 F000F813  BL.W     delay (0x080002DC)

0x080002D0 1400      ASRS     r0,r0,#16
0x080002D2 4001      ANDS     r1,r1,r0
0x080002D4 0C00      LSRS     r0,r0,#16
0x080002D6 4001      ANDS     r1,r1,r0

0x080004F4 B280      UXTH     r0,r0
   311: }
   312:  
   313: /**
   314:   * @brief  Sets the selected data port bits.
   315:   * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
   316:   * @param  GPIO_Pin: specifies the port bits to be written.
   317:   *   This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
   318:   * @retval None
   319:   */
   320: void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
   321: {
   322:   /* Check the parameters */
   323:   assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
   324:   assert_param(IS_GPIO_PIN(GPIO_Pin));
   325:   
0x080004F6 4770      BX       lr
   326:   GPIOx->BSRR = GPIO_Pin;
0x080004F8 6101      STR      r1,[r0,#0x10]
   327: }
问题有以下3个:
1.每次调用函数GPIO_SetBits(GPIOX,GPIO_Pin_X)时,先要将r0赋值,r0的值是否和GPIO的选择及端口有关?比如0x080002D0 1400 0x080002D2 4001中的0X40011400以及0x080002D4 0C00 0x080002D6 4001中的0X40010C00.  
2.0x08000296 F000F92F  BL.W     GPIO_SetBits (0x080004F8)语句中的0x080004F8地址是否就是调用函数 GPIO_SetBits的入口地址?但是GPIO_SetBits函数入口出现在0x080004F8的前面地址中。调用GPIO_SetBits函数时BL.W指令是不是用link register保存了下条语句delay的地址,在0x080004F6 4770      BX       lr中从函数GPIO_SetBits返回,继而跳到lr保存的地址进行指令执行

3.在给r0赋值的时候,高地址给r0的高4位,相邻的低地址给r0的低4位,这是不是和存储的小端模式和大端模式相关?(endianess)


谢谢指导!

使用特权

评论回复
9
nikiski|  楼主 | 2015-6-17 21:20 | 只看该作者
wowow 发表于 2015-6-16 22:10
C编译成机器码的结果都是一小段代码+一小段数据,这一小段代码中用到的常量,例如delay(6000000)里的600000 ...

谢谢解答!

使用特权

评论回复
10
wowow| | 2015-6-18 00:29 | 只看该作者
8楼问题1: c语言转编译成汇编以后, 函数调用里面的参数是通过寄存器和stack来传递的, 参数比较少的时候就放在寄存器里, 参数比较多放不下的就放在堆栈里. 如何放跟参数的数量位宽都有关系. 你这个例子只有一个32位的参数就是放在r0进去的.更详细的内容你就要查编译器的手册了

使用特权

评论回复
11
wowow| | 2015-6-18 00:29 | 只看该作者
其他两个问题你的理解是正确的

使用特权

评论回复
12
diweo| | 2015-6-18 08:02 | 只看该作者
nikiski 发表于 2015-6-17 21:19
恩 多谢解答
还有一个问题:
    17:                 GPIO_SetBits(GPIOD,GPIO_Pin_3); 0x08000292 2108 ...

大致上:
函数调用时,参数是通过工作寄存器传递的。CM3一般用r0~r7,具体用哪个,由编译器看情况决定。一般是按着顺序来的。
如果参数太多了,寄存器不够用了,就用栈来传递了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

23

帖子

0

粉丝