134

In order to make a page dirty (switching on the dirty bit in the page table entry), I touch the first bytes of the page like this:

pageptr[0] = pageptr[0];

But in practice gcc will ignore the statement by dead store elimination. In order to prevent gcc optimizing it, I re-write the statement as follows:

volatile int tmp;
tmp = pageptr[0];
pageptr[0] = tmp;

It seems the trick works, but somewhat ugly. I would like to know is there any directives or syntax which has the same effect? And I don't want to use a -O0 flag, since it will bring great performance penalty as well.

Dietrich Epp
  • 194,726
  • 35
  • 326
  • 406
ZelluX
  • 63,444
  • 18
  • 69
  • 104
  • 9
    @Mark -O0 will stop the optimization, but also slows down program performance. I just want to prevent optimization of this code snippet :P – ZelluX Feb 08 '10 at 05:53
  • 1
    I would like to add that in the past, even using `-O0` did not prevent dead code "optimization", e.g., when GCC detects some code has no effect, it simply removes it. AFAIK this is a stage even before `-O0`... But that's just my experience – smoothware Mar 05 '20 at 09:01

3 Answers3

214

You can use

#pragma GCC push_options
#pragma GCC optimize ("O0")

your code

#pragma GCC pop_options

to disable optimizations since GCC 4.4.

See the GCC documentation if you need more details.

Plow
  • 3,811
  • 3
  • 19
  • 21
  • 14
    It is worth noting however that this only works on entire functions, not on specific statments: https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Function-Specific-Option-Pragmas.html "Each function that is defined after this point is as if attribute((optimize("STRING"))) was specified for that function.". – Ciro Santilli Путлер Капут 六四事 Jun 26 '19 at 15:21
163

Instead of using the new pragmas, you can also use __attribute__((optimize("O0"))) for your needs. This has the advantage of just applying to a single function and not all functions defined in the same file.

Usage example:

void __attribute__((optimize("O0"))) foo(unsigned char data) {
    // unmodifiable compiler code
}
Toni
  • 35
  • 7
FRob
  • 3,705
  • 1
  • 26
  • 39
  • 3
    What if I am not using a`-Olevel`option but I used the individuals options it turns on separetely? *(In my case, I can't determine which is the individual optimization option which is breaking the code)*. – user2284570 Apr 16 '15 at 11:26
  • 1
    None of the recommendations around volatile work any more. GCC compiler headers cannot handle volatile + O0. While loops are optimized out as -faggressive-loop-optimization is default, only O0 blocks this. For these reasons, O0 and no volatile in the unoptimized function is now the correct answer. – rickfoosusa Sep 16 '20 at 21:03
110

Turning off optimization fixes the problem, but it is unnecessary. A safer alternative is to make it illegal for the compiler to optimize out the store by using the volatile type qualifier.

// Assuming pageptr is unsigned char * already...
unsigned char *pageptr = ...;
((unsigned char volatile *)pageptr)[0] = pageptr[0];

The volatile type qualifier instructs the compiler to be strict about memory stores and loads. One purpose of volatile is to let the compiler know that the memory access has side effects, and therefore must be preserved. In this case, the store has the side effect of causing a page fault, and you want the compiler to preserve the page fault.

This way, the surrounding code can still be optimized, and your code is portable to other compilers which don't understand GCC's #pragma or __attribute__ syntax.

Dietrich Epp
  • 194,726
  • 35
  • 326
  • 406
  • 3
    I would say this is preferable to turning off optimizations. You can still benefit from other optimizations using this method. – Ben S Feb 08 '10 at 05:54
  • Do you really need to do a load from the page, though? Surely just the store would do: `*(volatile int *)pageptr = 0;` – caf Feb 08 '10 at 05:56
  • You need to modify the program which will make it humanly unreadable. – Phong Feb 08 '10 at 05:56
  • @caf - your version could cause the contents of the page to change. The OP implies that the page contents should not change. – R Samuel Klatchko Feb 08 '10 at 06:31
  • True, I read something into it that wasn't there (of course, the given solution here also would change the page, if the type of `pageptr[0]` is wider than `char`). – caf Feb 08 '10 at 06:50
  • @caf - missed the int/char issue. @DietrichEpp - it looks like your fix should be `*(unsigned char volatile *)pageptr = *(unsigned char *)pageptr;` – R Samuel Klatchko Feb 08 '10 at 07:22
  • 3
    Dietrich Epp's solution is not working under **ARM4.1 compiler**. Even ZelluX's solution is not working. Alternative method to make this work for ARM4.1 is in ZelluX's solution, make '**temp**' a **global volatile variable**. – Preetham Nanjappa Nov 30 '11 at 11:15
  • 2
    That's pretty bad for said compiler. – Alexey Frunze Nov 30 '11 at 11:25
  • This doesn't work for `GCC 6.2.0` with `-O2`. My code `volatile Object* obj = ...` and result `obj = ` – QuantumBlack Aug 14 '17 at 17:29
  • 2
    @Shocker: GCC can still optimize out the variable without optimizing out the actual memory access. Those are different issues. – Dietrich Epp Aug 14 '17 at 17:39
  • 1
    *"One purpose of volatile is to let the compiler know that the memory access has side effects..."* - Under GCC that is not true. The GCC folks state the purpose of `volatile` is for memory mapped hardware. From Ian Lance Taylor's blog on [volatile](https://www.airs.com/blog/archives/154): *"In summary, if you are using volatile for anything other than manipulating memory mapped hardware, or for very limited communication between threads, it is very likely that you are making a mistake. Think carefully about what volatile means and about what it does not mean."* – jww Jan 13 '18 at 08:54
  • 2
    @jww: this usage fits with what is described in that blog post. `volatile` means that the memory access must occur as written, which is exactly what we want. In other words, we have thought carefully about it, and it means what we think it means. – Dietrich Epp Jan 13 '18 at 19:37