22 Jul 2005
关于volatile
$gcc --version gcc (GCC) 4.0.0 20050519 (Red Hat 4.0.0-8) Copyright (C) 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#+name cat 1.c
int main() { int j=0; int i=0; for (i = 0; i < 0xBACCA; i++) j += i * i; }
$gcc -g -O0 1.c -o 1-O0 (gdb) disas main Dump of assembler code for function main: ...... 0x08048364 <main+28>: movl $0x0,0xfffffff8(%ebp) 0x0804836b <main+35>: movl $0x0,0xfffffffc(%ebp) 0x08048372 <main+42>: movl $0x0,0xfffffffc(%ebp) 0x08048379 <main+49>: jmp 0x804838e <main+70> 0x0804837b <main+51>: mov 0xfffffffc(%ebp),%eax 0x0804837e <main+54>: mov %eax,%edx 0x08048380 <main+56>: imul 0xfffffffc(%ebp),%edx 0x08048384 <main+60>: lea 0xfffffff8(%ebp),%eax 0x08048387 <main+63>: add %edx,(%eax) 0x08048389 <main+65>: lea 0xfffffffc(%ebp),%eax 0x0804838c <main+68>: incl (%eax) 0x0804838e <main+70>: cmpl $0xbacc9,0xfffffffc(%ebp) 0x08048395 <main+77>: jle 0x804837b <main+51> 0x08048397 <main+79>: leave 0x08048398 <main+80>: ret $gcc -g -O1 1.c -o 1-O1 (gdb) disas main Dump of assembler code for function main: 0x08048348 <main+0>: push %ebp 0x08048349 <main+1>: mov %esp,%ebp 0x0804834b <main+3>: sub $0x8,%esp 0x0804834e <main+6>: and $0xfffffff0,%esp 0x08048351 <main+9>: sub $0x10,%esp 0x08048354 <main+12>: mov $0xbacca,%eax 0x08048359 <main+17>: dec %eax 0x0804835a <main+18>: jne 0x8048359 <main+17> 0x0804835c <main+20>: leave 0x0804835d <main+21>: ret End of assembler dump.
#+name 2.c
int main() { volatile int j=0; int i=0; for (i = 0; i < 0xBACCA; i++) j += i * i; }
$gcc -g -O0 2.c -o 2-O0 (gdb) disas main Dump of assembler code for function main: ...... 0x08048364 <main+28>: movl $0x0,0xfffffff8(%ebp) 0x0804836b <main+35>: movl $0x0,0xfffffffc(%ebp) 0x08048372 <main+42>: movl $0x0,0xfffffffc(%ebp) 0x08048379 <main+49>: jmp 0x8048392 <main+74> 0x0804837b <main+51>: mov 0xfffffffc(%ebp),%eax 0x0804837e <main+54>: mov %eax,%edx 0x08048380 <main+56>: imul 0xfffffffc(%ebp),%edx 0x08048384 <main+60>: mov 0xfffffff8(%ebp),%eax 0x08048387 <main+63>: lea (%edx,%eax,1),%eax 0x0804838a <main+66>: mov %eax,0xfffffff8(%ebp) 0x0804838d <main+69>: lea 0xfffffffc(%ebp),%eax 0x08048390 <main+72>: incl (%eax) 0x08048392 <main+74>: cmpl $0xbacc9,0xfffffffc(%ebp) 0x08048399 <main+81>: jle 0x804837b <main+51> 0x0804839b <main+83>: leave 0x0804839c <main+84>: ret End of assembler dump. $gcc -g -O1 2.c -o 2-O1 (gdb) disas main Dump of assembler code for function main: 0x08048348 <main+0>: push %ebp 0x08048349 <main+1>: mov %esp,%ebp 0x0804834b <main+3>: sub $0x18,%esp 0x0804834e <main+6>: and $0xfffffff0,%esp 0x08048351 <main+9>: sub $0x10,%esp 0x08048354 <main+12>: movl $0x0,0xfffffffc(%ebp) 0x0804835b <main+19>: mov $0x0,%ecx 0x08048360 <main+24>: mov 0xfffffffc(%ebp),%edx 0x08048363 <main+27>: mov %ecx,%eax 0x08048365 <main+29>: imul %ecx,%eax 0x08048368 <main+32>: add %edx,%eax 0x0804836a <main+34>: mov %eax,0xfffffffc(%ebp) 0x0804836d <main+37>: inc %ecx 0x0804836e <main+38>: cmp $0xbacca,%ecx 0x08048374 <main+44>: jne 0x8048360 <main+24> 0x08048376 <main+46>: leave 0x08048377 <main+47>: ret
先分析-O0的情况:
- 这是没有volatile的版本:
0x08048364 <main+28>: movl $0x0,0xfffffff8(%ebp) j=0; 0x0804836b <main+35>: movl $0x0,0xfffffffc(%ebp) i=0; 0x08048372 <main+42>: movl $0x0,0xfffffffc(%ebp) for(i=0; 0x08048379 <main+49>: jmp 0x804838e <main+70> -> 0x0804837b <main+51>: mov 0xfffffffc(%ebp),%eax 0x0804837e <main+54>: mov %eax,%edx 0x08048380 <main+56>: imul 0xfffffffc(%ebp),%edx i*i->EDX 0x08048384 <main+60>: lea 0xfffffff8(%ebp),%eax EAX->j; 0x08048387 <main+63>: add %edx,(%eax) j+=EDX 0x08048389 <main+65>: lea 0xfffffffc(%ebp),%eax eax->i; 0x0804838c <main+68>: incl (%eax) ++i; 0x0804838e <main+70>: cmpl $0xbacc9,0xfffffffc(%ebp) 0x08048395 <main+77>: jle 0x804837b <main+51> ?i<0xbacca 0x08048397 <main+79>: leave 0x08048398 <main+80>: ret
- 再看有volatile的版本:
0x08048364 <main+28>: movl $0x0,0xfffffff8(%ebp) j=0;(volatile) 0x0804836b <main+35>: movl $0x0,0xfffffffc(%ebp) i=0; 0x08048372 <main+42>: movl $0x0,0xfffffffc(%ebp) for(i=0; 0x08048379 <main+49>: jmp 0x8048392 <main+74> -> 0x0804837b <main+51>: mov 0xfffffffc(%ebp),%eax 0x0804837e <main+54>: mov %eax,%edx i*i->EDX, 0x08048380 <main+56>: imul 0xfffffffc(%ebp),%edx 到这里和上面都是一样的 0x08048384 <main+60>: mov 0xfffffff8(%ebp),%eax EAX=j; 0x08048387 <main+63>: lea (%edx,%eax,1),%eax 这里有点花哨,就是%edx+%eax*1,j+=i*i的意思 0x0804838a <main+66>: mov %eax,0xfffffff8(%ebp) 0x0804838d <main+69>: lea 0xfffffffc(%ebp),%eax 0x08048390 <main+72>: incl (%eax) 0x08048392 <main+74>: cmpl $0xbacc9,0xfffffffc(%ebp) 0x08048399 <main+81>: jle 0x804837b <main+51> 0x0804839b <main+83>: leave 0x0804839c <main+84>: ret
再看这里 http://www.linuxdevices.com/articles/AT5980346182.html 关于volatile的介绍:
The reason to use volatile is to ensure that the compiler generates code to re-load a data item each time it is referenced in your program.
就不难理解上面的差异了,volatile的j每次都是存入到寄存器中而不是由寄存器指向其地址,即所谓的 "re-load a data item each time it's refenced."