2016-07-03 5 views
2

ich über Speicherverwaltung studierte und ich kam in diesem Code:Pointer, dass funktionieren wurde von Code kopiert

void print(const char * str){ 
    printf(str); 
} 

void (*print_ptr)(const char *)=print; 

void foo2(void){ 
    print("goo\n"); 
    return; 
} 

void baz(void){ 
    print("foo\n"); 
    return; 
} 

int main() 
{ 
    char buf[256]; 
    void (*func_ptr)(void)=(void (*)(void))buf; 
    memcpy(buf,foo2,((void *)baz)-((void *) foo2)); 
    func_ptr(); 
    return 0; 
} 

Dieser Code wird seg Fehler verursacht

func_ptr(); 

erreicht Ich kann nicht verstehen, warum. Wenn ich den Zeiger so ändere, dass er auf eine statische Funktion zeigt (wie func_ptr=&baz wird es richtig funktionieren, aber ein dynamischer Code wird nicht.
Der Code selbst, wie ich es verstehe, wird auf den Stack kopiert, wo er sein sollte.
?. Was ist mit diesem Code falsch ist

Antwort

4

Was Sie versuchen, das Objekt-Code zu tun, kopieren Sie es aus foo2() in die Puffer und führen Dies wird nicht für eine Reihe von Gründen arbeiten:

  1. Ihr Code wird in buf kopiert, die im Datenbereich zugewiesen werden, der nicht ausführbar ist (dh t Der Speichermanager hat keine Ausführungsberechtigung für diesen Speicherbereich.

  2. Der Code ist im allgemeinen Fall wahrscheinlich nicht verschiebbar. Es kann entweder absolute Verweise auf sich selbst oder relative Verweise auf den Rest des Codes enthalten, die beide beim Kopieren brechen.

  3. Sie können nicht garantieren, dass der Code mit den Funktionen in der angegebenen Reihenfolge kompiliert wird. Es gibt also keine Garantie, dass Sie nur foo2() kopieren. Tatsächlich gibt es keine Garantie, dass der Compiler das foo2() als einen einzelnen zusammenhängenden binären Blob erzeugt. Ein Teil davon könnte (zum Beispiel) nach bar() sein. Oder (relativ häufig vorkommende) Teile der Funktion können vor dem Eintrittspunkt liegen.

Wenn Sie wirklich verstehen wollen, warum es zu brechen, Fix (1) für buf mit mmap() und MAP_ANON das Zuweisen von Speicher, PROT_READ|PROT_WRITE|PROT_EXEC verwenden, führen Sie es dann unter gdb. Ich würde vorschlagen, mit -O0 kompilieren (Optimierung deaktivieren), um die Chancen auf etwas Arbeit zu maximieren, aber ich würde wiederholen, Sie haben keine Garantien.

Die größere Frage ist, warum auf der Erde Sie Bits Ihres Codes herum kopieren möchten.

+0

Betreff 2: Sie meinen, dass wenn eine Funktion aufgerufen wird, diese in eine relative Adresse (dh ein Offset) übersetzt wird. Wenn ich also diesen Teil kopiere, erreicht er beim Erreichen dieses Offsets a Speichersegment, dass es nicht sollte? –

+0

@YinonEliraz, nein, ich meine, innerhalb der Funktion könnte es sich auf eine relative Adresse 'PC + N' beziehen, die außerhalb der Funktion liegt, oder auf eine absolute Adresse' X', die innerhalb der Funktion liegt. Beide können Probleme verursachen, wenn die Funktion verschoben wird. – abligh

+0

Hier sprechen wir über den Aufruf für die lokale Funktion drucken? –