2011-06-18 10 views
5

Czy kod samoczynnie modyfikujący jest możliwy w sposób przenośny w C?Czy standard C pozwala na kod samoczynnie modyfikujący?

Powód, dla którego pytam, polega na tym, że w pewnym sensie OOP polega na kodzie samo-modyfikującym (ponieważ kod wykonywany w czasie wykonywania jest faktycznie generowany jako dane, np. W v-table), a jednak, Wydaje się, że gdyby zaszło to zbyt daleko, uniemożliwiłoby to większość optymalizacji w kompilatorze.

Na przykład

void add(char *restrict p, char *restrict pAddend, int len) 
{ 
    for (int i = 0; i < len; i++) 
     p[i] += *pAddend; 
} 

optymalizacji kompilator może unieść *pAddend z pętli, ponieważ nie zakłócają p. Jednakże, nie jest to już poprawna optymalizacja samododującego kodu.

W ten sposób wydaje się, że C nie pozwala na samodefiniowanie kodu, ale czy nie oznacza to, że nie można wykonywać pewnych czynności, takich jak OOP w C? Czy C naprawdę obsługuje samodefiniujący się kod?

+2

C ma wskaźniki funkcyjne, które są wszystkim, czego potrzeba do zbudowania mechanizmu ekspedycji w czasie wykonywania. Nie potrzebujesz "samododującego kodu". – Nemo

+0

Nie powiedziałbym, że implementacja OOP w (powiedzmy) C++ używa samodefiniującego się kodu, moim zdaniem jest to po prostu kod sterowany danymi.Funkcje wirtualne nie są niczym innym, jak koncepcyjnie różni się od prostego "przełącznika". – Vlad

+0

@Noo: Czy to nadal jest forma kodu samoczynnie modyfikującego? – Mehrdad

Odpowiedz

7

własnym modyfikowania kodu nie jest możliwe w C z wielu powodów, z których najważniejsze to:

  1. Kod generowany przez kompilator jest całkowicie do kompilatora, a nic takiego nie może wyglądać co programista próbujący napisać kod, który sam się modyfikuje. Jest to jeden z podstawowych problemów związanych z wykonywaniem SMC, a nie tylko problem przenośności.
  2. Wskaźniki funkcji i danych są całkowicie oddzielne w C; język nie pozwala na konwersję między nimi. Problem ten nie jest istotny, ponieważ niektóre implementacje lub standardy wyższego poziomu (POSIX) gwarantują, że wskaźniki kodu i danych współdzielą reprezentację.

Poza tym samodefiniujący się kod jest po prostu naprawdę złym pomysłem. 20 lat temu mogło mieć kilka zastosowań, ale obecnie spowoduje tylko błędy, okropną wydajność i awarie przenośności. Zauważ, że w niektórych ISA pamięć podręczna instrukcji nawet widzi, że zmiany dokonane w pamięci podręcznej kodu mogą być nieokreślone/nieprzewidywalne!

Wreszcie vtables nie mają nic wspólnego z kodem modyfikującym. Jest to wyłącznie kwestia modyfikujących funkcji wskaźników, które są danymi, a nie kodem.

+1

+1 Twoje ostatnie zdanie jest kluczowe. Z jakiegoś powodu myślałem, że pośrednia instrukcja, jak "jmp EAX", zmienia się, gdy zmienia się "EAX" ... głupi błąd w myśleniu. Dziękuję za odpowiedź. – Mehrdad

+1

To nie jest prawda. Sprawdź mechanizmy ochrony stron w POSIX i WinAPI. Nic nie stoi na przeszkodzie (oprócz podpisywania kodu w jądrze iOS i podobnych) generowania kodu maszynowego w czasie wykonywania, ustawieniu flagi ochrony strony na EXEC i przekazywaniu do niej kontroli za pomocą wskaźnika funkcji w stylu C. –

3

Ściśle mówiąc, kod samodyfikujący nie może być zaimplementowany w sposób przenośny w C lub C++, jeśli poprawnie zrozumiałem standard.

samodzielne modyfikowanie kodu w języku C/C++ oznaczałoby coś takiego:

uint8_t code_buffer[FUNCTION_SIZE]; 
void call_function(void) 
{ 
    ... modify code_buffer here to the machine code we'd like to run. 
    ((void (*)(void))code_buffer)(); 
} 

To nie jest legalne i padnie na większości nowoczesnych architektur. Jest to niemożliwe do wdrożenia na architekturach Harvardu, ponieważ kod wykonywalny jest wyłącznie do odczytu, więc nie może być częścią żadnego standardu.

Większość współczesnych systemów operacyjnych ma możliwość korzystania z tego hakera, który jest używany przez dynamiczne rekompilatory dla jednego. mprotect() na przykład w systemie Unix.

+1

I * self * -modyfikowanie kodu jest kolejnym czajnikiem ryb z kodu, który zapisuje "świeży" kod i wykonuje go. Jak zauważa Mehrdad, modyfikacja kodu generowanego przez kompilator jest dość trudna, jeśli nie wiesz, jak ten kod został wygenerowany/zoptymalizowany w pierwszej kolejności, ponieważ instrukcje maszyny niekoniecznie mają jakiś szczególnie oczywisty związek z AST. –

+0

Chociaż nie można napisać "modyfikującej C", z pewnością możliwe jest, aby kompilator C emitował "samodyfikujący się kod maszynowy". Myślę, że to pytanie pozwala na jedno i drugie, czy OP miał na myśli jedno, czy nie wiem, czy jakikolwiek kompilator C kiedykolwiek to zrobił, ja też nie wiem. – hippietrail

Powiązane problemy