148

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
  • 205,541
  • 37
  • 345
  • 415
ZelluX
  • 69,107
  • 19
  • 71
  • 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
  • 2
    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

230

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
  • 4,001
  • 3
  • 20
  • 21
  • 18
    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 OurBigBook.com Jun 26 '19 at 15:21
  • 1
    Can you do the reverse to optimise a single function only @CiroSantilliOurBigBook.com – rollsch Dec 11 '22 at 17:35
  • 1
    @rollsch I'd try `pragma GCC optimize ("O3")`: https://stackoverflow.com/questions/47222127/what-does-pragma-gcc-optimize-o3-mean – Ciro Santilli OurBigBook.com Dec 11 '22 at 19:38
175

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,883
  • 2
  • 27
  • 40
  • 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
114

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
  • 205,541
  • 37
  • 345
  • 415
  • 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
  • 3
    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
  • 3
    @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
  • 2
    *"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
  • 4
    @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
  • then why call it "volatile"...it really means the opposite of "exactly what we want" or "strict" – pf12345678910 Jul 11 '23 at 13:24
  • @pf12345678910: One reason why access is strict is because the underlying memory may change depending on when it is read. In other words, it is a “volatile” memory location that may change even when you don’t write to it. Because the variable is volatile, the access must be done in a precise, strict way. – Dietrich Epp Jul 11 '23 at 18:17
  • no I mean volatile means it will evaporate, which is the opposite of strict – pf12345678910 Jul 13 '23 at 12:35
  • @pf12345678910: The variable is volatile. If you write a value to it, you might read a **different** value back. The value that you wrote evaporated, because the variable is volatile. – Dietrich Epp Jul 13 '23 at 12:49
  • With nonvolatile memory, when you write a value, you get the same value back afterwards. It sticks around. – Dietrich Epp Jul 13 '23 at 12:49