Moin, Woher weiß ich, wie viele "Padding" Bytes der Compiler einfügt? Hat das was mit der CPU zu tun? Gibt es das nur bei Strukturen?
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
|
Anzeige
|
C -> AVR -> Strukturen -> Padding BytesMoin, Woher weiß ich, wie viele "Padding" Bytes der Compiler einfügt? Hat das was mit der CPU zu tun? Gibt es das nur bei Strukturen?
Jan H. schrieb: > Woher weiß ich, wie viele "Padding" Bytes der Compiler einfügt? Die ABI-Definition wäre wohl die Stelle, wo das definiert ist. Meistens läuft es darauf hinaus, dass die Adresse beim Zugriff auf einen primitiven Datentyp immer ein ganzzahliges Vielfaches von dessen Größe sein muss. > Hat das was mit der CPU zu tun? Ja. Je nach CPU sind Speicherzugriffe mit falschem Alignment langsamer oder gar nicht möglich. > Gibt es das nur bei Strukturen? Ja. Jan H. schrieb: > Woher weiß ich, wie viele "Padding" Bytes der Compiler einfügt? > Hat das was mit der CPU zu tun? Ja. Der AVR ist ein 8Bitter, der fügt also nichts ein. Beim ARM kannst Du Dir mit sizeof die Größe einer Struct in Bytes ausgeben lassen.
Gast
#5873945
> Je nach CPU sind Speicherzugriffe mit falschem Alignment langsamer > oder gar nicht möglich. Oder die niederwertigsten Adressbits werden stillschweigend ignoriert (und man bekommt deshalb Daten aus dem falschen Speicherbereich). Rolf M. schrieb: > Jan H. schrieb: >> Woher weiß ich, wie viele "Padding" Bytes der Compiler einfügt? > > Die ABI-Definition Für was steht das? Wo finde ich das? Wenn man jetzt eine Struktur hat wie z.B
Müsste diese jetzt auf einem AVR ( 8 Bit ) 2 Byte groß sein?
Gast
#5874035
Jan H. schrieb: > Müsste diese jetzt auf einem AVR ( 8 Bit ) 2 Byte groß sein? Wurde schon beantwortet. Jan H. schrieb: > Wo finde ich das? Falsche Frage! Die Antwort lautet: Im Internet! Eigentlich muss sie heißen: Wie finde ich das? Und die Antwort lautet: In dem man danach sucht! Unter 3 Minuten suchen: https://gcc.gnu.org/wiki/avr-gcc#ABI
Gast
#5874056
Rolf M. schrieb: >> Gibt es das nur bei Strukturen? > > Ja. Nein! Auch zwischen zwei völlig unabhängigen Variablen kann der Linker Leerraum lassen, damit der Zugriff besser flutscht. Bei einer Struktur könnte man mit sizeof() rausfinden, wieviel Platz frei gelassen wurde. Wenn man keine Struktur hat oder genauer wissen will wo, gäbe es noch die Möglichkeit einen Pointer auf einen Integerwert zu casten und da etwas heraus zu lesen. Oder wenn es nur Dich interressiert : lies doch mal aufmerksam die .map-Datei durch. Meine Meinung zu dem Thema ist : Vernünftige Software sollte einfach funktionieren, egal wo ihre Variablen im Speicher liegen. Rolf M. schrieb: > Jan H. schrieb: >> Hat das was mit der CPU zu tun? > > Ja. Je nach CPU sind Speicherzugriffe mit falschem Alignment langsamer > oder gar nicht möglich. Für alle AVR-CPUs genügt ein Alignment von 1 Byte, und die Zugriffsgeschwindigkeit hängt bei AVRs nicht vom Alignment ab. Ich lass mich da aber gerne eines besseren belehren. Jan H. schrieb: > Moin, > > Woher weiß ich, wie viele "Padding" Bytes der Compiler einfügt? > Hat das was mit der CPU zu tun? > Gibt es das nur bei Strukturen? > >
Compiliert mit avr-gcc [-Os] -fno-pack-struct und verschiedene Compilerversionen (v8, v6.4.1, v4.7.2, WinAVR-20100110 (v4.3.3)). Wie es für andere AVR C-Compiler aussieht weiß ich nicht. Das AVR-Backend des GCC macht keine Änderungen am Default, und GCC-Default bestimmt Paddings anhand der Größe eines Words:
http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/avr.h?view=markup#l114 Ein formales ABI gab es für AVR nicht, d.h. das ABI des avr-gcc / avr-g++ definiert sich dadurch, wie Denis damals das Backend implementierte. ABI-Dokus wie http://gcc.gnu.org/wiki/avr-gcc entstanden erst viel später, also reverse engineered. Und zwar anhand dessen, was avr-gcc konkret implementiert. Layout von Structs / Unions wird im GCC-Wiki allerdings nicht behandelt. Habe ich das jetzt richtig verstanden? Wenn man jetzt ein 32 Bit System nutzen würde und ich in einer Struktur jetzt nur ein Byte reservieren würde, würde er die restlichen 3 Bytes mit Padding Bytes füllen?
Gast
#5874831
sizeof() würde es dir zeigen. Wieso stellst du solche Fragen? Wenn danach noch weitere 1-Byte—Variablen kommen, nicht unbedingt. Wenn danach ein 32—Bit—Wert kommt, bestimmt. Oliver
Gast
#5874834
Jan H. schrieb: > Habe ich das jetzt richtig verstanden? > Wenn man jetzt ein 32 Bit System nutzen würde und ich in einer Struktur > jetzt nur ein Byte reservieren würde, würde er die restlichen 3 Bytes > mit Padding Bytes füllen? > struct u32 > { > uint8_t x; > } Kommt wie gesagt auch die ABI an. Aus dem Bauch heraus würde ich sagen, ja meistens trifft deine Aussage zu.
Gast
#5874883
So, um es auf den Punkt zu bringen: Das Ganze ist vom jeweiligen Compiler abhängig. Wenn man es also richtig machen will, darf man die Größe der Struktur nicht selber berechnen. sizeof wurde ja schon gennant. fop schrieb: > Rolf M. schrieb: >>> Gibt es das nur bei Strukturen? >> >> Ja. > > Nein! Auch zwischen zwei völlig unabhängigen Variablen kann der Linker > Leerraum lassen, damit der Zugriff besser flutscht. Bei völlig unabhängigen Variablen ergibt sich die Frage nicht, eben weil sie völlig unabhängig von einander sind. Die können auch komplett anders sortiert sein als im Quellcode. So landen z.B. mit 0 initialisierte globale Variablen oft in ganz anderen Speicherbereichen als welche, die mit einem anderen Wert initialisiert werden. Auch ein "packing" kann man über mehrere Variablen, die nichts miteinander zu tun haben, nicht machen. > Meine Meinung zu dem Thema ist : > Vernünftige Software sollte einfach funktionieren, egal wo ihre > Variablen im Speicher liegen. Ja. Allerdings will Software manchmal auch mit der Umwelt kommunizieren, und muss man sich ggf. mit solchen Themen beschäftigen. Johann L. schrieb: > Für alle AVR-CPUs genügt ein Alignment von 1 Byte, und die > Zugriffsgeschwindigkeit hängt bei AVRs nicht vom Alignment ab. Ich lass > mich da aber gerne eines besseren belehren. Das stimmt. Ich hatte übersehen, dass es um AVR geht, weil das im Text des Postings nicht erwähnt wurde. > Compiliert mit avr-gcc [-Os] -fno-pack-struct und verschiedene > Compilerversionen (v8, v6.4.1, v4.7.2, WinAVR-20100110 (v4.3.3)). Warum schaltest du das Packing denn explizit aus? Jan H. schrieb: > Habe ich das jetzt richtig verstanden? > Wenn man jetzt ein 32 Bit System nutzen würde und ich in einer Struktur > jetzt nur ein Byte reservieren würde, würde er die restlichen 3 Bytes > mit Padding Bytes füllen? > struct u32 > { > uint8_t x; > } Nicht gezwungenermaßen. Aber bei sowas:
Denn man kann ja auch ein Array aus diesen Strukturen machen. Bei Arrays gibt's aber kein Padding. Damit bei einem u32[2] das y vom zweiten Element auch aligned ist, müssen nach dem x vom ersten aber drei Padding-Bytes kommen, die Teil der struct sein müssen. Also wird diese struct auf gängigen 32-Bit-Systemen vermutlich 64 Bit groß sein. Rolf M. schrieb: > Bei völlig unabhängigen Variablen ergibt sich die Frage nicht, > eben weil sie völlig unabhängig von einander sind. Die können > auch komplett anders sortiert sein als im Quellcode. Naja, wenn ich zwei globale Variablen definiere und gleich initialisiere, dann tauchen die mit hoher auch nebeneinander im Binary auf. Und auch dort darf der Compiler padding einführen (und tut es auf manchen Architekturen auch, z.B. ia64). S. R. schrieb: > Rolf M. schrieb: >> Bei völlig unabhängigen Variablen ergibt sich die Frage nicht, >> eben weil sie völlig unabhängig von einander sind. Die können >> auch komplett anders sortiert sein als im Quellcode. > > Naja, wenn ich zwei globale Variablen definiere und gleich > initialisiere, dann tauchen die mit hoher auch nebeneinander im Binary > auf. Wie gesagt: Wenn du z.B. die eine mit 0 initialisierst und die andere mit 1, ist die Wahrscheinlichkeit sehr gering, dass sie nebeneinander landen. > Und auch dort darf der Compiler padding einführen (und tut es auf > manchen Architekturen auch, z.B. ia64). Ich würde hier nicht von Padding sprechen. Davon spricht man meiner Meinung, wenn zwischen zusammengehörigen Daten Füllbytes einführt. Wenn die alle separat sind, wird einfach für jede einzeln geschaut, dass sie mit passendem Alignment im Speicher liegt. Gut, wenn die alle hintereinander im Speicher landen, ist das Prinzip natürlich sehr ähnlich, aber der Compiler bzw. Linker könnte sich genauso gut entscheiden, alle globalen 4-Byte-Variablen in einen gemeinsamen Speicherblock zu legen und alle 2-Byte-Variablen in einen anderen, um möglichst wenig Verschnitt zu haben. S. R. schrieb: > Rolf M. schrieb: >> Bei völlig unabhängigen Variablen ergibt sich die Frage nicht, >> eben weil sie völlig unabhängig von einander sind. Die können >> auch komplett anders sortiert sein als im Quellcode. > > Und auch dort darf der Compiler padding einführen (und tut es auf > manchen Architekturen auch, z.B. ia64). Rein technisch ist das kein Padding. Ein Padding wäre Teil der internen Repräsentation, GCC erreicht das z.B. mit .space. Was du meinst sind die Lücken, die durch das Alignment von Objekten entstehen, diese werden bei dem GNU-Tools vom Locator eingefügt. Der Compiler kann hier nix einfügen, da er keine Adressen kennt. Was der Compiler einfügt sind Direktiven wie .p2align N vor einem Object, damit dessen Startadresse durch 2**N teilbar ist. Alternative Direktive ist .balign 2**N. (Semantik von .align ist abhängig vom Target wie .p2align oder wie .balign. Mehr Argumente sind möglich, z.B. für Maximalanzahl einzufügender Bytes, wie sie gerne bei Code-Alignment zum Einsatz kommen.) Will man den Verschnitt aufgrund Alignment minimieren, kann man im Linker-Script anweisen, die Objekte nach ihrem Alignment sortieren zu lassen. > Naja, wenn ich zwei globale Variablen definiere und gleich > initialisiere, dann tauchen die mit hoher auch nebeneinander im Binary > auf. Es soll schon Spezialisten gegeben haben, die sich auf eine bestimmte Reihenfolge der Objekte verlassen haben, und mit der nächsten Binutils-Version hat plötzlich nix mehr funktioniert. Grund: Binutils verwendete intern andere Algorithmen, so dass die Objekte in anderer Reihenfolge ausgegeben wurden. Rolf M. schrieb: > Johann L. schrieb: >> Compiliert mit avr-gcc [-Os] -fno-pack-struct und verschiedene >> Compilerversionen (v8, v6.4.1, v4.7.2, WinAVR-20100110 (v4.3.3)). > > Warum schaltest du das Packing denn explizit aus? Manche GUI setzt ungefragt -fpack-struct. Wenn man das Beispiel in so einer Umgebung testen würde, wäre es nichtssagend wegen -fpack-struct. Daher als Erinnerung dass man den Default für einen sinnvollen Test braucht. Rolf M. schrieb: >> Naja, wenn ich zwei globale Variablen definiere und gleich >> initialisiere, dann tauchen die mit hoher auch nebeneinander im Binary >> auf. > > Wie gesagt: Wenn du z.B. die eine mit 0 initialisierst und die andere > mit 1, ist die Wahrscheinlichkeit sehr gering, dass sie nebeneinander > landen. Darum schrieb ich "gleich initialisiere", so dass beide entweder in .bss oder in .data landen. Wenn ich die eine mit 1 und die andere mit 2 initialisiere, sieht das mit der Wahrscheinlichkeit wieder völlig anders aus... >> Und auch dort darf der Compiler padding einführen (und tut es auf >> manchen Architekturen auch, z.B. ia64). > Ich würde hier nicht von Padding sprechen. Ich meinte, dass einzelne Variablen z.B. immer auf 128 Bit aufgeblasen werden (unabhängig vom Datentyp), damit der Zugriff darauf effizienter ist. Das ist im Prinzip auch eine Art, Füllbytes einzuführen, aber auf einer anderen Ebene. Wenn du das anders bezeichnen möchtest, dann sehe ich das auch ein. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|