Ich habe mich tiefer in Linux und C vertieft und bin gespannt, wie Funktionen im Speicher gespeichert werden. Ich habe folgende Funktion:
%Vor%Einfach genug. Wenn ich objdump auf der ausführbaren Datei mit dieser Funktion ausführen, bekomme ich Folgendes:
%Vor%Was alles gut aussieht. Der interessante Teil ist, wenn ich das folgende Stück Code ausführen:
%Vor%Ich bekomme Folgendes (was falsch ist):
%Vor%Wenn ich optiere, lasse das memset aus (data, 0, sizeof (data)); Zeile, dann ist das rechte Byte korrekt, aber einige von ihnen haben immer noch die führenden 1s.
Hat jemand eine Erklärung dafür, warum
?A) Verwenden von memset zum Löschen meines Arrays führt zu einer falschen (Bearbeitung: ungenau) Darstellung der Funktion und
LÖSUNG: lag an der Verwendung von memset (data, 0, sizeof (data)) anstelle von memset (data, 0, 20 * sizeof (unsigned char)). Der Speicher wurde nicht vollständig festgelegt, da nur die Größe eines Zeigers als die Größe des gesamten Arrays betrachtet wurde.
B) Wie wird dieses Byte im Speicher gespeichert? Ints? verkohlen? Ich verstehe nicht ganz, was hier vor sich geht. (Klarstellung: Welche Art von Zeiger würde ich verwenden, um solche Daten im Speicher zu durchlaufen?)
LÖSUNG: Ich bin dumm. Ich habe das nicht signierte Schlüsselwort vergessen, und hier kam das gesamte Problem auf: (
Jede Hilfe wäre sehr willkommen - ich konnte nichts finden, wenn ich mich darum kümmere.
Neil
PS: Mein direkter Gedanke ist, dass dies ein Ergebnis davon ist, dass x86 eine Anweisung hat, die nicht auf einer Byte- oder Halbbyte-Grenze endet. Aber das macht keinen großen Sinn und sollte keine Probleme verursachen.
Danke an Will, dass ich auf meinen Fehler mit dem Char-Typ hingewiesen habe. Es hätte unsigned char sein sollen. Ich bin aber immer noch neugierig, wie ich auf einzelne Bytes zugreifen kann.
Hier ist ein viel einfacherer Fall des Codes, den Sie versucht haben:
%Vor% Die von mir vorgenommenen Änderungen bestehen darin, den überflüssigen Puffer zu entfernen, stattdessen einen Zeiger zum Testen zu verwenden, unsigniertes Zeichen anstelle von char zu verwenden und den Ausdruck so zu ändern, dass "% 02x" verwendet wird, so dass immer zwei Zeichen gedruckt werden. t fixiere die "negativen" Zahlen, die als ffffff89 oder so herauskommen - das ist mit dem unsigned
im Datenzeiger behoben.
Alle Anweisungen in x86 enden an Bytegrenzen, und der Compiler fügt häufig zusätzliche "padding-instructions" ein, um sicherzustellen, dass die Verzweigungsziele für Effizienz an 4, 8 oder 16-Byte-Grenzen ausgerichtet sind.
Das Problem ist in Ihrem Code zu drucken.
Ein Byte wird aus dem Datenfeld geladen. (ein Byte == ein Zeichen)
Das Byte wird in ein 'int' konvertiert, da der Compiler weiß, dass 'printf' will. Um dies zu tun, verlängert das Zeichen das Byte auf ein 32-Bit-Doppelwort. Das wird als Hex ausgegeben. (Dies bedeutet, dass ein Byte mit dem hohen Bit von eins in einen 32-Bit-Wert konvertiert wird, wobei die Bits 8-31 alle gesetzt sind. Das sind die ffffffxx-Werte, die Sie sehen.)
Was ich in diesem Fall mache ist, es selbst zu konvertieren:
%Vor%Dann wird es korrekt gedruckt. (Wenn Sie 16-Bit-Werte laden würden, würden Sie UND mit 0xffff verknüpfen.)
Antwort auf B) Byte wird als Byte im Speicher gespeichert. Ein Speicherplatz mit genau 1 Byte ist im Speicherplatz enthalten (ein Byte ist unsigned char
)
Tipp: Nehmen Sie ein gutes Buch über Computer-Organisation auf (mein Favorit ist einer von Carl Hamachar und verstehe eine Menge darüber, wie die Erinnerung intern dargestellt wird)
In Ihrem Code:
%Vor%Der Ausdruck sieht seltsam aus, weil Sie vorzeichenbehaftete Werte drucken, sodass sie vorzeichenerweitert werden.
Die zu druckende Funktion unterscheidet sich jedoch geringfügig. Es sieht so aus, als würde man EAX nicht mit der Adresse der Zeichenkette laden und auf den Stack stopfen, sondern direkt die Adresse speichern.
%Vor%Warum ändert es sich, wenn Sie anderswo im Code scheinbar gütige Änderungen vornehmen - nun, das ist erlaubt. Deshalb ist es gut, sich nicht auf undefiniertes Verhalten zu verlassen.