g++ inline assembler



  • die hab ich scho gekannt. und im allgemeinen funktioniert es auch, aber sobald ich ecx in die clobbered list setz, behauptet der g++, dass er dieses register nicht kennt.

    was ich überhaupt machen will:
    ich habe eine klasse memory. diese hat zwei eigenschaften: selector und offset. diese geben den beginn eines stückes speichers an. um innerhalb des segments dann auf einzelne byte zuzugreifen, kommt noch eine variable index hinzu.
    dh das byte, dass ich adressieren will ist: segment_base + offset + index.

    jetz offtopic (bitte seid nachsichtig):
    wenn ich in c++ char* adresse = 0x12345678; schreib, welches segment wird dann beim zugriff verwendet?



  • Original erstellt von <someone>:
    die hab ich scho gekannt. und im allgemeinen funktioniert es auch, aber sobald ich ecx in die clobbered list setz, behauptet der g++, dass er dieses register nicht kennt.

    Was setzt du denn genau rein? c, ecx, %ecx, %%ecx?

    jetz offtopic (bitte seid nachsichtig):
    wenn ich in c++ char
    adresse = 0x12345678; schreib, welches segment wird dann beim zugriff verwendet?
    *

    Das Datensegment dürfte dafür verwendet werden.



  • das ist egal, was ich reinscheib. das ergebnix ist immer das gleiche.

    dürfte? ich muss es sicher wissen. soll ich das in einem anderen forum fragen? ist das hier das falsche oder? so weit ich weiß, verwendet der g++ für lokale variablen den stack und für dynamische ein datensegment.

    wie kann ich ein bestimmtes segment verwenden? das ist ziemlich wichtig. oder kann ich das mit g++ nicht?

    danke für die hilfe bisher



  • Original erstellt von <someone>:
    **dürfte? ich muss es sicher wissen. soll ich das in einem anderen forum fragen? ist das hier das falsche oder?
    **

    "dürfte" war mehr eine rhetorische Klausel 🙂 Unter normalen 32-Bit benutzt der GCC das Datensegment dafür. Wenn du natürlich in einer hochsegmentierten Umgebung wie DJGPP arbeitest und far-pointer zur Verfügung hast, könnte der Compiler sich auch ein Register (z.B. fs oder gs) bereitlegen um sowas auszuwerten.

    **
    so weit ich weiß, verwendet der g++ für lokale variablen den stack und für dynamische ein datensegment.
    **

    Der g++ verwendet selber garnicht Segmente. Er legt lokale Variablen auf dem Stack an und dynamische werden normal Adressiert. Das Betriebssystem legt in Flat-Umgebungen 4GB umspannende Segmente an und aufgrund der verwendeten Adressierung im assemblermodus landen lokale variablen dann im Stacksegment und alles andere im Datensegment.

    **
    wie kann ich ein bestimmtes segment verwenden? das ist ziemlich wichtig. oder kann ich das mit g++ nicht?
    **

    Eventuell kann der DJGPP für DOS sowas, bin ich aber nicht sicher. Ansonsten hat der GCC selber keine solche fähigkeiten weil er eben für 4GB-Flat-Adress-Umgebungen geschaffen wurde. Da müsstest du dann mit inline-ASM angreifen



  • ok danke

    ist es sicher, dass ich mit inline assembler erfolg habe und dem gcc das beibringen kann, dass er segmente in der form verwendet?

    darf ich code posten, den du mir dann mal kurz durchsiehst, um mir zu sagen, ob der funktionieren würde? es ist nur sehr wenig.



  • Original erstellt von <someone>:
    ist es sicher, dass ich mit inline assembler erfolg habe und dem gcc das beibringen kann, dass er segmente in der form verwendet?

    Nun, wie gesagt, der gcc wird sichelrihc immer das Datensegment/Stacksegment benutzen. Du kannst aber sicherlich einzelne Zugriffe üebr Inline-Assembler in anderen Segmenten stattfinden lassen, bin leider auch nicht der Experte in GCC-Inline-ASM, mir liegt der NASM näher 🙂

    **
    darf ich code posten, den du mir dann mal kurz durchsiehst, um mir zu sagen, ob der funktionieren würde? es ist nur sehr wenig.**

    Ich kanns versuchen, und ansonsten laufen heir auhc noch einige andere sehr fähige Leute rum. Also immer her damit 🙂



  • ich hoff das mit dem ubb code klappt....
    das wär der code. segment is nur eine klasse die _selector hergibt mehr nicht.

    #ifndef MEMORY_H
      #define MEMORY_H
    
      #include "include/segment.h"
    
      namespace kernel {
        class memory : public segment {
          protected:
            unsigned long _offset;
            unsigned long _size;
    
          public:
            memory(void) : segment() {
              _offset = 0;
              _size = 0;
            }
            memory(unsigned short selector, unsigned long offset, unsigned long size) : segment(selector) {
              _offset = offset;
              _size = size;
            }
    
            inline memory& operator=(memory& other) {
              register const unsigned long length = (_size <? other._size);
                asm volatile (
                  "movw %%ds, %%bx \n\t"
                  "movw %%es, %%ax \n\t"
                  "cld \n\t"
                  "rep \n\t"
                  "movsl"
                  :
                  : "a"(_selector), "b"(other._selector), "c"(length), "S"(other._offset), "D"(_offset)
                  : "memory"
                );
              return *this;
            }
            inline unsigned char at(register const unsigned long index) {
              unsigned long buffer;
              asm (
                "movw %%ds, %%ax \n\t"
                "xorl %%eax, %%eax \n\t"
                "lodsb"
                : "=a"(buffer)
                : "a"(_selector), "S"(index + _offset)
                : "memory"
              );
              return (unsigned char)buffer;
            }
            inline void at(register const unsigned long index, register const unsigned char value) {
              asm (
                "movw %%es, %%bx \n\t"
                "stosb"
                :
                : "a"(value), "b"(_selector), "D"(index + _offset)
                : "memory"
              );
              return;
            }
        };
      };
    
    #endif
    

    könnten durch das setzen der codesegmente gravierende performance einbrüche entstehen?



  • Original erstellt von <someone>:
    könnten durch das setzen der codesegmente gravierende performance einbrüche entstehen?

    Zum Code: sofern der gas jetzt nichts gegen %%ds und %%es hat, kompiliert es zumindest. Du solltest überlegen, ob die DS und ES nicht vielelicht am Ende der Funktion wiederherstellst.

    Ob der gcc damit zufrieden ist, ist ne andere frage. Was Performance angeht, nun ein Codesegment wurde hier nirgends gesetzt 🙂 Aber DS und ES und das Laden eines Segmentdeskriptors im Protected Mode ist zumindest mit einigen Prüfungen verbunden. Man sollte es nicht zu oft machen würde ich sagen, weil es nunmal einen Moment dauert, zu checken ob alle Bedingungen erfüllt sind. Auf dem Pentium dauerte es 2-11 Takte + 8 Takte für einen Deskriptor der nicht im Cache ist. Sagen wir mal, auch heute wird es nicht hochperformant sein 🙂

    [ Dieser Beitrag wurde am 28.04.2003 um 17:57 Uhr von TriPhoenix editiert. ]



  • der g++ will das %%. compilieren tut er es, ohne irgendwas zu meckern.

    geht der prozessor also davon aus, dass zwischen dem setzen des segmentregisters und allen folgenden zugriffen, die rechte des segments gleich geblieben sind? trotzdem muss er bei jedem zugriff nachsehen, ob er lesen oder schreibend ist und erlaubt ist. das muss er nicht nur beim setzen des registers. das einzige, was sicher zeit braucht ist das laden aus der gdt/ldt.

    im prinzip heißt das, dass man entweder sicherheit hat, oder performance. was ist jetzt wichtiger? oder schafft man es vielleicht mit hilfe der register gs und fs einen kompromiss zufinden. das problem sind zb die string befehle, die nur mit ds und es arbeiten.



  • Original erstellt von <someone>:
    der g++ will das %%. compilieren tut er es, ohne irgendwas zu meckern.

    Das ist ein gutes Zeichen.

    **
    geht der prozessor also davon aus, dass zwischen dem setzen des segmentregisters und allen folgenden zugriffen, die rechte des segments gleich geblieben sind? trotzdem muss er bei jedem zugriff nachsehen, ob er lesen oder schreibend ist und erlaubt ist. das muss er nicht nur beim setzen des registers. das einzige, was sicher zeit braucht ist das laden aus der gdt/ldt.
    **

    Es macht shcon einen Unetrschied ob man ein Register lädt oder auf eines zugreift. Beim laden des Registers wird zuerst der Deskriptor aus dem Speicher geholt. Dann wird gecheckt ob der DPL z.B. stimmt und alle Rechte in Ordnung sind. Ist das alles ok, dann wird der Deskriptor in interne segment-cache-register geladen. Dort wird dann nur noch gecheckt ob lesen/schrieben erlaubt ist, und da die Segmentcaches im Prozi liegen geht das unglaublich schnell.
    Ergo komtm beim ladne dazu: Deskriptor aus dem Speicher holen, DPL/CPL/RPL checken. Typ überprüfen etc. Das entfällt alle sbiem Zugriff, der check ob de rZugriff erlaubt ist ist parallel zur Ausführung des Befehles machbar und damit vernachlässigbar klein.

    **
    im prinzip heißt das, dass man entweder sicherheit hat, oder performance. was ist jetzt wichtiger?**

    Deswegen nutzen die meisten OS heutzutage keine Segmentierung. Wenn man ständig Segmentregister hin und herladen muss, dauert das. Außerdem ist es ein unpraktisches Modell. Die Paging-Mechanismen reichen grundsätzlich aus um z.B. user- und kernel-mode zu trennen und sind ausreichend schnell. Dann braucht man die Segmentregister nämlcih nur einmal zu laden (natürlich für den Kernel/User-Wechsel immer) aber nicht mehr zwischendruch.

    oder schafft man es vielleicht mit hilfe der register gs und fs einen kompromiss zufinden. das problem sind zb die string befehle, die nur mit ds und es arbeiten.[/QB][/QUOTE]
    Sicher, dass man denen keinen Segment-Override andrehen kann? Ansonsten wären FS/GS wirklcih eine gute alternative. Dann lädt man die Dinger einmal am Anfang und lässt sie dann in Ruhe.



  • vielleicht könnte man durch segmentierung andere gebiete beschleunigen. zb das relozieren. dh, man verwendet für libs segmente oder so und statt hier viel zu relokieren wird einfach das segment geändert. ich muss aber zu geben, dass ich wenig ahnung vom relozieren hab.

    die andere frage ist, ob überhaupt viele änderungen von segment registern nötig sind. wenn man einmal den stack und sein segment außer acht lässt, dann könnte man doch alle anderen daten eines prozesses, auf die schreibend und lesen zugegriffen würden müssen, in einem segment behalten. ein großer teil des speicherzugriffs wird hier stattfinden. dazu gibts eine neue klasse, die die segment register nie verändert.

    um auf system segmente zuzugreifen, verwendet man dann eine andere klassen, die die segment register zwar ändern, aber auch wieder herstellt. das braucht dann zwar noch länger, aber ich denk, der zugriff auf system segmente ist deutlich geringer als auf das datensegment des prozesses.

    der sinn des ganzen ist, dass ich gern maximale sicherheit haben möchte. möglicherweise kann man in anderen gebieten zeit einsparen.
    die frage ist jetzt, wie stark die performance sinkt. kann man das irgendwie voraussagen? ich mein eine allgemein-performance, wenn man davon ausgeht, dass der rest gleich schnell ist wie zb linux, aber segmentierung verwendet wird. halb so schnell? nur mehr ein viertel? oder 1% performanceverlust? weniger als das?



  • Kann man da nicht einfach eine Simulation schreiben die genau so viele Überprüfungen tätigt (müssen ja keine richtigen sein einfach 2 Operanden vergleicht so oft wie es in "echt" auch gemacht wird) wie das Laden von Segmenten über Deskriptoren oder ob man eben keine Segmentierung verwendet? Wäre sicher etwas Aufwand aber besser als später ein langsames OS zu haben 😃

    Kevin



  • Original erstellt von <someone>:
    vielleicht könnte man durch segmentierung andere gebiete beschleunigen. zb das relozieren. dh, man verwendet für libs segmente oder so und statt hier viel zu relokieren wird einfach das segment geändert. ich muss aber zu geben, dass ich wenig ahnung vom relozieren hab.

    Da ist wohl was dran. Nur hast du dann für jeden Library-Call einen kompletten Codesgementwechsel und die sind nicht die schnellsten. Ich denke der Effekt gleihct sich im Endeffekt aus. Nur gehtd as Relozieren einmal am Anfang während das mit den Segmenten bei jedem Aufruf wirkt.

    **
    die andere frage ist, ob überhaupt viele änderungen von segment registern nötig sind. wenn man einmal den stack und sein segment außer acht lässt, dann könnte man doch alle anderen daten eines prozesses, auf die schreibend und lesen zugegriffen würden müssen, in einem segment behalten. ein großer teil des speicherzugriffs wird hier stattfinden. dazu gibts eine neue klasse, die die segment register nie verändert.

    um auf system segmente zuzugreifen, verwendet man dann eine andere klassen, die die segment register zwar ändern, aber auch wieder herstellt. das braucht dann zwar noch länger, aber ich denk, der zugriff auf system segmente ist deutlich geringer als auf das datensegment des prozesses.**

    Das stimmt. Und beim wechsel in den Systemcode muss man sowieso die Segmente wechseln, egal ob man nun ein Flat-Modell oder ein Segmentiertes Modell nimmt.

    **
    der sinn des ganzen ist, dass ich gern maximale sicherheit haben möchte. möglicherweise kann man in anderen gebieten zeit einsparen.
    die frage ist jetzt, wie stark die performance sinkt. kann man das irgendwie voraussagen? ich mein eine allgemein-performance, wenn man davon ausgeht, dass der rest gleich schnell ist wie zb linux, aber segmentierung verwendet wird. halb so schnell? nur mehr ein viertel? oder 1% performanceverlust? weniger als das?**

    Das hängt stark davon ab, wie oft die Segmente wechseln und wie oft diese kritischen Stellen aufgerufen werden. Ich denke der Performanceverlust ist im Normalfall vernachlässigbar. Höchstenbs bei Hochleistungsanwendungen wie Spielen könnte es interessant werden.



  • Original erstellt von Surkevin:
    **Kann man da nicht einfach eine Simulation schreiben die genau so viele Überprüfungen tätigt (müssen ja keine richtigen sein einfach 2 Operanden vergleicht so oft wie es in "echt" auch gemacht wird) wie das Laden von Segmenten über Deskriptoren oder ob man eben keine Segmentierung verwendet? Wäre sicher etwas Aufwand aber besser als später ein langsames OS zu haben 😃
    **

    Das wird noch langsamer. In dem Konzept muss du jedesmal eine Check-Funktion aufrufen für JEDEN lese- und schriebvorgang. Dann dohc lieber die CPu das nebenbei erledigen lassen.


Anmelden zum Antworten