Flagregister auslesen
-
Weiß jemand wie man das Flagregister in einer Hochsprache wie C auslesen kann?
Versuche eigenen Overflowschutz zu machen...
-
--- schrieb:
Weiß jemand wie man das Flagregister in einer Hochsprache wie C auslesen kann?
Versuche eigenen Overflowschutz zu machen...ist so nicht eingebaut.
enterder, du nimmst inline-assembler...
unsigned int plus(unsigned int a,unsigned int b){ bool overflow; unsigned int result; __asm mov eax,a; __asm add eax,b; __asm setc overflow; __asm mov result,eax; if(overflow) throw Fehler(); return result; }
oder du nimmst mathematische überlegungen...
unsigned int plus(unsigned int a,unsigned int b){ int result=a+b; if(result<a) throw Fehler(); return result; }
evtl
if(result<a || result<b) throw Fehler();
, hab ich jetzt nicht genau überlegt.
-
Danke ...
Hab davon gehört, dass man mit pushf das Register auf den Stack bringt.
Könnte man nicht so die Flags vom Stack in eine Variable speichern und dann auswerten? Wenn ja, wie?
-
es gibt verschiedene möglichkeiten. im übrigen ist zu beachten, dass in einigen wenigen fällen die flags keine verlässliche auskunft über das vorliegen eines überlaufs geben. z.b. imul kann man sowohl für vorzeichenbehaftete als auch vorzeichenlose multiplikation verwenden (was der grund dafür ist, warum mul nur in der umständlichen expandierenden version existiert) - allerdings kann man dann die flags nicht benutzen, um einen vorzeichenlosen überlauf zu erkennen.
prinzipiell ist eine überprüfung des ergebnisses der sauberste weg, überläufe zu erkennn, dummerweise ist es nicht unbedingt performant, wenn man komplexe ausdrücke hat.
was du möglicherweise meinst, ist so etwas:
unsigned getFlags() { __asm pushf __asm pop eax }
dummerweise kann das nicht funktionieren, da du keine kontrolle darüber hast, wie der compiler einen gegebenen ausdruck tatsächlich auswertet, ausserdem wird dir auch noch instruktion reordering in die quere kommen.
volkards inline vorschlag kann man noch minimal optimieren:
unsigned int plus(unsigned int a,unsigned int b){ __asm mov eax,a __asm add eax,b __asm jnc exit_ throw Fehler(); exit_: }
eine andere möglichkeit ist es, überläufe vorher abzufangen:
if ( std::numeric_limits<unsigned>::max() - a < b ) throw Fehler(); }
-
DANKE
-
camper schrieb:
[...]z.b. imul kann man sowohl für vorzeichenbehaftete als auch vorzeichenlose multiplikation verwenden (was der grund dafür ist, warum mul nur in der umständlichen expandierenden version existiert)
Das ist mir neu. Kannst du das bitte mal etwas genauer erlaeutern?
-
wie du sicher weisst, gibt es verschiedene formen von imul mit einem, zwei oder drei operanden (hier nur die varianten mit 32bit operanden):
imul r/m32
imul r32, r/m32
imul r32, imm8/32
imul r32, r/m32, imm8/32nur die variante mit einem operanden hat eine entsprechung mit mul.
die zwei- und drei-operanden formen führen zwar intern ebenfalls eine vollständige (expandierende) multiplikation aus, es wird aber nur das niederwertige 32bit word gespeichert. einen eventuellen signed überlauf bekommt man dabei durch carry- und overflow-flag mit. tatsächlich ist aber aufgrund der 2er-komplementdarstellung das ergebnis identisch zu dem, dass entstünde, wenn die operanden vorzeichenlos wären. lediglich überläufe kann man hier nicht abfragen. um es deutlich zu sagen: mul und imul unterscheiden sich nur im höherwertigen teil des ergebnisses.
falls das neu für dich ist... ich hab auch jahre gebraucht, bis mir das klar geworden ist, obwohl es eigentlich auf der hand liegt. sehr praktisch bei adressberechnungen, wenn man mit dem SIB byte allein nicht weiterkommt. häufig genügen ja die unteren 32bit, und man ist dann nicht mehr an edx:eax gebunden und spart sich ständiges hin- und hergeschiebe nur im die register frei zu bekommen.
-
Ahso, thnx.
Nur hat das IMHO nicht viel mit vorzeichenloser Multiplikation zu tun...
Sobald du in der Multiplikation eine "negative Zahl" (also letztes Bit gesetzt) hast, passt das Ergebnis auf jeden Fall (ausgenommen Multiplikation mit 1) nicht mehr allein ins niederwertige Word.
Oder habe ich da jetzt was falsch verstanden?Ansonsten hast du recht: Diese vielen verschiedenen Formate von imul sind durchaus praktisch.
-
Nobuo T schrieb:
Sobald du in der Multiplikation eine "negative Zahl" (also letztes Bit gesetzt) hast, passt das Ergebnis auf jeden Fall (ausgenommen Multiplikation mit 1
) nicht mehr allein ins niederwertige Word.
Und was willst du damit sagen?
-
Das war ein Versuch zu verdeutlichen, dass bei Verwendung von imul immer eine vorzeichenbehaftete Multiplikation ausgefuehrt wird und die Ergebnisse (in Gaenze betrachtet) von imul und mul nur so lange vergleichbar sind, wie mit positiven Zahlen multipliziert wird. => Verwendung von imul als mul-Ersatz macht nicht uneingescharaenkt Sinn. Kam mir nicht deutlich genug rueber - wollte ich nur nochmal auf den Punkt bringen... ...whatever...
Ich seh' schon, das fuehrt nur zu Verwirrung und wird auch zu OT.
-
Nobuo T schrieb:
Das war ein Versuch zu verdeutlichen, dass bei Verwendung von imul immer eine vorzeichenbehaftete Multiplikation ausgefuehrt wird und die Ergebnisse (in Gaenze betrachtet) von imul und mul nur so lange vergleichbar sind, wie mit positiven Zahlen multipliziert wird. => Verwendung von imul als mul-Ersatz macht nicht uneingescharaenkt Sinn. Kam mir nicht deutlich genug rueber - wollte ich nur nochmal auf den Punkt bringen... ...whatever...
Ich seh' schon, das fuehrt nur zu Verwirrung und wird auch zu OT.und genau das ist eben nicht der fall. es macht eben keinen unterschied, ob die benutzten zahlen negativ wären oder nicht - das niederwertige wort des ergebnis ist stets dasselbe:
seien a und b zwei integer mit n bits.
sei der wert von a interpretiert als vorzeichenloser integer,
der wert von a von interpretiert als vorzeichenbehafteter integer in 2er komplementdarstellung.dann ist wenn das höchswertige bit nicht gesetzt ist, andernfalls gilt
anolg seien und definiert.
das ergebnis einer vorzeichenlosen multiplikation ist dann:
das ergebnis einer vorzeichenbehafteten multiplikation ist je nachdem, welches vorzeichen und haben:
((a\_u-2^n)\*b\_u) mod 2^n = ((a\_u\*b\_u)-2^n*b_u) mod 2^n = ((a\_u\*b\_u) mod 2^n - (2^n\*b\_u) mod 2^n) mod 2^n = (a\_u*b_u) mod 2^n
(Anmerkung: im die frage ob -1 mod 2^n nun -1 oder 2^n-1 wäre, brauchen wir uns hier nicht kümmern, dank zweikomplement macht das keinen unterschied)
und das ist eben genau dasselbe, was bei vorzeichenloser multiplikation herauskommt. Häufig genug ist man ja gar nicht am exakten ergebnis interessiert, sondern nur an den niederwertigen bits des ergbnissen, und dann arbeitet man meist mit vorzeichenlosen zahlen. da halte ich es schon für bedeutsam, dass man in jedem falle bedenkenlos imul einsetzen kann, unabhängig davon, ob die höhstwertigen bits der argumente gesetzt sind oder nicht.