2016-03-30 4 views
-1

Ich bin neu in den Grundlagen der GCC-Kompilierung. Soweit ich weiß, ist der Stack aus Sicherheitsgründen nicht ausführbar. Dann wie können wir Code auf Stapel haben und ausführen. Ich beobachtete dies im Falle einer Funktion, die den Zeiger auf eine Funktion zurückgibt. Es gibt keinen Zeiger auf den Code zurück, sondern auf einen Ort auf dem Stapel, auf dem der Code ausgeführt wird. Wie ist das in Linux erlaubt?Ausführung von Code auf dem Stapel

Es ist bereits von gcc getan. Ich möchte wissen, wie es überhaupt möglich ist? Hier

ist der C-Code:

 #include<stdio.h> 

    typedef int (* funcptr)(); 


funcptr f() 
{ 

    int g() 
    { 

} 
return (&g); 
} 


main() 
{ 
    funcptr fp; 
    fp = f(); 

    fp(); 

} 

Und hier ist der Teil des Assembler-Code geerating Code auf den Stack:

#Starting trampoline code. The trampoline code is a small 
    #piece of code set up inside the stack!!!. This code, when 
    #executed, loads ecx with the static link and calls the 
    #function g 
     movb $-71, (%eax) # This is B9, the opcode for 
            "movl address_in_next_loc ecx" 
            this, when executed, will 
            load the static link in ecx 

     movl %edx, 1(%eax) # address_in_next_loc=ebp-16 
            the static link effectively 

     movb $-23, 5(%eax) # This is E9. the opcode for 
            jmp addr_nxt_ins + offset_ 
            in_nxt_loc 
            Since the offset_in_nxt_loc 
            is &g - addr_nxt_ins, this 
            results in a jump to &g 

     movl $g.1831, %ecx # Stores &g - addr_nxt_ins 
     leal 10(%eax), %edx # 
     subl %edx, %ecx # 
     movl %ecx, %edx # 
     movl %edx, 6(%eax) # 
    #End of trampoline code 
+0

Was macht sagen Sie gcc dies tut? –

+0

Weil ich die von gcc erstellte Assembly gelesen habe. Ich habe die Baugruppe erstellt und gelesen. –

+1

Können Sie diesen Assemblercode anzeigen? –

Antwort

1

Ihre C-Code eine verschachtelte Funktion enthält, so GCC die .note.GNU-stack gesetzt wird Abschnitt der generierten Objektdatei zu x (zeigt an, dass ein ausführbarer Stapel erforderlich ist).

Wenn der Linker aufgerufen wird, überprüft es alle bereitgestellten Objektdateien für diesen Abschnitt. Da eine der Eingabedateien .note.GNU-stack auf x festgelegt hat, weiß der Linker, dass der Stapel ausführbar sein muss.

Um dies anzuzeigen, der ELF-Header GNU_STACK in der endgültigen ausführbaren Datei hat das Flag PF_X hinzugefügt.

Der Befehl:

readelf -l a.out | grep -A1 GNU_STACK 

Sollten Sie erlauben, die RWE Flags gesetzt statt RW zu sehen.

Der Kernel sucht beim Erstellen der Speicherzuordnung für den Prozess gezielt nach diesem Header.

Weitere Details in der original patch

+0

Vielen Dank für die Antwort :) –

1

Sie würden Speicher von Heap reservieren im Gegensatz zu dem Stapel . Aber das könnte auch nicht den Zweck erfüllen, da moderne Prozessoren/Betriebssysteme es ermöglichen, zwischen Speicherbereichen, die Code enthalten, und solchen, die Daten enthalten (aus offensichtlichen Sicherheitsgründen), zu unterscheiden.

0

Ich nehme an, Sie nehmen an, dass der Stapel den Code selbst hält. Das ist möglicherweise nicht der Fall. Stack ist nur ein Halter für den Zeiger auf den Codebereich.

Sie lernen mehr darüber, wie Stack arbeitet here

This SO answer zeigt, dass die Funktionszeiger oder die Funktion selbst den Code Standort benötigen würde

+0

Der Stapel enthält einen Code, nicht den gesamten Funktionscode, sondern einen Code. zum Springen und Einstellen der statischen Verbindung usw., aber der Code ist dort auf dem Stapel. –

+0

Vielleicht hilft dieser Link: http://hokstad.com/how-to-implement-closures – CarlH