www.mikrocontroller.net

Forum: Compiler & IDEs assembler-routinen in C++: function-names


Autor: sous (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich stelle mich vielleicht nur wieder zu dumm beim Druchsuchen der
Manuals und dieses Forums an, fand jedoch die Antwort bisher nicht:

Ich möchte eine Funtion in Assembler schreiben und von einem
Cpp-Programm aus aufrufen:

*.S-File:

.global wait
.func wait
wait:
// Assembler-Anweisungen



*.cpp-File:

void wait(void);

int main()
{
 wait();


}


Dieses geht schief, weil avr-gcc offenbar aus 'void wait(void)' den
Namen '_Z4waitv' generiert. (Habe durch Versuche herausgefunden, dass
immer '_Z + Anzahl der Buchstaben des Namens + Name + v' erzeugt
wird.)
Wenn ich in meinem *.S-File diesen kryptischen Namen einsetze, geht
es.

Wie kann ich erreichen, in meinem *.S-File nicht mit so kryptischen
Namen hantieren zu müssen?

Gruß, Michael

Autor: Marco S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael.

In meine Assemblerdatei (.S) schreibe ich:

        .section .text
        .global uuprintf_P
        .type   uuprintf_P, @function

uuprintf_P:
        ...

Das ganze wird mit:

avr-gcc  -Os -g3 -mmcu=atmega8 -Wa,-gstabs -c uuprintf.S

/bin/sh ../libtool --mode=link --tag=CC avr-gcc  -Os -g3 -mmcu=atmega8
-Wa,-gstabs   -o avrthermometer2   avrthermometer2.o sensor.o asmfkt.o
lcd.o mprintf.o uuprintf.o

unter KDevelop übersetzt. In avrthermometer2.c steht u.a:

const char pstr1[] PROGMEM = "Temp = %\000C     ";
extern void uuprintf_P(char *s, const char *ff, uint16_t n);
...
int main(void) {
   ...
   char A[20];
   uuprintf_P(A, pstr1, (uint16_t) ScratchPad[0]>>1);
   ...
}

und alles funktioniert ohne _Zxyv.


Vielleicht hilft es.

Gruß
Marco
-

Autor: Christoph __ (chris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Dieses geht schief, weil avr-gcc offenbar aus 'void wait(void)' den
> Namen '_Z4waitv' generiert. (Habe durch Versuche herausgefunden,
> dass immer '_Z + Anzahl der Buchstaben des Namens + Name + v'
> erzeugt wird.)

Dafür brauchst du genau genommen keine Versuche, sondern nur die Doku:
http://www.codesourcery.com/cxx-abi/abi.html#mangling
Aber zugegeben, diese Doku ist nichts, was man so nebenbei mal
überfliegt, und meistens muss man das so genau gar nicht kennen. Wie so
häufig gilt auch hier: Wichtig ist zu wissen, dass es so etwas gibt,
nicht wie genau es funktioniert (grobe Implementierungskenntnisse
können aber nie schaden).

Mit "so etwas" meine ich das "name mangling", eine Eigenart von
C++. C++ unterstützt Überladung und namespaces. Beides bewirkt, dass
Funktionen mit ein und demselben Namen mehrmals existieren können.
Damit da nichts kollidiert, hat man zwei Möglichkeiten:
1. Den Linker und das Format der kompilierten Zwischendateien
anpassen.
2. Die ganzen zusätzlichen Infos in die Funktions- und Klassennamen
kodieren und den gewöhnlichen C-Linker nehmen.

Man hat sich für zweitens entschieden. Deswegen wird aus "void
wait()" ein "_Z4waitv", damit z.B. gleichzeitig eine Funktion "void
wait(int)" existieren kann (letzteres würde zu "_Z4waiti" werden).

Für einzelne Funktionen kann man das deaktivieren, indem man extern
"C" davor schreibt:

extern "C" void wait();

Dann wird der Funktionsname nicht dekoriert, allerdings kann man die
Funktion (logischerweise) nicht mehr überladen.

Autor: Roland Schmidt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schreibe im *.cpp-File:

#ifdef  __cplusplus
extern "C" {

void wait(void);

}
#endif

Autor: Roland Schmidt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uups, zu langsam.

Autor: sous (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank Euch allen!

@Christoph:
Super Erklärung, jetzt versteh' ich, was dahinter steckt. Wenn ich das
File als *.c speichere und compiliere, tritt das Ganze (logischer Weise)
nicht auf.

@Marco S:
Danke auch Dir, wie schon erwähnt, ist es ein reiner C++-Effekt, der
bei Dir daher nicht auftritt.

@Roland Schmidt:
Durchaus nicht zu langsam! Du hast mir gezeigt, wie man das 'extern
"C"' für mehrere Funktionen kürzer schreiben kann, also auch Dir
vielen Dank!

Gruß, Michael

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Schreibe im *.cpp-File:
>
> #ifdef  __cplusplus
> extern "C" {
>
> void wait(void);
>
> }
> #endif

Komplett wäre es so:

#ifdef  __cplusplus
extern "C" {
#endif

void wait(void);

#ifdef  __cplusplus
}
#endif

Denn die Deklaration soll ja auch dann vorhanden sein, wenn man das als
C compiliert. Es soll nur nicht in einem  extern "C" block stehen.

Autor: sous (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank auch für diesen Hinweis. Das wäre bei mir wahrscheinlich nie
aufgefallen, da ich immer *.cpp-Files habe und alles als C++
compiliere.

Gruß, Michael

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.