A First-Principles-Driven Life
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的情况:

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
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."

Tags: system programming c programming
Creative Commons License
A First-Principles-Driven Life by Miao, ZhiCheng is licensed under a Creative Commons Attribution 3.0 License.