mikrocontroller.net

Forum: Compiler & IDEs GCC: Bug bei Warnings zu packed struct


Autor: N. G. (newgeneration) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Forum,

mir ist heute möglicherweise ein Bug im ARM-GCC aufgefallen.

Wenn ich zu einem struct, der ein "perfektes" Alignment aller Members 
hat, das Attribut packed gebe, dann gibt mir der Compiler auch 
Warnungen:
typedef struct {
    volatile uint32_t register0;
    volatile uint32_t register1;
    union {
        volatile const uint32_t read_only_register;
        volatile uint32_t write_only_register;
    };
} registers_unpacked;

typedef struct {
    volatile uint32_t register0;
    volatile uint32_t register1;
    union {
        volatile const uint32_t read_only_register;
        volatile uint32_t write_only_register;
    };
} __attribute__((packed)) registers_packed;
Kompiliert wird mit
$ arm-none-eabi-gcc -S -Wattributes -Wpacked packed-struct.c
Den Testfall habe ich einerseits angehängt, er ist aber auch über 
folgenden Link im Compiler-Explorer zu sehen: 
https://godbolt.org/g/ghyVdT

Ich habe auch überprüft, dass die Struct-Members immer an der selben 
Stelle sitzen (ob mit oder ohne packed-Attribut):
extern void foo(size_t);

void store_offsets(void) {
    foo(offsetof(registers_unpacked, register0));
    foo(offsetof(registers_packed  , register0));
    foo(offsetof(registers_unpacked, register1));
    foo(offsetof(registers_packed  , register1));
    foo(offsetof(registers_unpacked, read_only_register));
    foo(offsetof(registers_packed  , read_only_register));
    foo(offsetof(registers_unpacked, write_only_register));
    foo(offsetof(registers_packed  , write_only_register));
}
Ergibt (aufs Wesentliche gekürzt):
  mov  r0, #0
  bl  foo
  mov  r0, #0
  bl  foo
  mov  r0, #4
  bl  foo
  mov  r0, #4
  bl  foo
  mov  r0, #8
  bl  foo
  mov  r0, #8
  bl  foo
  mov  r0, #8
  bl  foo
  mov  r0, #8
  bl  foo
Man sieht, dass die Register immer den selben Offset haben. Trotzdem 
warnt det Compiler an:
$ arm-none-eabi-gcc -S -Wattributes -Wpacked packed-struct.c 
packed-struct.c:14:20: warning: packed attribute causes inefficient alignment for 'register0' [-Wattributes]
  volatile uint32_t register0;
                    ^~~~~~~~~
packed-struct.c:15:20: warning: packed attribute causes inefficient alignment for 'register1' [-Wattributes]
  volatile uint32_t register1;
                    ^~~~~~~~~
packed-struct.c:19:2: warning: packed attribute causes inefficient alignment for '({anonymous})' [-Wattributes]
  };
  ^
packed-struct.c:20:1: warning: packed attribute causes inefficient alignment [-Wpacked]
 } __attribute__((packed)) registers_packed;
 ^

Wo liegt dder Fehler? Bei mir oder beim Compiler?

Mit freundlichen Grüßen,
N.G.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Die Warnung scheint invertiert zu sein, d.h. sie wird für die optimal
alignten statt für die misalignten Strukturelemente ausgegeben.
Ausnahme: Für 1-Byte-Elemente (char und dergleichen) wird die Warnung
(korrekterweise) nicht ausgegeben.

Für mich sieht das tatsächlich nach einem Bug aus, auch wenn er nicht
schwerwiegend ist.

Ein weiterer kleiner Bug:

Die Meldung lautet zwar

  packed attribute causes inefficient alignment for '…' [-Wattributes]

Aktiviert wird sie aber nicht mit -Wattributes, sondern mit Wpacked.

Übrigens gibt Clang an genau denselben Stellen ebenfalls Warnungen aus,
nur heißen diese dort anders:

  warning: packed attribute is unnecessary for '…' [-Wpacked]

Auch wenn es IMHO unsinnig ist, für jedes Element einer gepackten
Struktur, das zufälligerweise trotz des Packens richtig alignt ist, eine
Warnung auszugeben, ist sie wenigstens korrekt. Auch das [-Wpacked]
stimmt dort.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
N. G. schrieb:
> Wo liegt dder Fehler?

1) Schau dir an, welche Zugriffe generiert werden.

2) Schau dir an, welche .align Direktive für entsprechende Objekte 
verwendet wird.

Was du vermutlich willst, ist __attribute((_packed_,__aligned__(4)))

Autor: N. G. (newgeneration) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Yalu, hallo Johann,

stimmt, die Warnung scheint invertiert zu sein. Das sieht man z.B. wenn 
man eine 16bit Variable dazwischenschiebt.

Das aligned()-Attribut änder leider weder an den Warnings, noch am 
generierten Code etwas (siehe dazu den godbolt.org-Link im 
Eingangsposting, da kann man schnell und einfach rumspielen).

Leider gibt es im Compiler-Explorer keinen ARM-clang und ich habe auf 
dem Rechner hier auch keinen zur Verfügung.
Das mit dem -Wattributes vs. -Wpacked ist aber auch interessant...

Mit freundlichen Grüßen,
N.G.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
3 lesenswert
nicht lesenswert
N. G. schrieb:
> Das aligned()-Attribut änder leider weder an den Warnings, noch am
> generierten Code etwas

Ich meine nicht den gezeigten Code, sondern die Zugriffe.  Und auch mit 
inkorrekter align-Direktive kann ein Objekt korrekt aligned sein.

Merke: Aus korrekt generiertem Code lässt sich nicht die Korrektheit der 
Eingabe folgern.

packed impliziert üblicherweise ein Alignment von 1.

: Bearbeitet durch User
Autor: N. G. (newgeneration) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Johann L. schrieb:
> N. G. schrieb:
>> Das aligned()-Attribut änder leider weder an den Warnings, noch am
>> generierten Code etwas
>
> Ich meine nicht den gezeigten Code, sondern die Zugriffe.  Und auch mit
> inkorrekter align-Direktive kann ein Objekt korrekt aligned sein.
>
> Merke: Aus korrekt generiertem Code lässt sich nicht die Korrektheit der
> Eingabe folgern.
>
> packed impliziert üblicherweise ein Alignment von 1.

Okay, sehe ich ein. Du hast da mehr Durchblick wie ich.

Wo lese ich denn so etwas nach, wenn ich es noch nicht weiß? Mir war 
ehrlich gesagt noch nicht einmal bewusst, dass es diese Direktiven gibt, 
bzw. ich kannte sie nur zum alignen von großen Arrays.

Mit freundlichen Grüßen,
N.G.

: Bearbeitet durch User
Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Sowas steht üblicherweise im Application Binary Interface (ABI).

Die Sprachspezifikation beschreibt lediglich eine abstrakte Maschine, 
die von einer konkreten Implementation umzusetzen ist.  Die 
Spezifikation ist dabei allgemein gehalten und macht z.B. keine Aussagen 
über:

* Layout von int (und damit über die Promotion-Regeln)

* Alignment und Layout von Datentypen

* Registerverwendung

* Binärformat (ELF, aout, ...)

* Relocations, Section-Header, etc.

etc. Dies wird im ABI ausgeführt.  Testfall für packed:
typedef struct { int i; } __attribute((packed)) S;

S sss = { 1 };
und übersetzt mit
$ arm-gcc -c obj.c -Os -save-temps
  .global  sss
  .data
  .type  sss, %object
  .size  sss, 4
sss:
  .4byte  1
hingegen:
$ arm-gcc -c obj.c -Os -save-temps -Dpacked=
  .global  sss
  .data
  .align  2
  .type  sss, %object
  .size  sss, 4
sss:
  .word  1
Die gepackte Struktur unterliegt also einem weniger strikten Alignment. 
Dies sieht man in der Assembler-Quelle oder man weiß es aus dem ABI.  Im 
erzeugten Code sieht man es u.U. nicht mehr: Wenn ein gepacktes 
Konstrukt auf ein normal aligntes folgt, dann hat auch das gepackte das 
größere Alignment obwohl kein explizites Alignment gefordert ist.

Wie immer lässt sich also aus der Korrektheit des erzeugten Codes nicht 
auf die Korrektheit der Eingabe schließen.

: Bearbeitet durch User
Autor: N. G. (newgeneration) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Hallo Johann,

danke!
Ich lerne immer wieder Dinge über den GCC, von denen ich nicht mal 
wusste, dass es sie gibt ;-)
Und an sich dachte ich immer, dass ich mich im Vergleich zum 
Durchschnitt noch eher gut auskenne...

Zur Zeit befinde ich mich allerdings im Prüfungsstress, deswegen fällt 
meine Antwort so kurz aus.

Mit freundlichen Grüßen,
N.G.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.