Jak zapobiec optymalizacji niektórych instrukcji w C przez gcc?

107

Aby zabrudzić stronę (włączając brudny bit we wpisie tablicy stron), dotykam pierwszych bajtów strony w ten sposób:

pageptr[0] = pageptr[0];

Ale w praktyce gcc zignoruje stwierdzenie przez eliminację martwego magazynu. Aby zapobiec optymalizacji przez gcc, ponownie piszę instrukcję w następujący sposób:

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

Wygląda na to, że sztuczka działa, ale jest trochę brzydka. Chciałbym wiedzieć, czy są jakieś dyrektywy lub składnia, które mają taki sam skutek? I nie chcę używać -O0flagi, ponieważ przyniesie to również duży spadek wydajności.

ZelluX
źródło
8
@Mark -O0 zatrzyma optymalizację, ale także spowolni działanie programu. Chcę tylko zapobiec optymalizacji tego fragmentu kodu: P
ZelluX,
Dodam, że w przeszłości nawet użycie -O0nie zapobiegało „optymalizacji” martwego kodu, np. Gdy GCC wykryje jakiś kod nie daje efektu, po prostu go usuwa. AFAIK, to jest etap jeszcze wcześniej -O0... Ale to tylko moje doświadczenie
smoothware

Odpowiedzi:

91

Wyłączenie optymalizacji rozwiązuje problem, ale jest to niepotrzebne. Bezpieczniejszą alternatywą jest uniemożliwienie kompilatorowi optymalizacji magazynu przy użyciu volatilekwalifikatora typu.

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

volatileTyp kwalifikatora instruuje kompilator być ścisły o sklepach pamięci i obciążeń. Jednym z celów volatilejest poinformowanie kompilatora, że ​​dostęp do pamięci ma skutki uboczne i dlatego musi zostać zachowany. W takim przypadku efekt uboczny sklepu powoduje błąd strony i chcesz, aby kompilator zachował błąd strony.

W ten sposób otaczający kod może być nadal optymalizowany, a twój kod jest przenośny dla innych kompilatorów, które nie rozumieją GCC #pragmaani __attribute__składni.

Dietrich Epp
źródło
2
Powiedziałbym, że jest to lepsze rozwiązanie niż wyłączenie optymalizacji. Nadal możesz korzystać z innych optymalizacji przy użyciu tej metody.
Ben S,
3
Rozwiązanie Dietricha Eppa nie działa pod kompilatorem ARM4.1 . Nawet rozwiązanie ZelluX nie działa. Alternatywną metodą wykonania tego zadania dla ARM4.1 jest rozwiązanie ZelluX, uczynienie „ tempglobalną zmienną zmienną .
Oculus Dexter
1
To niedobrze dla wspomnianego kompilatora.
Alexey Frunze
1
@Shocker: GCC może nadal optymalizować zmienną bez optymalizacji rzeczywistego dostępu do pamięci. To są różne kwestie.
Dietrich Epp
2
@jww: to użycie pasuje do tego, co opisano w tym poście na blogu. volatileoznacza, że ​​dostęp do pamięci musi nastąpić zgodnie z zapisem, czyli dokładnie tym, czego chcemy. Innymi słowy, przemyśleliśmy to dokładnie i oznacza to, co myślimy, że oznacza.
Dietrich Epp
184

Możesz użyć

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

your code

#pragma GCC pop_options

aby wyłączyć optymalizacje od wersji GCC 4.4.

Zobacz dokumentację GCC, jeśli potrzebujesz więcej informacji.

Pług
źródło
3
Warto jednak zauważyć, że działa to tylko na całych funkcjach, a nie na konkretnych instrukcjach: gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/… "Każda funkcja zdefiniowana po tym punkcie jest atrybutem jakby (( Optimize („STRING”))) została określona dla tej funkcji. ”.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
134

Zamiast korzystać z nowych pragm, możesz również użyć ich __attribute__((optimize("O0")))do swoich potrzeb. Ma to tę zaletę, że stosuje się tylko do pojedynczej funkcji, a nie do wszystkich funkcji zdefiniowanych w tym samym pliku.

Przykład użycia:

void __attribute__((optimize("O0"))) foo(unsigned char data) {
    // unmodifiable compiler code
}
FRob
źródło
3
Co się stanie, jeśli nie używam -Olevelopcji, ale użyłem opcji indywidualnych, które włącza ona oddzielnie? (W moim przypadku nie mogę określić, która opcja optymalizacji indywidualnej psuje kod) .
user2284570