对LED点灯实验的C与汇编的深入分析,提及到volatile
查看点灯实验的反汇编代码,如下图所示:
下面是 C 代码,main 函数:
int main()
{unsigned int *pReg;/* 使能GPIOB */pReg = (unsigned int *)(0x40021000 + 0x18);*pReg |= (1<<3);/* 设置GPIOB0为输出引脚 */pReg = (unsigned int *)(0x40010C00 + 0x00);*pReg |= (1<<0);pReg = (unsigned int *)(0x40010C00 + 0x0C);while (1){/* 设置GPIOB0输出1 */*pReg |= (1<<0);delay(100000);/* 设置GPIOB0输出0 */*pReg &= ~(1<<0);delay(100000); }return 0;
}
查看有无 volatile 对 delay 函数的影响:
- 无 volatile,编译器自动优化了,为了提升速度,不需要将变量存入栈中,它直接存放在 CPU 的寄存器里:
void delay(int d) //参数的值已经存在r0里
{while(d--);
}
i.delay
delay0x08000138: bf00 .. NOP 0x0800013a: 1e01 .. SUBS r1,r0,#0 ;这个递减会影响到程序状态寄存器,不过这个不会改变变量值0x0800013c: f1a00001 .... SUB r0,r0,#1 ;这个指令才会让r0-10x08000140: d1fb .. BNE 0x800013a ;如果不等于0就跳到0x0800013a地址继续执行delay函数0x08000142: 4770 pG BX lr ;为0之后就跳转到lr寄存器
- 有 volatile,再搞个返回值,目的是清楚的看到函数结束后返回哪里。volatile 的作用是提醒编译器不需要优化我的代码,变量该保存到栈中就保存到栈中,这样,代码的可靠性就增加了,但是效率下降:
int delay(volatile int d)
{while(d--);return 0x55;
}
i.delay
delay0x08000138: b501 .. PUSH {r0,lr} ;PUSH就是保存到栈里面去,将r0和lr的值保存到栈里0x0800013a: bf00 .. NOP 0x0800013c: 9800 .. LDR r0,[sp,#0] ;再将栈里r0原本保存的值100000读到r0里0x0800013e: 1e41 A. SUBS r1,r0,#1 ;r1 = r0 - 1,并影响程序状态寄存器0x08000140: 9100 .. STR r1,[sp,#0] ;再把r1的值放入栈中,也就是刚刚存放的10000,经过-1操作后变成99990x08000142: 2800 .( CMP r0,#0 ;将r0的值与0比较0x08000144: d1fa .. BNE 0x800013c ;如果不为0,就跳转到0x0800013c地址上继续自减0x08000146: 2055 U MOVS r0,#0x55 ;如果为0,就将0x55放到r0寄存器0x08000148: bd08 .. POP {r3,pc} ;从栈中把之前的值恢复出来,lr的地址赋值给pc,delay函数结束后就返回lr保存的地址0x0800014a: 0000 .. MOVS r0,r0