Funktionen (dynamisch) kopieren



  • Hallo Forum!

    Ich programmiere z.Zt. einen Microcontroller in C. Dabei ist es nötig einige Funktionen zur Laufzeit in einen anderen Speicherbereich zu verschieben (bzw um exakt zu sein zu kopieren). Meine Frage wäre nun, wie ich dieses in Ansi C am elegantesten bewerkstellige. Dabei habe ich insbesondere mit dem erkennen des Funktionsendes einige Probleme. Wie kann ich feststellen, wie wieviele Bytes meine Funktion im Speicher einnimmt? Kann ich dieses dynamisch ermitteln (über Label, goto-Anweisungen o.Ä.)? Es gibt doch sicher z.B. im Linuxquellcode ähnliche Mechanismen, da ja jedes Programm zum Starten in den Arbeitsspeicher geladen wird...

    Ich wäre für ein paar konkrete Tipps sehr dankbar!

    Gruß
    Christoph



  • hi,
    welcher controller ist das?
    sowas ist extrem architekturabhängig, manche architekturen kennen tatsächlich verschiebbaren code.
    'nur' mit c könnte es so gehen:
    1. den code für den speicherbereich builden, in dem er tatsächlich laufen soll.
    2. das, was compiler und linker erzeugt haben in ein array packen.
    3. zur laufzeit des 'hauptprogramms' den array-inhalt an die zieladresse kopieren
    4. vom hauptprogramm über function-pointer den code aufrufen.
    🙂



  • Es handelt sich um eine TriCore Architektur. Ich bin mir aber ziemlich sicher, dass es sich um einen vereinigten Speicherbereich handelt und ich deswegen auf den Code exakt wie auf Daten zugreifen kann (während der Laufzeit). Wenn ich dich richtig verstanden habe schlägst du einen Weg vor den fertig erzeugten Code statisch in ein Array zu packen, richtig? Das geht jedoch leider nicht, da dies zu aufwendig ist. Gibt es keine Möglichkeit irgendwie anders die Addresse des letzten Befehls der Funktion herauszubekommen?



  • schultzc schrieb:

    Wenn ich dich richtig verstanden habe schlägst du einen Weg vor den fertig erzeugten Code statisch in ein Array zu packen, richtig? Das geht jedoch leider nicht, da dies zu aufwendig ist.

    richtig, aber das ist doch nicht aufwendig 😕
    müsstest dir nur ein kleines tool schreiben, dass den linker-output in ein 'unsigned char' array umwandelt (mit den c-file funktionen). das dauert keine 10 minuten...

    schultzc schrieb:

    Gibt es keine Möglichkeit irgendwie anders die Addresse des letzten Befehls der Funktion herauszubekommen?

    ich glaub' da gibt's nix einfaches. solche tricks wie 2 funktionen untereinander schreiben und die differenz beider adressen zu nehmen klappen leider nicht (d.h. es wäre glück, wenn der linker die beiden auch wirklich so hinschiebt, wie du sie im quelltext angeordnet hast). du könntest natürlich auch die grösse abschätzen, falls es kein problem ist, wenn dabei ein paar bytes mehr kopiert werden. oder vielleicht guckste mal in die doku für deine toolchain. vielleicht gibt es da ein 'sizeof()' für funktionen oder andere features, die die verschieberei selber machen. mit purem ansi-c sieht's leider schlecht aus...

    was ist der der grund des verschiebens? muss code aus'm RAM laufen, damit sich der chip selber flashen kann oder sowas?



  • Für das Flashen haben wir ein entsprechendes Tool (zum Glück -g-). Es geht einfach um die Ausführungsgeschwindigkeit. Z.Zt. wird der komplette Code aus dem externen Flash ausgeführt. Es gibt jedoch einzelne sehr zeitkritische Funktionen die mit maximaler Geschwindigkeit ablaufen müssen. Der Controller bietet einen internen RAM Speicher an, in dem sich Code ablegen lässt, der dann mit vollem CPU Takt ausgeführt wird.

    Ich habe eine Lösung dieses Problems eines anderen Authors gesehen, der wie du bereits angemerkt hast, einfach den Anfang der folgenden Funktion als Endpunkt genommen hat. Das halte ich jedoch für zu riskant. Da muss nur irgendeine Linkereinstellung geändert werden und das ganze funktioniert nicht mehr.

    Ich werd jetzt mal ein paar Sachen ausprobieren, ob ich es vielleicht durch eine geschickte Anordnung von if..goto statements gebacken kriege. Da ich Zugriff auf das PC-Register habe mache ich mir Hoffnungen es damit in den Griff zu bekommen.

    Hast schon Recht, dass das mit dem Array vermutlich die einfachste Lösung ist, das probier ich dann danach aus ^^ Insbesondere weil ich dann auf jeglichen Overhead die Addressberechnung betreffend verzichten könnte...

    Vielen Dank für deine Antworten! 🙂



  • Ich stand mit einem XScale Proz. vor ein ähnliches Problem. Aber am besten ist es Memory Mapping zu benutzen. Wenn du eine Funktion kopierst, dann musst 1. die startadresse und 2. die Endadresse kennen. Dann musst du überpfüfen, ob die Funktion sprünge macht, vor allem in andere Funktionen. D.h. da musst du dynamisch die Werte der Sprünge ändern, und dasselbe gilt für alle andere Funktionen, die deine kopierte Funktion aufrufen. Deswegen, lieber memory mapping



  • supertux schrieb:

    Deswegen, lieber memory mapping

    ob er damit wohl den code vom FLASH ins RAM kriegt?
    wie macht'n das ein XScale mit seinen 400 MHz? das kann ja auch nicht aus dem FLASH laufen?



  • vista schrieb:

    supertux schrieb:

    Deswegen, lieber memory mapping

    ob er damit wohl den code vom FLASH ins RAM kriegt?

    bei mir kümmert sich der Bootloader darum 😉

    naja, ich dachte, er wollte nur eine einzige Funktion kopieren, aber er kann auf jeden Fall beim initialisieren vom FLASH in RAM kopieren (sollte im Prinzip mit wenig Aufwand möglich sein) und dann Memory Mapping zu benutzen.


Log in to reply