Assembler Tutorial

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • Assembler Tutorial

      1. Vorwort
      Willkommen zu meinen ARM7tdmi Thumb Assembler Tutorial.
      Erstmal möchte ich mich bei 2 Personen bedanken.
      prime, ohne dein Tutorial wäre es mir erst garnicht möglich gewesen,
      dieses Tutorial zu schreiben, von welchem ich mir erhoffe, dass es etwas
      ausführlicher wird.
      Sturmvogel, weil du mir fast immer geholfen hast wenn ich ein Problem
      hatte. Danke euch zweien.

      Zum Tutorial:
      Ihr solltet auf jedenfall als Basis mitbringen, Kentnisse darüber,
      wie der RAM des GameBoy Advance aufgebaut ist und was Bytes etc. Pointer und Addressen sind..

      2. Programme die ihr benötigt
      Ihr braucht den ARM-EABI Assembler, ihr findet ihn unten als Link
      Dazu solltet ihr im Besitz eines Hexeditors und einer Pokémon ROM sein.

      3. Unterschied ARM u. Thumb
      Es gibt bei dem ARM7tdmi von Advanced Risc Machines 2 verschiedene
      Arten von Anweißungen/Befehlen. Einmal ARM Befehle, welche 32-Bit groß sind, sprich 4 Bytes oder auch 1 DWORD. ARM Befehle können direkt von der CPU abgearbeitet werden. Dann gibt es noch Thumb Befehle, welche 16-Bit groß sind, bzw. 2 Bytes. Thumb kann nicht direkt abgearbeitet werden. Thumb Befehle müssen erst vom Prozessor in ARM Befehle umgwandelt werden. Thumb Befehle werden allerdings oft lieber als ARM Befehle benutzt, weil sie schneller sind und weniger
      RAM verbrauchen, da 1 Befehl nur 2 Bytes hat und nicht 4.
      So viel dazu.

      In diesem Tutorial werden wir uns nur mit dem Thumb Befehlssatz auseinandersetzen, da er am häufigsten im Bereich des Romhackings benötigt wird.

      4. Grundlagen

      Datengrößen

      BYTE: Zahl 0-255/8-Bits
      WORD: Zahl 0-65535/16-Bits/2 Bytes, wird im Hexeditor rückwärts gelesen, d.h aus FF AA wird das Word AAFF
      DWORD: Zahl 0-4294967295/32-Bits/4 Bytes, wird im Hexeditor rückwärts gelesen, aus 01 02 03 04 wird 04030201

      Register

      Bei jedem Prozessor gibt es sog. Register in die man mit Hilfe von Assembler verschiedene Werte schreiben kann, 2 Register addieren und das Ergebnis in ein
      anderes Register packen etc. Bei dem ARM7tdmi haben wir 17 Register, diese
      werden mit r0-r16 benannt und jedes Register ist 32bit lang.
      Im Thumb Modus können wir im Normalfall davon nur die Register r0-r7 und
      r13-r16 verwenden.

      In r13 ist der Stack Pointer gespeichert, d.h. die Addresse wo sich der Stack befindet.
      Der Stack ist so eine Art Zwischenspeicher auf den Werte und Inhalte von Registern gepackt werden können. Und der Stack funktioniert nach dem Stapelprinzip, d.h, dass alles, was auf den Stack gepackt wird, wieder in der umgekehrten Reihenfolge runtergenommen werden muss.

      r14 ist das sog. Link Register, d.h im Prinzip nichts anderes als, wenn
      wir in unserem Code in eine Unterfunktion springen, dass dort dann drin steht wohin die Unterfunktion nacher zurückspringen soll.

      In r15 steht der Code Pointer, d.h die Addresse von der Anweisung, die der Prozessor als nächstes ausführt.

      r16 ist das Status Register. Wir brauchen es im Normalfall nicht. Für die, die es interessiert Zitiere ich hier GBATEK.
      Spoiler anzeigen

      Quellcode

      1. Current Program Status Register (CPSR)
      2. Bit Expl.
      3. 31 N - Sign Flag (0=Not Signed, 1=Signed)
      4. 30 Z - Zero Flag (0=Not Zero, 1=Zero)
      5. 29 C - Carry Flag (0=No Carry, 1=Carry)
      6. 28 V - Overflow Flag (0=No Overflow, 1=Overflow)
      7. 27 Q - Sticky Overflow (1=Sticky Overflow, ARMv5TE and up only)
      8. 26-8 Reserved (For future use) - Do not change manually!
      9. 7 I - IRQ disable (0=Enable, 1=Disable)
      10. 6 F - FIQ disable (0=Enable, 1=Disable)
      11. 5 T - State Bit (0=ARM, 1=THUMB) - Do not change manually!
      12. 4-0 M4-M0 - Mode Bits (See below)
      13. Bit 31-28: Condition Code Flags (N,Z,C,V)
      14. These bits reflect results of logical or arithmetic instructions. In ARM mode, it is often optionally whether an instruction should modify flags or not, for example, it is possible to execute a SUB instruction that does NOT modify the condition flags.
      15. In ARM state, all instructions can be executed conditionally depending on the settings of the flags, such like MOVEQ (Move if Z=1). While In THUMB state, only Branch instructions (jumps) can be made conditionally.
      16. Bit 27: Sticky Overflow Flag (Q) - ARMv5TE and ARMv5TExP and up only
      17. Used by QADD, QSUB, QDADD, QDSUB, SMLAxy, and SMLAWy only. These opcodes set the Q-flag in case of overflows, but leave it unchanged otherwise. The Q-flag can be tested/reset by MSR/MRS opcodes only.
      18. Bit 27-8: Reserved Bits (except Bit 27 on ARMv5TE and up, see above)
      19. These bits are reserved for possible future implementations. For best forwards compatibility, the user should never change the state of these bits, and should not expect these bits to be set to a specific value.
      20. Bit 7-0: Control Bits (I,F,T,M4-M0)
      21. These bits may change when an exception occurs. In privileged modes (non-user modes) they may be also changed manually.
      22. The interrupt bits I and F are used to disable IRQ and FIQ interrupts respectively (a setting of "1" means disabled).
      23. The T Bit signalizes the current state of the CPU (0=ARM, 1=THUMB), this bit should never be changed manually - instead, changing between ARM and THUMB state must be done by BX instructions.
      24. The Mode Bits M4-M0 contain the current operating mode.
      25. Binary Hex Dec Expl.
      26. 10000b 10h 16 - User (non-privileged)
      27. 10001b 11h 17 - FIQ
      28. 10010b 12h 18 - IRQ
      29. 10011b 13h 19 - Supervisor (SWI)
      30. 10111b 17h 23 - Abort
      31. 11011b 1Bh 27 - Undefined
      32. 11111b 1Fh 31 - System (privileged 'User' mode) (ARMv4 and up)
      33. Writing any other values into the Mode bits is not allowed.
      Alles anzeigen


      Da der "richtige" Status der Register für den Code sehr wichtig ist, damit er richtig funktioniert sollten wir, wenn wir eine Unterfunktion aufrufen, in dieser als erstes
      alle wichtigen Register auf den Stack packen und anschließend am Ende der Unterfunktion wieder zurückladen.

      Zum Abschluss des Grundlagen Teils bleibt gesagt, dass wir bei Assembler immer nur Daten
      ändern und hin und her schieben.

      5. Befehle
      So hier lernt ihr auch schon die ersten wichtigen Befehle ;)
      Ich sage mal so, ich werde hier nicht alle erklären, sondern die, die man am häufigsten braucht.

      Der MOV Befehl
      Mit MOV ist wie man sich vlt. denken kann MOVE (to move -> bewegen) gemeint.
      Wir können damit also Daten in ein Register kopieren. Das kann entweder eine fest angegebene Zahl von 0-255 sein oder der Inhalt eines anderen Registers.

      Beispiel:

      Quellcode

      1. mov r0, #0x13
      2. mov r1, r0


      In der 1. Zeile schreiben wir in r0 den Wert 13 Hexadezimal.
      In der 2. Teile kopieren wir dann den Inhalt von r0 (also 13 Hexadezimal) und packen ihn in r1. Das war dann auch schon der 1. Befehl.

      Der ADD Befehl
      Der ADD Befehl ist zum addieren 2er Werte gedacht und hat folgende Syntax:
      add rX, rY, rZ
      und entspricht folgendem:
      rX = rY + rZ
      Dabei kann rZ entweder ein Register oder eine vorgegebene Zahl sein.

      Beispiel:

      Quellcode

      1. mov r1, #0x5
      2. mov r2, #0x2
      3. add r0, r1, r2
      4. add r0, r0, #0x1


      Na, wer weiß es? Das Ergebnis ist hier natürlich, dass in r0, der Wert 8 steht.

      Der SUB Befehl
      Der SUB Befehl is t da zum Subtrahieren zweier Werte.
      Syntax:
      sub rX, rY, rZ
      rX = rY - rZ
      rZ kann wieder entweder eine vorgegebene Zahl oder ein Register sein.

      Beispiel:

      Quellcode

      1. mov r0, #0x5
      2. mov r1, #0x2
      3. sub r2, r0, r1


      r2 = r0(5) - r1(2). Von Daher ist das Ergebnis unseres Codes also 3.

      Der MUL Befehl
      Der MUL Befehl ist zum multiplizieren zweier Werte gedacht.
      Syntax:
      mul rX, rY, rZ
      rX = rY * rZ
      rZ kann wieder einmal entweder eine Zahl oder ein Register sein.

      LDR, LDRB, LDRH Befehle
      Im Prinzip ist das ganze relativ einfach, es geht um Befehle zum Laden von Werten aus dem RAM oder ROM.
      Mit LDR lädt mein ein 32 Bit Wert von einer Addresse in ein Register.
      Mit LDRH lädr man ein 16 Bit Wert von einer Addresse in ein Register.
      Und mit LDRB lädt man ein BYTE von einer Addresse in ein Register.
      Die Syntax ist bei allen 3 gleich:
      ldr rX, addresse oder
      ldr rX, [rY] In den Fall liegt die Addresse in rY

      Um mal ein Beispiel zu geben (Mit dem @ Zeichen setzen wir ein Kommentar, dieser wird von dem Assembler dann ingnoriert.):

      Quellcode

      1. .align 2 @ Immer nötig bei Thumb
      2. .thumb @ Unser Code soll als Thumb assembliert werden
      3. .global main @ Nicht dirgend notwendig, gibt an, das main die Hauptfunktion ist
      4. main: @Unsere Hauptfunktion.
      5. ldr r0, .addr @ Lade DWORD von .addr in r0
      6. ldrb r1, [r0] @ Lade 1 BYTE von der Addresse in r0 nach r1
      7. .align 2
      8. .addr: @ Wir verwenden eine Unterfunktion, um unser Offset direkt unter den Code zu kriegen..
      9. .word 0x6000000 @ Wir platzieren hier unser RAM Offset 0x06000000


      Also im Prinzip laden wir nur 1 BYTE vom Offset 0x6000000 im Endeffekt.


      STR, STRH, STRB Befehle

      Jetzt schreiben wir in den RAM.
      Also mit diesen Befehlen könnt ihr den Wert aus einem bestimmten Register an eine bestimmte Addresse schreiben.
      Mit STR schreiben wir ein 32 Bit Wert, mit STRH ein 16 Bit Wert und mit STRB ein BYTE..
      Syntax (bei allen gleich):

      Quellcode

      1. str rX, [rY]

      Dabei wird der Inhalt von rX ins Offset, welches in rY angegeben ist, geschrieben.

      Und ein Beispiel:

      Quellcode

      1. .align 2
      2. .thumb
      3. .global main
      4. main:
      5. ldr r0, .offset @ Sollte aus dem letzen Teil klar sein..
      6. mov r1, #0x2 @ Schiebe 2(Hexadezimal) nach r1
      7. strb r1, [r0] @ Der Inhalt von r1 wird ans Offset geschrieben, welches in r0 steht.
      8. .align 2
      9. .offset:
      10. .word 0x6000000
      Alles anzeigen


      Wir schreiben also im Endeffekt im RAM am Offset 0x6000000 den Wert 2.
      ACHTUNG: Typischer Anfängerfehler. In den Bereich 0x08000000-0x08FFFFFF kann nicht geschrieben werden, da der ROM Read Only ist.

      Der Befehl B
      Der Befehl B macht eigentlich nichts anderes, als an eine bestimme Codestelle zu springen.

      Syntax:
      b offset

      Beispiel:

      Quellcode

      1. .align 2
      2. .thumb
      3. .global main
      4. main:
      5. b .unterfunktion @ Eine Unterfunktion ist nichts anderes als eine kleine Unterroutine in einer Funktion
      6. [bla...]
      7. .unterfunktion: @ Bei einer Unterfunktion
      8. @tuhe irgendwas..


      Der Befehl bx
      Der Befehl bx ist so ähnlich wie der Befehl b.
      Der einzige Unterschied liegt darin, dass bei bx nicht ein Offset,
      sondern ein Register angegeben, indem das Offset steht.
      Zu beachten ist, dass wenn der Code an der Zieladdresse Thumb ist (welches wir hier verwenden), sprich nicht ARM,
      dann muss das Offset +1 gerechnet werden.

      Vergleichen von Werten
      Wenn wir 2 Werte (sprich 2 register oder 1 register und 1 fester Wert) vergleichen, tuhen wir das erstmal
      in dem wir den CMP Befehl (von compare -> vergleichen) ausführen.
      Sprich also:

      Quellcode

      1. cmp rX, rY

      bzw.

      Quellcode

      1. cmp rX, #0xY


      Darauf folgt dann ein Conditional Jump. D.h., wenn bei dem Vergleich ein bestimmtes Ergebnis erzielt wurde, springt der Prozessor einer bestimmten Stelle im Code.
      Ich habe hier eine Liste für euch mit den wichtigsten Conditional Jumps.

      Quellcode

      1. BEQ Werte sind gleich
      2. BNE Werte sind ungleich
      3. BGE Parameter 1 ist größer/gleich Parameter 2
      4. BLT Parameter 1 ist kleiner Parameter 2
      5. BGT Parameter 1 ist größer Parameter 2
      6. BLE Parameter 1 ist kleiner/gleich Parameter 2


      Beispiel:

      Quellcode

      1. .align 2
      2. .thumb
      3. .global main
      4. main:
      5. mov r0, #0xFE
      6. cmp r0, #0x1
      7. beq .unterfunktion1
      8. bne .unterfunktion2
      9. .unterfunktion1:
      10. @mach irgendwas ^^
      11. .unterfunktion2:
      12. @mach auch irgendetwas
      Alles anzeigen


      So jetzt könnt ihr raten welche unterfunktion ausgeführt wird !

      BIOS Funktionen.
      Das BIOS des GBAs bringt bereits einige handliche Funktionen mit sich, die es erleichtern,
      z.B. größere Datenmengen zu kopieren, oder LZ77 zu dekomprimieren.
      Jede Funktion hat eine Number. CpuFastSet z.B. 0xC.
      Man führt eine BIOS Funktion folgendermaßen aus:

      Quellcode

      1. swi 0xNUMMER

      Da der Teil ein bisschen lang werden würde, würde ich hier jede einzelne Funktion behandeln, verweiße ich euch
      hier einfach mal auf GBATek:
      nocash.emubase.de/gbatek.htm#biosfunctions

      PUSH, POP
      So hier kommt jetzt der Stack ins Spiel
      PUSH macht im Prinzip nichts anderes als ausgewählte Register auf den Stack zu packen.

      Paar Beispiele:

      Quellcode

      1. push {r0} @pushe r0
      2. push {r0-r3, r5} @ pushe r0 bis r3 und r5


      Und POP holt die Daten vom Stack wieder herunter in die ausgewählten Register.
      Es gibt natürlich sowas , wo man ein Register pusht und dann in ein anderes popt.
      Also z.B.:

      Quellcode

      1. mov r0, #0x8
      2. push {r0} @ Wert von r0 auf den Stack packen
      3. pop {r1} @ Und Den Wert dann vom Stack nehmen und nach r1 packen


      Dann haben beide Register den Wert 8.

      6. Sichern von Registern
      Wie schon erwähnt, ist es wichtig, dass wenn man seinen eigenen Code irgendwo einbaut und ausführen lässt, dass wir in diesem Code die Register sichern und am Ende wiederherstellen. Das geht im Prinzip ganz einfach indem wir am Anfang unseres Code
      push {r0-r7, lr} schreiben und am Ende pop {r0-r7, pc}.
      Wir popen den Inhalt von lr am Ende nicht wieder in lr sondern in PC, also den Program Counter. Das machen wir, weil wir am Ende wieder zum ursprünglichen Code müssen und
      in lr steht ja die Addresse zu dem der Code zurückspringen sollen. Und das Zurückspringen machen wir in dem wir über den pop Befehl unteranderem den Inhalt vom LR in PC packen, wir ändern also den Program Counter und damit die Position des aktuell zu ausführenden Code auf das Offset wo der Code liegt, der unsere Funktion aufgerufen hat.

      Beispiel:

      Quellcode

      1. .align 2
      2. .thumb
      3. .global main
      4. main:
      5. push {r0-r7, lr}
      6. @ tuhe etwas
      7. pop {r0-r7, pc}


      7. Ein Beispiel Code
      So nochmal ein Beispielcode der fast alles beinhaltet was ihr (hoffentlich)
      gelernt habt. Der Code ist für eine Feuerrot Deutsch ROM gedacht und ändert das
      Leben des 1. Pokemons im Team auf 1. Wie man vlt. sieht liegt das Leben des 1. Pokemons im Team an den RAM Offsets 0x02023c0c und 0x020242da ;)

      Öffne mich.

      Quellcode

      1. .align 2
      2. .thumb
      3. .global main
      4. main:
      5. push {r0-r7, lr}
      6. ldr r0, .leben1
      7. mov r1, #0x1
      8. strh r1, [r0]
      9. ldr r0, .leben2
      10. strh r1, [r0]
      11. pop {r0-r7, pc}
      12. bx lr
      13. .align 2
      14. .leben1:
      15. .word 0x02023c0c
      16. .leben2:
      17. .word 0x020242da
      Alles anzeigen


      8. Compilieren bzw. Assemblieren
      OK das ist der weniger komplizierte Teil.
      Ihr geht in dem Assemler Ordner in den Unterordner 'cmp' und dann dort in
      den Ordner 'bin'.
      Dort erstellt ihr eine build.bat Datei die so aussieht:

      Quellcode

      1. as -o output.o EureDatei.asm
      2. objcopy -O binary output.o Ausgabe.bin
      3. pause


      EureDatei.asm müsst ihr noch auf den Path zu eurem AssemblerSkript anpassen.
      Dann einfach Doppelklick auf build.bat und wenn er dann in der Konsole nichts mit 'Error: ' sagt, dann hat alles geklappt.
      Jetzt könnt ihr die Ausgabe.bin öffnen und den Code an einen freien Platz in der ROM kopieren.
      In einem XSE Script könnt ihr dann eure Routine mit callasm 0xOFFSET+1 aufrufen.

      9. Schlusswort
      So, erstmal danke fürs Lesen und Respekt, dass ihr solange ausgehalten habt.
      Ich hoffe euch hat das Tutorial geholfen, wie schon gesagt habe es sind nicht alle Befehle angesprochen worden, dass geht einfach nicht, wenn man man die Befehle ausführlich erklären will.

      Das Tutorial ist Copyright by hack!osa und darf ohne meine Erlaubnis nicht kopiert werden.

      In dem Sinne, mfG hack!osa

      ARM-EABI Assembler: Im Anhang
      Dateien
      • Assembler.zip

        (779,32 kB, 182 mal heruntergeladen, zuletzt: )

      Dieser Beitrag wurde bereits 11 mal editiert, zuletzt von hack!osa () aus folgendem Grund: Update 22.08.2012

    • Nu ja, mein Lieblingskapitel, leider muss ich sagen, wäre ich ein Anfänger in diesem Bereich würde ich persönlich warscheinlich nichts verstehen, bzw. selbst wenn ich es verstehen könnte wüsste ich nichts damit anzufangen weil ich nicht researchen könnte.
      Um einzelne Befehle kennen zu lernen empfinde ich das Tutorial nicht als schlehcht, allerdings sollte in einem Assembler Tutorial vorallem Dinge wie debugging, blablub vorkommen, damit man auch versteht was man macht. Meist läuft es ja so ab, dass man seinen Code einschläust in den Nintendo Code(Um bei Pokemon zu bleiben), der callasm Befehl ist nur die simpelste Methode eine ASM Routine aufzurufen.
      Letztlich erfüllst du das, was du durchgehen wolltest mit dem Tutorial hier, ich habe mir aber irgendwie mehr erwartet. Wenn ich zurück denke als ich kläglich versuchte Assembler zu lernen und letztlich nur durch fremde Hilfe es geschafft habe, weil driver mir mal irgendeinen Link gab, so würde ich das hier nicht verstehen.

      ~Sturmvogel
      Wandering on Horizon Road
    • In 1. Linie erfreut es mich, dass du der "Elite" beitreten möchtest und dich offensichtlich intensiv mit ASM beschäftigt hast.

      Allerdings, ich, als Anfänger bzw. ohne großartige ASM-Kenntnisse ausgestattet, verstehe das Tutorial bloß bedingt. Unbekannte Begriffe à la "DWORD" hättest du eventuell kurz erklären sollen, zur verwendeten Software hättest du ebenfalls 1 oder 2 Sätze schreiben können. Ressourcen, mit welchen man sich selbstständig Wissen bezüglich des RAMs etc. aneignen kann (Welches du ja vorraussetzt), wären ebenfalls eine Erleichterung.

      Konkret vermisse ich, wie Sturmvogel bereits änhlich fomulierte, einen praxisorientierten Bereich. Als Laie, der bislang keinen ASM-Script / Code bewusst zu Gesicht bekam, kann ich mit diesen Befehlen nichts anfangen. Einen kurzen ASM-Script, welcher im Spiel bereits integriert ist, auszuarbeiten und mit Hilfe dieses Scripts das Erlernte zu vertiefen bzw. praktisch anzuwenden (Vgl. diverse Scripting-Tutorials) wäre für mich persönlich eine große Hilfe.

      Keine Ahnung, ob meine Kritik überhaupt legitim ist oder hilfreich ist.
      Arbeite an diesem Tutorial, das Fundament passt ;).

      Lg.
      MfG, Alen
    • gut, dass es endlich mal ein Tutorial auf Deutsch gibt. Auf Englisch habe ich ja auch schon welche gefunden, aber nur so zu 90% (also jetzt rein sprachlich) verstanden, was gemeint war. Ansonsten ein sehr, sehr schönes und gut verständliches Tutorial, was einigen Leuten den "Ersten Schritt" zum ASM-Scripten gut näher bringen kann. Auch gut strukturiert und gut dargestellt. Was man vielleicht besser machen kann ist dass du um die Scripte einen Spoiler oder so etwas macht. Also ich schließe mich da looper an, dass es schwer zu lesen ist.
      Also ich hab mich jetzt auch (auch im Schul-IT) etwas mit ASM beschäftigt. Aber ich habe trotzdem ein Frage. Und zwar gibt es ja verschiedene ASM "Arten" (nenn ich jetzt mal so vereinfacht). Dort sind die Befehle glaub auch zum Großteil gleich. Aber wo ist da ein Unterschied, bzw. Was ist der Unterschied?
      Der kostenlose Resourcen PKMN Markt!
      [Link aufgrund von Malware verdacht moderativ entfernt]
      Mit fast täglichem Update!
      Wer ein Teil davon werden will schickt mir eine E-Mail oder eine PN.

    • So danke erstmal fürs Feedback. Ich werde wohl das Tutorial noichmal etwas überarbeiten :P

      @Alen: Joa kann ASM schon etwas länger (ca. 1 Jahr)
      Und btw ein DWORD sind einfach 4 rückwarts gelesen. D.h wenn du im Hexeditor siehst FA AD 03 0A dann ist das 0A03ADFA ;)

      @Hackrex Danke für das doch sehr positive Feedback :P
      Die Idee mit den Spoilern finde ich nicht schlecht, werde ich umsetzen.
      Zu deiner Frage. Die ASM "Art" kommt auf den Prozessor drauf an. Jeder Prozessor hat seine eigene Art von ASM. Du hast recht oft heißen die Befehle gleich in Hex werden sie allerdings ganz anders geschrieben. Was noch anzumerken wäre, dass du eine bestimmte Art Assembler nur für eine Art Prozessor verwenden kannst.

      mfG hackiosa
    • O.k, ich habe alles fliesend verstanden :D

      Nur das wohl simpelste mislingt mir...

      Ich habe den Code als .asm gespeichert, nun macht er aber immer etwas falsches...?( (Glaube ich zumindest)

      Also ich habe diesen Code:

      Brainfuck-Quellcode

      1. .thumb
      2. .align 2
      3. main:
      4. LDR R5, =0x20370CA often
      5. LDRB R5, [R5]
      6. CMP R5, #0xF BEQ new_code
      7. STR R1, [R2]
      8. LDR R1, =0x2023E82
      9. MOV R0, #0xF
      10. STRB R0, [R1]
      11. LDR R4, =0x8010665
      12. BX R4
      13. new_code:
      14. ADD R1, #1
      15. STR R1, [R2]'----------
      16. LDR R1, =0x2023E82
      17. MOV R0, #0xF
      18. STRB R0, [R1]
      19. LDR R4, =0x8010665
      20. BX R4
      Alles anzeigen


      Nun habe ich das als asm gespeichrt und in dern Ordner reingefügt. es erscheint aber immer dein Bespiel.txt. Klingt blöd aber das assemblen versteh ich nicht... :rolleyes: (Ich bin halt Gfe xD)

      Kann mir ma jemand helfen?

      Gfe
      Das waren noch Zeiten...

      ...

      Wodka schrieb:

      Wodka - 3. Oktober 2012

      Ich spüre seinen Atem in meinem Nacken o.O!

      PEDODAD!


    • Naja wie schon erwähnt ist das hier lange nicht alles, wird dir aber bestimmt auch selbst noch bewusst werden. Assembler ist eine Sprache, ähnlich zu anderen Programmiersprachen, vielleicht ein wenig schwieriger, allerdings das was man damit anstellt, Daten kopieren, dafür sorgen, dass "das passiert was man will, dass es passiert", benötigt viel Verständnis der Logik der Hardware auf der man die Sprache verwedent.

      Anyway, ist ja nicht Thema des Tutorials, zum Thema Assembler wollte ich noch anmerken, ich verstehe nicht ganz das Problem, würde aber ebenfalls empfehlen die Dateiendungen zu überprüfen und vorallem beim verwenden des Programmes selbst darauf achten, dass man sich nicht verschreibt. Rechtschreibfehler frisst der Assembler ungern.

      ~Sturmvogel
      Wandering on Horizon Road
    • Sorry, dass ich dieses alte Thema wieder ausgrabe.
      Ich möchte Hack! dafür danken, dass er das geschrieben hat, ich fands sehr verständlich und hab innerhalb einer halben Stunde ziemlich durchgeblickt. Mir ergaben sich nur 2 Fragen.
      Wenn du bx lr verwendest, welches Register stellt lr da? Und braucht die Haupt bzw Unterroutine nicht eine Art "return" Befehl?

      Und einige Sachen weiterhin. Mit ASM schiebt man nur Datenmengen (Byte, Hword, Word) durch die Gegend, man braucht dazu jedoch Offsets, um damit etwas anfangen zu können. Wie researche ich die denn? Du solltest dein TUT vielleicht mit derartiger Thematik erweitern. Und die SWI-Befehle aus dem BIOS. Ich meine, ich weiß, denke ich, welchen ich für mein Vorhaben brauceh, aber was dort steht, als definiton, was z.B: in r0 stehen muss. Ich zitiere einmal.
      Data header (32bit)
      Bit 0-3 Reserved
      Bit 4-7 Compressed type (must be 1 for LZ77)
      Bit 8-31 Size of decompressed data
      Repeat below. Each Flag Byte followed by eight Blocks.
      Flag data (8bit)
      Bit 0-7 Type Flags for next 8 Blocks, MSB first
      Block Type 0 - Uncompressed - Copy 1 Byte from Source to Dest
      Bit 0-7 One data byte to be copied to dest
      Block Type 1 - Compressed - Copy N+3 Bytes from Dest-Disp-1 to Dest
      Bit 0-3 Disp MSBs
      Bit 4-7 Number of bytes to copy (minus 3)
      Bit 8-15 Disp LSBs
      Ab "repeat below" hört es bei mir schon auf. Du solltest vielleicht doch mehr darauf noch eingehen.
      mfg Wodka ;)
      Wo war Gondor, als meine Klausurenphase begann?

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Wodka ()

    • Du hast hier die Beschreibung des LZ77-Kompressionsformats vorliegen. zuerst 32bit/4Bytes Header-Daten, danach den aufbau der komprimierten Daten, und dieser wieder natürlich immer wieder wiederholt (repeatet)

      Ansich musst du dich damit aber nicht auskennen, da es zum einfügen Tools gibt und zum Dekomprimieren gibt es swi-Funktionen. Diese sind auf GBA-Tek zu finden, wie auch eine grobe übersicht über die RAM, genaueres ist vom Spiel abhängig und muss geresearcht werden. Dieses Tut könnte dir dabei helfen: sfc.pokefans.net/3-suche-unbekanntes aber auch hier gibt es mehrere Tuts und mit der Zeit wirst du auch eigene "Researchstrategieren" entwickeln bzw diese oder schon zuvor erlernte effizienter zusammen fügen können.
      Users[4939].postCount++;

      • Weltherrschafts AG in Cooperation mit Weltuntergangs GmbH:
        "Wir sorgen dafür, dass sie sich keine Sorgen um Morgen machen müssen!"
    • Zu deiner ersten Frage, ich kenne "bx lr" nur in dem zusammenhang, dass es wie in XSE ein "return" ist, wenn du vorher ein "bl .Ort" hast.
      Beispiel

      Quellcode

      1. code
      2. bl .Ort
      3. code
      4. .Ort:
      5. code
      6. bx lr

      bl = call ; bx = return. Mithilfe von bl wird hat sozusagen in lr die aktuelle Stelle geschrieben (wie ein 2. push {lr}). Also so wie ich das bis jetzt verstanden habe, falls es nicht stimmt steinigt mich! :3
      (s. nocash.emubase.de/gbatek.htm#thumb19longbranchwithlink)

      Zu deiner zweiten Frage: Musst du glaub ich gar nicht verstehen. :P Also keine Ahnung, weil es ganz simpel ist, du gibst einfach das "Bild" Offset an.
      (s. board.romhackersworld.eu/board…/6352-asm-by-prime-dialga)
    • Also ich bisher diesen Codeschnipsel mit Laz0r "gelernt"


      Quellcode

      1. .thumb
      2. .align
      3. ldr r0, .source
      4. ldr r1, .destination
      5. swi 0x12
      6. .align2
      7. .source
      8. .word 0x[Bildoffset]
      9. .align2
      10. .destination
      11. .word 0x[Zieloffest im Vram]
      Alles anzeigen


      Damit schreibe ich dann (hoffentlich) meine Grafik ins Vram. Wie lasse ich die dann anzeigen?
      Wo war Gondor, als meine Klausurenphase begann?