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


von sous (Gast)


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

von Marco S (Gast)


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
-

von Christoph _. (chris)


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.

von Roland Schmidt (Gast)


Lesenswert?

Schreibe im *.cpp-File:

#ifdef  __cplusplus
extern "C" {

void wait(void);

}
#endif

von Roland Schmidt (Gast)


Lesenswert?

Uups, zu langsam.

von sous (Gast)


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

von Rolf Magnus (Gast)


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.

von sous (Gast)


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

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.