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


von N. G. (newgeneration) Benutzerseite


Angehängte Dateien:

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:
1
typedef struct {
2
    volatile uint32_t register0;
3
    volatile uint32_t register1;
4
    union {
5
        volatile const uint32_t read_only_register;
6
        volatile uint32_t write_only_register;
7
    };
8
} registers_unpacked;
9
10
typedef struct {
11
    volatile uint32_t register0;
12
    volatile uint32_t register1;
13
    union {
14
        volatile const uint32_t read_only_register;
15
        volatile uint32_t write_only_register;
16
    };
17
} __attribute__((packed)) registers_packed;
Kompiliert wird mit
1
$ 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):
1
extern void foo(size_t);
2
3
void store_offsets(void) {
4
    foo(offsetof(registers_unpacked, register0));
5
    foo(offsetof(registers_packed  , register0));
6
    foo(offsetof(registers_unpacked, register1));
7
    foo(offsetof(registers_packed  , register1));
8
    foo(offsetof(registers_unpacked, read_only_register));
9
    foo(offsetof(registers_packed  , read_only_register));
10
    foo(offsetof(registers_unpacked, write_only_register));
11
    foo(offsetof(registers_packed  , write_only_register));
12
}
Ergibt (aufs Wesentliche gekürzt):
1
  mov  r0, #0
2
  bl  foo
3
  mov  r0, #0
4
  bl  foo
5
  mov  r0, #4
6
  bl  foo
7
  mov  r0, #4
8
  bl  foo
9
  mov  r0, #8
10
  bl  foo
11
  mov  r0, #8
12
  bl  foo
13
  mov  r0, #8
14
  bl  foo
15
  mov  r0, #8
16
  bl  foo
Man sieht, dass die Register immer den selben Offset haben. Trotzdem 
warnt det Compiler an:
1
$ arm-none-eabi-gcc -S -Wattributes -Wpacked packed-struct.c 
2
packed-struct.c:14:20: warning: packed attribute causes inefficient alignment for 'register0' [-Wattributes]
3
  volatile uint32_t register0;
4
                    ^~~~~~~~~
5
packed-struct.c:15:20: warning: packed attribute causes inefficient alignment for 'register1' [-Wattributes]
6
  volatile uint32_t register1;
7
                    ^~~~~~~~~
8
packed-struct.c:19:2: warning: packed attribute causes inefficient alignment for '({anonymous})' [-Wattributes]
9
  };
10
  ^
11
packed-struct.c:20:1: warning: packed attribute causes inefficient alignment [-Wpacked]
12
 } __attribute__((packed)) registers_packed;
13
 ^

Wo liegt dder Fehler? Bei mir oder beim Compiler?

Mit freundlichen Grüßen,
N.G.

von Yalu X. (yalu) (Moderator)


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.

von Johann L. (gjlayde) Benutzerseite


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)))

von N. G. (newgeneration) Benutzerseite


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.

von Johann L. (gjlayde) Benutzerseite


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
von N. G. (newgeneration) Benutzerseite


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
von Johann L. (gjlayde) Benutzerseite


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:
1
typedef struct { int i; } __attribute((packed)) S;
2
3
S sss = { 1 };
und übersetzt mit
1
$ arm-gcc -c obj.c -Os -save-temps
1
  .global  sss
2
  .data
3
  .type  sss, %object
4
  .size  sss, 4
5
sss:
6
  .4byte  1
hingegen:
1
$ arm-gcc -c obj.c -Os -save-temps -Dpacked=
1
  .global  sss
2
  .data
3
  .align  2
4
  .type  sss, %object
5
  .size  sss, 4
6
sss:
7
  .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
von N. G. (newgeneration) Benutzerseite


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.

Beitrag #7414684 wurde von einem Moderator gelöscht.
Beitrag #7414942 wurde von einem Moderator gelöscht.
Beitrag #7416083 wurde von einem Moderator gelöscht.
Beitrag #7416134 wurde von einem Moderator gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.