Hello, Guest the thread was called1.6k times and contains 11 replays

last post from hannenz at the

relokatibles Programmieren

  • bin jetzt endgültig auf Turbo Macro Pro +REU umgestiegen. Da besagter Assembler Makros und bedinget Assemblierung beherrscht, versuche ich mich gerade an zwei Makros um relokatiblen Code zu erstellen, genauer Substitute für JMP und JSR:


    jmmp .macro


    ß1 ist der übergebene Parameter, also jeweils die Zieladresse des Sprungs/ Aufrufs.
    Meine erste Frage lautet: geht das noch einfacher, geschickter, besser...?!


    Und das zweite was mir unter den Fingern brennt, wäre jetzt natürlich die jumps, die mit branches zu substitionieren wären (also innerhalb -128 oder +127 Bytes Offset) über eine bedingte Assembleirung innerhalb des Macros mit Verzweigungen zu realisieren.
    Etwa so:



    Aber wie muss die Bedingung lauten, mit .ifne/.ifpl kann wird ja scheinbar auf das Vorzeichen des 16-bit-Ausdrucks geprüft, also $7fff (plus) --> $8000 (minus)
    ...
    Wie kann man prüfen ob der Abstand zw. Programmzähler und Zieladresse mit einem Byte im Zweierkomplement ausdrückbar ist?
    irgendjemand eine Idee?

  • Also Du könntest die Daten für das Sprungziel direkt mit PHA auf den Stapel legen. Allerdings sehe ich nicht, wieso das relokatibel ist? Die Werte hinter den lda's müssen doch noch geändert werden, wenn Du den fertigen Code verschiebst.
    Vom Acme her kenne ich nur ein .if xyz=true, da würde man was schreiben in der Art von .if (*-Ziel<128 and *-Ziel>-128) (so in der Art jedenfalls). Probier' mal, ob das mit dem Assembler mit .ifne geht, True ist in der Regel -1, false 0. Falls der wirklich eine Zahl braucht würde ich beide Befehle schachteln .ifpl (*-ziel-128) (.ifne(ziel-*-128) lda...). Die richtigen Werte statt 128 musst Du mal mit einem Monitor ausexperimentieren, das Byte nach dem Branch überschreiben und dann rechnen.

  • ok, stimmt: relokatibel ist das ganze überhaupt nicht, hab ich auch eben gemerkt.... sch***ade...


    Also Zeiladresse PHAen ist gut, hätt ich auch drauf kommen können, aber an die aktuelle Programmadresse (PC) komm ich ja wirklich nur über ein JSR und dann eben die Adresse vom Stack holen, oder gibt es da noch andere Möglichkeiten?


    Einen JSR wirklich relokatibel zu substitionieren geht - wenn ich das richtig sehe - nur über einen fixne Bezugspunkt, da ich ja mindestens ein JSR ausführen muss (an eine fixe Adresse), um an den PC zu kommen zwecks Rücksprung oder? Also so in der Art:


    jsr $340


    und bei $340 wird dann zum eigentlichen Zeil gesprungen, in diesem Fall wäre die richige Rücksprungadresse ja schon auf dem Stack...



    Die .if-geschichte probier ich gleich mal aus...

  • Kannst Du nicht mit folgendem Beispiel einen festen Bezugspunkt erkennen lassen ? :



    Code
    1. START LDA *+1 ;low byte
    2. STA tabelle
    3. LDA start+2 ;high byte
    4. STA tabelle+1
    5. RTS
    6. tabelle !byte $00,$00 ;feed me ;)



    Dann erkennt das Programm imo wo es im Speicher liegt. Wenn man mit diesem Wert weiterrechnen kann, wird man es doch auch relokatibel machen koennen ?


    Oder habe ich das Problem nicht kapiert ? :gruebel


    Gruesse
    Michael

  • Es gäbe da noch die Option, beim Laden des Programms (also, beim ersten Start nach dem Laden) das Programm komplett zu relozieren. Geht fast simpel, wenn der Code in einem kontinuierlichem Block liegt.


    Dazu klatschst dDu halt einen Stub vor's eigentliche Programm (das vieleicht für eine Startadresse $8000 assembliert wurde). Der Stub geht dann den Code durch und wenn auf eine Adresse im Bereich des Programms stößt, so wird diese angepasst. Daanch wird das Programm gestartet.


    Vorteil: Nach dem reloc geht die Ausführung genauso schnell wie bei einem nicht-relozierbarem Programm.
    Nachteil: Der erste Start dauert was länger. Der Stub muss für 100%-ige Sicherheit auch den Code "verstehen" (d.h. wissen, wie viele Bytes ein Befehl braucht und welche Befehle umgeschrieben werden sollen). Der Code muss in einem durchgängigen Block stehen (damit der Parser nicht aus dem Tritt kommt). Geht nicht für Programme, die in ROMs/EPROMs stecken, weil selbst-modifizierend (es sei denn, der Code wird vorher in's RAM kopiert).


    - KLaus

  • Imo ist der Aufwand groesser als das zu erwartende Programm. Zudem wird das eine irre Hopserei.
    Ich wuerde es mit einer Art Parser machen. Der Befehlssatz des 6502 ist sowieso nicht zu ueppig und auf JSR/JMP verzichten ist hart.


    Wenn man es umbedingt versuchen will, wuerde ich eher Adressen erkennen lassen, in der Zeropage zwischenspeichern, Vektoren passend bestuecken (verbiegen) und so springen lassen. Das ist reine Theorie, muesste aber gehen.
    Findet man gelegentlich im Kopierschutz, um den boesen Crackern das Leben schwer zu machen.


    Gruesse
    Michael

  • cbmhardware: Ne, das hilft leider nicht, um die tatsächliche Adresse herauszufinden. Wenn Du das Programm nach $c000 assemblierst fängt es mit lda $c001 an. Damit wird es dann immer anfangen, egal, wohin Du es lädst.


    Um an den tatsächlich gerade benutzten PC zu kommen fällt mir jetzt nur ein, ein RTS anzuspringen und sich dann vom Stapel die Rücksprungadresse zu klauen

    Code
    1. sei ; IRQ's landen ja auch auf dem Stapel, evtl. NMI's sperren
    2. lda#$60
    3. sta 2
    4. jsr $0002
    5. tsx
    6. lda $100,x ; oder so
    7. ...
    8. lda $00ff,x ; oder so irgendwo in der Gegend
    9. cli
    10. ...


    Wenn Du die Adresse hast, wirst Du ja anschliessend eh noch eine größere Routine brauchen, die die Adressen in deiner Routine entsprechend anpasst. Das beim "Laden" von einer anderen Routine erledigen zu lassen, wie Klaws meinte, ist vielleicht gar nicht schlecht, musst Du wissen, ob das möglich ist. Oder verschieden verschobende Versionen auf die Diskette packen.


    Vor Urzeiten hatte ich mal einen 6510-Interpreter für den C64 geschrieben, um von Programmen belegte/benutzte Adressen finden zu lassen. Ich habe das Programm an verschiedene Adressen assembliert und beide Versionen auf Diskette abgelegt. Mit einem kleinen Basic-Programm konnte ich dann jede beliebige Version erstellen lassen.
    Ich hatte mich darauf beschränkt, das nur 256Byte-weise verschiebbar zu machen. Ganz beliebig verschiebbar tut nämlich Aua-aua-weh.

  • [quote]Original von hoogo
    cbmhardware: Ne, das hilft leider nicht, um die tatsächliche Adresse herauszufinden. Wenn Du das Programm nach $c000 assemblierst fängt es mit lda $c001 an. Damit wird es dann immer anfangen, egal, wohin Du es lädst.
    [/qoute]


    Recht hast Du. Damit waere maximal ein relativ relokierbarer Source moeglich.


    Gruesse
    Michael

  • cool... es kommt eine hochinteressaante Diskussion zu Tage... wobei mir das ursprüngliche Problem schon fast wieder aus den Augen ist. Ich dachte eben, z.B. auf "höheren" prozessoren (und in höheren Sprachen sowieso) wird ja sowieso grundsätzlich ausschliesslich relokatibel programmiert, oder?! Für eine Umsetzung eines Betriebssystems z.B. ist das Problem best. interessant, also kleine (Dienst-) Programme, die sich überall im Speicher befinden können, dazu einen IRQ-Handler, der dann ein (Pseude-)Multio-tasking macht usw. usf... interessant ist das alles alle mal, hat sich denn noch noiemand so richtig damit befasst... Literatur...??!


    Ich denke, einen Relocator vors Programm zu klatschen wäre evtl. tatsächlich die beste Methode...

  • Bei "besseren" Systemen gibt's dafür Memory Management Units, die (per hardware) einem Programm vorgaukeln, an einer bestimmten Stelle im Speicher zu stehen (durch hardwaremäßige Adressumsetzung).


    Bei einigen Betriebssystemen wird ein spezielles Binärformat verwendet, bei dem hinter dem eigentlichen programm eine Tabelle mit drinsteckt, die dem "relocating loader" der BSes sagt, wo welche Adressen angepasst werden müssen, wenn das Programm in den Speicher geklatscht wird.


    LNG hat natürlich runtime code relocation. Source code ist natürlich auch vorhanden. Ist natürlich etwas weniger gut ausgestattet als ein "großes Unix", aber kann immerhin 32 Tasks auf dem C64 laufen lassen.


    - Klaus