Hi, ich verwende ein STM32F4 Board mit FreeRTOS und ich versuche gerade, mein Assembler etwas zu verbessern. unsigned int my_pc = 0x08000890; _asm __volatile_ ( "movw R1, #0x0fd0\n" "movt R1, #0x1000\n" "ldr r15,[r1]\n" ); Ich speichere in my_pc einen gewünschen, neuen Program-Counter. Der Wert 0x08... ist der PC an der Stelle unsigned int my_pc. Dannach lade ich mir diesen Wert in Register R1 - dabei ist 0x10000fd0 die Adresse im Speicher, wo my_pc liegt. Nun möchte ich meinen tatsächlichen PC abändern, sodass ich erneut bei unsigned int my_pc lande. Mit gdb habe ich rausgefunden, dass ich R1 nun tatsächlich 0x10000fd0 steht. Allerdings komme ich hier in den Trap handler: prvGetRegistersFromStack (pulFaultStackAddress=0x10000f90 Wieso stimmt die Adresse nicht überein? Verwende ich nun diesen Code, funktioniert mein Vorhaben wie gewünscht: unsigned int my_pc = 0x08000890; _asm __volatile_ ( "movw R1, #0x0fd0\n" "movt R1, #0x1000\n" "ldr r4,[r1]\n" "mov pc,r4\n" ); Wo liegt hier das Problem?
Das unterste Bit der Adresse muss 1 sein, sonst weist du den Prozessor an, in den ARM-Modus zu wechseln, was der Cortex-M4 nicht kann. Ich würde dir empfehlen, erstmal nur mit nacktem Assembler anzufangen, weil Inline Assembler noch eine ganze Reihe an Tücken hat und auch noch schlecht dokumentiert ist.
PS: Direkt in den PC eine Adresse zu schreiben ist etwas unüblich und hat gewisse Einschränkungen - normalerweise nimmt man dafür die Branch-Anweisung "B".
Auf einem Cortex-M kann man keinen graden Wert in den PC laden => Thumb-Bit muss gesetzt sein, sonst Fault. In der Version die funktionier muss also noch was anders sein. Noch eine Kleinigkeit: Der Wert im PC selbst ist grade, wenn man den ausliesst. Die "push PC" und BL/BLX Instruktionen handhaben das mit dem Thumb Bit korrekt AFAIK (so das man den Wert hinterher einlesen kann, Bit 0 hat den Wert 1).
Jim M. schrieb: > In der Version die funktionier muss also noch was anders sein. Bei manchen Schreib-Operationen auf den PC wird das Thumb Bit ignoriert, und der aktuelle Modus beibehalten. Welche das sind kann ich mir aber auch nicht merken :) "B" schaltet nicht um, "BX" schon, und nur letzteres kann man mit Registern als Ziel nutzen.
1 | unsigned int my_pc = 0x08000890; |
2 | void foo() { |
3 | asm("bx %0"::"r"(my_pc)); |
4 | //oder
|
5 | goto *my_pc; |
6 | }
|
1 | foo: |
2 | push {r7} |
3 | add r7, sp, #0 |
4 | |
5 | movw r3, #:lower16:my_pc |
6 | movt r3, #:upper16:my_pc |
7 | ldr r3, [r3, #0] |
8 | bx r3 |
9 | |
10 | movw r3, #:lower16:my_pc |
11 | movt r3, #:upper16:my_pc |
12 | ldr r3, [r3, #0] |
13 | orr r3, r3, #1 |
14 | bx r3 |
Schon richtig, wenn die Befehle verfügbar sind: unbedingter Sprung, sonst Push-Pop.
kilaz schrieb: > unsigned int my_pc = 0x08000890; > _asm __volatile_ > ( > "movw R1, #0x0fd0\n" > "movt R1, #0x1000\n" > "ldr r15,[r1]\n" > ); Das kann (neben dem schon erwähnten Thumb-Bit) gut gehen oder auch nicht (je nachdem, was sonst noch an C-Code aussenrum ist). Wenn Du dem C-Compiler Register klaust, ohne ihm das mitzuteilen, geht das früher oder später schief. Lies' dir das Kapitel "extended asm" im gcc-Handbuch aufmerksam durch.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.