2016-08-16 1 views
8

In einem Versuch, ein Betriebssystem zu schreiben, muss ich die Adresse der aktuellen Funktion Ende (direkt vor Epilog) für Task-Wechsel.
Konkret ist mein Problem, eine EIP zu bekommen, um meine neu erstellte Aufgabe (Prozess) innerhalb des kopierten Stapels zuweisen. Ich habe es bereits geschafft, Register für einen Prozess zu speichern/wiederherzustellen, aber ich muss herausfinden, welchen Wert der Kindprozess in seinem EIP haben wird.GCC - Etikett Adresse zurück aktuelle EIP anstelle von realen Etikett Adresse

verwenden ich GCC-Erweiterungen C-Standard: Labels as Values und Local Labels
Aus der Dokumentation: Sie die Adresse eines in der aktuellen Funktion (oder eine enthaltende Funktion) mit dem unären Operator ‚& &‘ definierte Label erhalten. Der Wert hat den Typ void *.
und: GCC ermöglicht es Ihnen, lokale Beschriftungen in jedem verschachtelten Blockbereich zu deklarieren. Ein lokales Label ist wie ein gewöhnliches Label, aber Sie können es nur (mit einer goto-Anweisung oder indem Sie seine Adresse angeben) innerhalb des Blocks, in dem es deklariert ist, referenzieren.

pid_t fork(void) 
{ 
    __label__ fork_end; 
    ... 
    task->regs.eip = (uintptr_t)&&fork_end; 
    ... 
    return task->pid; 
    fork_end:; 
} 

GCC tut es kompilieren, mit nur Warnungen über Nicht-Standard-Code.
Wenn jedoch zerlegt, gdb zeigt:

task->regs.eip = (uintptr_t)&&fork_end; 
0x00105008 <+87>: mov $0x105008,%edx 
0x0010500d <+92>: mov -0xc(%ebp),%eax 
0x00105010 <+95>: mov %edx,0x40(%eax) 
... 
    fork_end:; 
    } 
0x00105096 <+229>: leave 
0x00105097 <+230>: ret 

ich task->regs.eip = (uintptr_t)&&fork_endl erwarten 0x00105096 statt 0x00105008 zu speichern.
CFLAGS sind -O0 -std=gnu99 -fgnu89-inline -DDEBUG -ggdb3 -ffreestanding -fbuiltin (Warnungen Optionen hier nicht gezeigt).

Kommentieren __label__ fork_end; ändert nichts.

+1

Bitte geben Sie einen Verweis auf die GCC-Dokumentation über '&&' und geben Sie an, was es in Ihrem Verständnis tut. Es warnt nicht, wenn Erweiterungen verwendet werden. Siehe [fragen] und geben Sie alle erforderlichen Informationen an. – Olaf

+0

Bearbeitet und @Olaf, gcc warnt vor nicht standardmäßigen Code mit der Option "-Wpedantic". Danke für Ihre Ratschläge. – Aerath

+0

Aha, ich verstehe. Die Verwendung von "Wpedantic" mit Erweiterungen klingt nach einer schlechten Idee. Wie auch immer, Ihr Cast ist eine Implementierung definiert und ein "uint32_t" ist nicht erforderlich, um einen Zeiger zu halten, noch gibt es eine 1: 1 Zuweisung. Auf einem 64-Bit-System sind Sie bereits kaputt. Verwenden Sie mindestens die richtigen Typen. Gibt es einen Grund, warum Sie nicht 'void *' als Zeiger, sondern als Integer verwenden? – Olaf

Antwort

1

Es scheint, dass der Compiler das Label vollständig optimiert, da kein Code-Pfad jemals dazu führt. Ich habe bestätigt, dass das Verschieben des Etiketts vor der return-Anweisung und sicherstellen, dass es tatsächlichen Code zwischen der Zuordnung und der Beschriftung Ergebnisse gibt, was ich glaube, ist Ihr gewünschtes Verhalten. Hier ist der Code, den ich zusammen auf dem Prüfstand:

void *fork(void) { 
    __label__ fork_end; 
    void *test = &&fork_end; 

    test++; 

    fork_end: 
    return test; 
} 

auf dieser Basis würde ich erwarten, dass Sie in der Tat bekommen, was Sie wollen, indem erneut arbeitet Code Pfad leicht, um sicherzustellen, dass das Etikett Punkt für jeden erreichbar ist Codepfad.

+0

Da erwartet wird, dass der Aufrufer diese Bezeichnung nicht erreicht, musste ich ein nie wahres verwenden, um GCC auszutricksen und es als erreichbar erscheinen zu lassen, auch wenn es nicht so ist. Wie auch immer vielen Dank @ Joel-c – Aerath