Seite 1 von 1

(erledigt) [C++] Array Funktionszeiger Compile-Time-konstant

Verfasst: 06.06.2010, 18:44
von Krishty
Hi,

Gibt es zufällig eine Möglichkeit, ein Array von Funktionszeigern schon zur Compile-Time zu initialisieren?
Selbst, wenn nicht (afaik sind Win32-PEs ja kein position-independent code?) – der Compiler (VS 2010) sorgt dafür, dass die Laufzeitinitialisierung des Arrays als endlose Liste von movs geschieht. Könnte ich ihn zumindest dazu kriegen, dafür SSE zu benutzen?

Gruß, Ky

Edit: Kurzfassung: Compiler-Bug; wird in nächster Zeit nicht behoben, möglichst das & weglassen.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 18:47
von zwergmulch
Das sollte vlt. mit constexpr aus C++0x gehen. Wird aber imho noch nicht von VS 2010 unterstützt.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 18:56
von Krishty
Das ging schnell :)

Ich glaube nicht, dass constexpr einen Unterschied machen wird – das Array ist static const deklariert, er würde also garnicht erst kompilieren, wenn in der Initialisierung keine Compile-Time constant expression stünde. Auch sind Funktionszeiger keine Daten, die von Anfang an feststehen, sondern erst zu Laufzeit. Der Compiler kennt während des Linkvorgangs erst die Offsets der Funktionen von der Basisadresse des Moduls, die sich beim Laden möglicherweise noch ändern, wenn die bevorzugte Basisadresse schon belegt ist.

Die Frage ist also eher, wie ich den Compiler dazu kriege, dieses Array als für die Relocation-Table der Exe gedacht zu erkennen.

Meine Kenntnisse um die PE-Internals und alles außerhalb der main() sind leider nicht sehr tiefgreifend – darum ist alles, was ich hier schreibe, ins Blaue geraten und vielleicht komplett falsch.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 19:26
von Aramis
afaik sind Win32-PEs ja kein position-independent code?
Ja, relocatable (mit den bekannten Vor– und Nachteilen im Vergleich zu Linux’ ELF). Die /FIXED–Option fuer den Linker hast du probiert?

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 19:52
von Krishty
Keine Veränderung außer, dass er andere Register benutzt, um die Ziele der movs anzugeben :/

Achja, lohnt sich eigentlich /DYNAMICBASE, d.h. erschwert das die Entwicklung von Trainern und Cheat-Tools?

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 20:44
von Aramis
Die Startup–Zeit verschlechtert sich wegen dem Rebasing, Cheater abhalten kannst du sowieso nicht. /DYNAMICBASE ist als Sicherheitsfeature gedacht – eingeschleuster Code ist ja oftmals winzig, das Ermitteln der korrekten Basisadresse ist alse ein Showstopper. Ein Cheat, Crack oder Trainer hingegen ist ja meist ein vollwertiges Programm, wird also dadurch nicht aufgehalten.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 20:58
von Krishty
Naja, zumindest Trainer sind meist extern und dürften mit dem Manipulieren des Prozessspeichers bedeutende Probleme haben sobald sie nicht mehr wissen, wo der Stack anfängt. Aber sei’s drum, mit der .reloc-Section wären wieder 20 KiB weg.

Das ursprüngliche Problem bleibt aber bestehen. Ich finde haufenweise Threads aus dem Embedded-Programming-Bereich, wo gefragt wird, wie Arrays von Funktionszeigern im ROM statt RAM landen … überall funktioniert es, sobald const oder static const dran stehen. Bei mir mit Win32 aber nicht. Ich werde gleich mal eine kleine Testanwendung bauen um zu sehen, ob es an mir oder an dem Compiler liegt … habe keine Lust, schon wieder einen Bug zu melden.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 21:25
von Aramis
Der Stack ist von Dynamic Basing nicht betroffen, denke ich. Nur die Stelle, an der das Betriebsystem PE–Images in den Adressraum hineinmap’d.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 21:28
von Krishty
Laut Wikipedia schon. Naja, sonst wäre das Ganze auch ziemlich wenig effektiv.

Bei einem Miniprojekt optimiert er das Erzeugen des Tables übrigens weg. Ich muss also mal genauer nachbohren ob nun Templates, Multi-Dimensionality des Arrays, seine pure Länge oder meine Dummheit verantwortlich sind.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 21:29
von Aramis

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 21:39
von Krishty
Okay, habe es: Wird das Array so initialisiert

Code: Alles auswählen

static void (* const Functions[])() = { &FuncA, &FuncB };
, landet für jedes Element ein mov in der Exe. Wird das Array so initialisiert

Code: Alles auswählen

static void (* const Functions[])() = { FuncA, FuncB };
, landet alles in der Read-only-Section und es entsteht kein Run-Time-Overhead.

Ist eines von beiden vielleicht eine Microsoft-Extension? Ist es legal, Funktionsadressen mit & abzufragen? Macht das einen Unterschied (funktionell scheint das gleiche zu passieren)? Ich finde im Netz auf die Schnelle nur die Variante ohne & …

Wahnsinn, das & hat mich 7 KiB .text und 3 KiB .data gekostet. Das war die Optimierung mit dem größten Ursache-Wirkung-Verhältnis meiner bisherigen Programmierlaufbahn.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 21:50
von Aramis
Ist es legal, Funktionsadressen mit & abzufragen?
Ich mag mich schon wieder irren, aber ich glaube, ‘&’ auf eine Funktion angewandt liefert einen Pointer auf sie, einfach nur der Funktionsname eine Referenz.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 06.06.2010, 21:53
von Krishty
Ja, ich mag dir auch nicht aufbürden, dich für Details einer so missgeborenen Syntax durch den Standard zu wühlen. Hier wird gesagt, dass das Weglassen des & nicht portabel sei. Sollte das zutreffen, geht morgen mein Bug-Report raus.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 07.06.2010, 16:31
von Krishty
Sooooooo.

Mal die Ergebnisse meiner Recherche:

• & kann man benutzen, muss man aber nicht. Da man Funktionen nur für zwei Dinge benutzen kann (zum Aufrufen oder zum Abholen der Adresse) wird im nicht-Aufruf-Fall implizit zum Funktionszeiger gecastet.

• Das Array wird nur dann zur Laufzeit initialisiert, wenn die Funktionen, deren Adressen man nimmt, Templates sind. Mit C-Funktionen funktioniert es immer korrekt, egal, ob ein & vor der Funktion hängt oder nicht.

Darum gehe ich davon aus, dass das ein Bug ist und habe einen entsprechenden Report mit kurzem, einprägsamem Titel abgeschickt. Wen es interessiert und/oder wer ihn reproduzieren kann, ist zum Voten eingeladen.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 07.06.2010, 16:43
von Aramis
Zu 1.: das entspraeche meinem Verstaendnis des Sprachstandards:
  • Der Funktionsname alleine ist eine Referenz, d.h.

    Code: Alles auswählen

    void foo(int);
    void bar(int);
    
    void (&foo_ptr)(int) = foo;
    foo_ptr(4); // OK
    foo_ptr = bar; // ERROR, reference cannot be reassigned
    
  • Ebenso, der Funktionsname wird implizit nach T* (wobei T der function-type ist) konvertiert. Das gilt iirc nur fuer ‘normale’ Funktionen, Memberfunktionen unterstuetzen diese Konversion nicht, d.h.

    Code: Alles auswählen

    class MyClass
    {
       void foo(int) const;
    };
    
    void (MyClass::*myptr)(int) const = MyClass::foo; // ERROR, need explicit address-of
    MyClass().*myptr(4);
    
  • Ein & liefert einen Pointer auf die Funktion.

Re: [C++] Array von Funktionszeigern Compile-Time-konstant

Verfasst: 07.06.2010, 17:24
von Krishty
Das klingt äußerst plausibel. Wusste trotz Pointer-Hass und Referenzenliebe garnicht, dass es Funktionsreferenzen gibt … wieder was gelernt :)

Edit:
Microsoft hat geschrieben:The & operator seems to be be giving the notion to compiler that it is uninitialized data. This has a workaround by not using the & operator in the initialization of array.
Considering the priority of the issue and other blocking bugs we have , we will not be able to fix the issue for dev10. We have put the bug in pur database and will be looking at it in future releases.
Also, falls in geschwindigkeitskritischen Abschnitten Funktionszeiger auf Template-Funktionen genutzt werden, möglichst den &-Operator weglassen.