Das Übersetzen dieses Programmes #include <avr/io.h> const void (*foo)(void) =0; int main(void) { foo(); return 0; } erzeugt folgenden code: 0000005c <main>: 5c: cf e5 ldi r28, 0x5F ; 95 5e: d4 e0 ldi r29, 0x04 ; 4 60: de bf out 0x3e, r29 ; 62 62: cd bf out 0x3d, r28 ; 61 64: e0 91 60 00 lds r30, 0x0060 68: f0 91 61 00 lds r31, 0x0061 6c: 09 95 icall 6e: 80 e0 ldi r24, 0x00 ; 0 70: 90 e0 ldi r25, 0x00 ; 0 72: 00 c0 rjmp .+0 ; 0x74 ich hätte aber erwartet, dass bei den Adressen 64..6d folgendes steht: 64: e0 91 00 00 lds r30, 0x0000 68: f0 91 00 00 lds r31, 0x0000 6c: 09 95 icall Warum ist das nicht so ??? Ich möchte erreichen, dass ich eine Funktion an einer bekannten Adresse ausführen kann. Damit will ich erreichen, dass ich Code der sich im Bootloader eines ATmega befindet auch im Anwenderprogramm nutzen kann.
Fragen, warum der gcc etwas genau so, und nicht anders macht, sind selten sinnvoll zu benatworten. Aber in den allermeisten Fällen funktioniert das :-) const void (*foo)(void) =0; legt einen Datenbereich für einen Pointer auf eine Funktion an. Der liegt, aus Gründen unerfindlicher Weisheit von Compiler und Linker, an den Adressen 0x060 und 0x061 im Datenspeicher, und wird mit an Sicherheit grenzender Wahrscheinlichkeit vor dem Aufruf der Funktion main() mit dem Wert 0x0000 initialisiert. (sollte sich im Code finden lassen) lds r30, 0x0060 lädt den INHALT von Datenadresse 0x60, also 0x00. Oliver
Ich glaube, Oliver hat recht. Ich möchte eine Variable an eine bestimmte Stelle im RAM setzen, und verwende eine ähnliche Syntax. Nach begutachten des ASM-Codes steht aus sowas da wie: Lade Z-Pointer mit var aus ram greife auf Z-Pointer zu.. diese "var aus ram" beinhaltet genau meine gewünschte speicherzelle. Bei dir ist genau dasselbe passiert: Der Compiler speichert deine Adresse 0x0000 auf 0x60/0x61 und lädt das dann ins Z-Register zur Weiterverwendung.. Warum er hier nicht das Z-Register direkt lädt, weiß ich auch nicht... Hier der Topic: Beitrag "variable im externen RAM"
Danke für die Erklärungen. Ich habe LDS mit LDI verwechselt ;) Nach nochmaligem nachschauen im Datenblatt der MCU ist auch klar, warum die Adressen 0x60 und 0x61 verwendet werden. Dort beginnt der RAM Bereich die Adressen 0x00 bis 0x5f sind von Regisetern und IO Adressen belegt. Ich habe irgendwie erwartet, der GCC sieht den Zeiger auf die Funktion foo() als Konstante an. Aber ist schon richtig. Warum sollte er das tun.
Es ist eine globale Variable. Die landen eher nicht in Registern.
Ach, noch eine Frage: Warum definierst du foo als Zeiger auf eine Funktion, die ein "const void" zurückgibt?
Wenn du eine Konstante dafür haben willst, solltest du es dem Linker überlassen. Ich habe aus einem anderen Anlass neulich das beigefügte Beispiel mal geschrieben. Das implementiert eine "shared library", also einen Zugriff auf vorgelinkte Funktionen an einer festen Stelle im ROM. Das ist sehr ähnlich zu deinem Problem (außer dass du noch einen Resetvektor für den Bootload in der Sprungtabelle ganz am Anfang brauchst), und sollte sich einfach anpassen lassen.
>> Ach, noch eine Frage: Warum definierst du foo als Zeiger auf eine >> Funktion, die ein "const void" zurückgibt? Hallo Rolf, der Rückgabewert const void der Funktion war der vergebliche Versuch einen Konstanten Zeiger auf ein Funktion zu definieren.
> Hallo Rolf, der Rückgabewert const void der Funktion war der > vergebliche Versuch einen Konstanten Zeiger auf ein Funktion zu > definieren. Um anzuzeigen, dass foo konstant ist, muss das const for dem foo, nicht vor dem Rückgabetyp stehen: void (*const foo)(void) =0; Wenn du dann noch die Optimierungsstufe -O2 wählst, kommt auch der erwartetet Code heraus: 52: cf e5 ldi r28, 0x5F ; 95 54: d2 e0 ldi r29, 0x02 ; 2 56: de bf out 0x3e, r29 ; 62 58: cd bf out 0x3d, r28 ; 61 5a: e0 e0 ldi r30, 0x00 ; 0 5c: f0 e0 ldi r31, 0x00 ; 0 5e: 09 95 icall 60: 80 e0 ldi r24, 0x00 ; 0 62: 90 e0 ldi r25, 0x00 ; 0 64: 00 c0 rjmp .+0 ; 0x66 <_exit>
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.