Funktionspointer

Gast #365949
Lesenswert?

Weil man das auch sonst nicht kann, jedenfalls nicht so. Wenn doch und
ohne Warnung, gib von mir eine Ohrfeige an den Compiler weiter.

0x1f14 ist nunmal kein Pointer, also stimmt der Typ nicht.

Besser:
typedef unsigned char (*myfcnptr)(unsigned char);
fcnptr fu_pointer = (fcnptr)0x1f14;

Empfehlen kann ich es freilich nicht. Denn ob das eine Byte- oder
Wortadresse ist, mag je nach Compiler verschieden sein.
Gast #365951
Lesenswert?

Hallo A.K.
Vielen Dank für die schnelle Antwort. Der Compiler meckert nicht mehr,
aber die Pointerinitialisierung funktioniert leider nicht richtig, da
beim Funktionsauruf im gestarteten Programm, die Funktion leider nicht
angesprungen wird sondern das Programm sich irgendwohin verirrt! Die
zugewiesene Funktions-Adresse (Funktion im Boot-Loader-Flash) ist
richtig (habe ich durch auslesen des Boot-Loader-Flash überprüft). Wie
kann ich die Zuweisung überprüfen (Mapfile oder sowas?).

Kurt
Gast #365953
Lesenswert?

Ja, aber ich bin doch hier im GCC-Forum und spreche doch auch vom GCC.
Also noch einmal meine zweite Frage: Wie kann ich überprüfen, ob die
initialisierung richtig vorgenommen wird (Mapfile oder so)? Übrigens,
laut C-Lehrbuch und auch Informationen aus dem Net, ist die Deklaration
eines Funktions-Pointers mit direkter Initialisierung in C wie:

unsigned char (*fu_pointer)(unsigned char) = 0x1f14;

richtig und dürfte vom Compiler nicht beanstandet werden!


HILFE..., Kurt
Gast #365956
Lesenswert?

Ich habe die Initialisierung des typedef-Funktions-Pointers (wie oben
von A.K. vorgeschlagen) mal innerhalb einer Funktion durchgeführt. Das
macht der Compiler dann aus dem Funktionsaufruf:

     fu_pointer(72);
  6e:  88 e4         ldi  r24, 0x48  ; 72
  70:  7f df         rcall  .-258      ; 0xffffff70
<__eeprom_end+0xff7eff70>

Der Funktions-Pointer ist mit der Adrese 0x1f14 initialisiert.

Wie kommt der Compiler darauf, dass sich die Funktion im EEPROM
befindet oder was bedeutet der angefügte eeprom-end-Kommentar? Muss ich
dem Compiler irgendwie mitteilen das es sich um eine Funktion im Flash
handelt?

Kurt
Gast #365957
Lesenswert?

Ich finde nicht, dass der Compiler die Funktion im EEPROM vermutet.

Wenn du deine normalen Daten im EEPROM liegen hast, liegt natürlich
auch die Variable fu_pointer im EEPROM.

Für den Funktionsaufruf sollte das keine Rolle spielen, wenn der Inhalt
der Variablen eine gültige Flash-Adresse einer Funktion ist.

D.h. wie kommst du auf den absoluten Wert 0x1f14?
Gast #365958
Lesenswert?

Dass hier EEPROM-Adressen angezeigt werden, hat weniger mit dem EEPROM
und viel dem etwas hilflosen Adressmapping vom Von-Neumann-GCC auf eine
Hardward-CPU zu tun, und dem verzweifelten Versuch des Disassemblers,
darin einen Sinn zu erkennen. Hilfreicher wäre es gewesen, den Typ vom
AVR und die Adresse den RJMP zu kennen. Wenn es sich um einen 8KB-Typen
handelt, ist 0x1Fxx eine Byteadresse im Bootbereich am Ende vom Flash
und GCC will eine Wortadresse, also ist dann 0x1Fxx/2 richtig.
Persönliche Seite #365959
Lesenswert?

Hi

der GCC arbeitet AFAIK immer mit Byteadressen. Das was man da sieht ist
ein rjmp dessen negatives Argument dafür sorgt das es zu einem
Unterlauf kommt was der Dissasembler mit dieser riesigen Adresse
beantwortet. Was wirklich im Chip passiert ist ein Wrap-Around so das
der rcall dann irgendwo am oberen Ende des Flash endet.

Ich fürchte aber das sich Kurt irgendwie verrant hat und den Wald vor
lauter Bäumen nicht mehr sieht. Desshalb meine Frage an den OP: Was
soll das ganze werden?

Matthias
Gast #496557
Lesenswert?

Ich steh jetzt vor dem gleichen Problem:

#define APP_FLASH_SIZE 0x1800
typedef uint8_t (*CAN_FUNCTION)( CAN_MSG * );
#define rcvCan( X ) ( ((CAN_FUNCTION)( APP_FLASH_SIZE + 2 ))( X ) )
#define sndCan( X ) ( ((CAN_FUNCTION)( APP_FLASH_SIZE + 4 ))( X ) )

sndCan( msg );

daraus entsteht folgendes Listing:

  d0:  d5 db         rcall  .-2134     ; 0xfffff87c

wenn ich nun aber nachrechne ( 0xd0 - 2134 + 0x2000 ) ergibt das nicht 
APP_FLASH_SIZE + 4 sondern APP_FLASH_SIZE + 4 + 0x78. 0x78 ist 
zufälliger weise die Größe der .vectors und .init sections. Wie sag' ich 
dem GCC jetzt das die Adresse eine absolute Adresse ist und nicht eine 
im .text Segment?
Moderator Persönliche Seite #500088
Lesenswert?

Das Beispiel ist ein wenig komplex, habe ich gerade nicht (getestet)
zur Hand.

Im Prinzip ungefähr so: statt des normalen Startups setzt du an den
Anfang des Bootloaders eine Sprungtabelle:
1
rjmp   bootload  ; reset vector
2
rjmp   thisfunc
3
rjmp   thatfunc
4
rjmp   whatever

Die daraus assemblierte Objektdatei wird beim Linken als erstes
angegeben.

Für die normale Applikation links du die folgende Datei mit hinzu,
um auf diese Sprungtabelle zuzugreifen:
1
#define bl_offset 0x1800
2
#define sizeof_rjmp 2
3

4
.equ bootload,  bl_offset + 0
5
.equ thisfunc,  bl_offset + 1 * sizeof_rjmp
6
.equ thatfunc,  bl_offset + 2 * sizeof_rjmp
7
.equ whatever,  bl_offset + 3 * sizeof_rjmp

Wie geschrieben, ist alles ungetestet, aber sollte dir zumindest die
Idee bringen.
Gast #500165
Lesenswert?

Im Prinzip benutzt man auf diese Weise ja unbenutzte 
Bootloader-IR-Einsprünge.

Am Schönsten wäre es, wenn man ein Makro ähnlich wie SIGNAL oder 
INTERRUPT schreiben würde, welches den Vektor automatisch setzt, aber 
einen normalen Funktionsaufruf statt eines IRs generiert.

Auf diese Weise kommt man auch weniger mit vom Bootloader benutzten 
Interrupts in die Quere.

Gruß, Stefan
Gast #500174
Lesenswert?

Nochmal zu Byte- und Wortadressen: Es stimmt schon, dass GCC und 
insbesondere die Binutils mit Byteadressen rechnen. Die Maschine 
allerdings sieht das anders und daher muss man höllisch aufpassen wer 
da grad rechnet und ob er weiss womit er rechnet.

GCC erlaubt von Haus aus keine Rechnung mit Codeadressen und kennt auch 
keine numerischen Konstanten von Codeadressen (mit diesem Problem fing 
der Thread ja an). Wenn man nun per type-cast eine numerische Konstante 
in einen Funktionszeiger umwandelt, dann findet keine Umrechnung 
zwischen Byte- und Wortadresse statt und die angegebene Zahl wird direkt 
als (Wort-) Adresse verwendet.

Im Beispiel am Anfang dieses Threads wird also die Wortadresse 0x1f14 
angesprungen. Bei einem Mega8 existiert diese Adresse überhaupt nicht. 
Korrekt wäre also "... = 0x1f14/2" gewesen.

Analog muss auch beim Problem von m4444x in Worten gerechnet werden:

#define APP_FLASH_SIZE (0x1800/2)
typedef uint8_t (*CAN_FUNCTION)( CAN_MSG * );
#define rcvCan( X ) ( ((CAN_FUNCTION)( APP_FLASH_SIZE + 1 ))( X ) )
#define sndCan( X ) ( ((CAN_FUNCTION)( APP_FLASH_SIZE + 2 ))( X ) )
Gast #500541
Lesenswert?

Kann man so etwas micht über den Linker machen?

Also eine Funktion deklarieren (aber nicht definieren) und beim Linken 
dann die Adresse dieser Funktion per Option setzen.

So, oder so ähnlich müsste das gehen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren