Forum: Compiler & IDEs Funktion an bekannter (konstanter) Adresse aufrufen


von speedy (Gast)


Lesenswert?

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.

von Oliver (Gast)


Lesenswert?

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

von Matthias (Gast)


Lesenswert?

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"

von speedy (Gast)


Lesenswert?

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.


von Rolf Magnus (Gast)


Lesenswert?

Es ist eine globale Variable. Die landen eher nicht in Registern.

von Rolf Magnus (Gast)


Lesenswert?

Ach, noch eine Frage: Warum definierst du foo als Zeiger auf eine 
Funktion, die ein "const void" zurückgibt?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

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.

von speedy (Gast)


Lesenswert?

>> 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.

von yalu (Gast)


Lesenswert?

> 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
Noch kein Account? Hier anmelden.