Forum: PC-Programmierung C Struktur Puzzle


von Hans-Georg L. (h-g-l)


Lesenswert?

Ich versuche gerade die Aufrufparameter in einem Windows Kernel Treiber 
im IoControlEvent zu analysieren.Dort bekomme unter anderem eine 
C-Struktur mit Parametern übergeben von der ich keine Information über 
die Struktur und ihre Variablen habe. Ich habe nur die Gesamt-Länge der 
Struktur und kenne Variable die sie enthalten muss.
1
// structur definition aus Beispielen passt nicht   
2
typedef struct _ASYNC_READ_ORG {
3
  ULONG           bRawMode;
4
  ULONG           bGetGeneration;
5
  IO_ADDRESS      DestinationAddress; //BusNr NodeNr Ofset-hi offset-Low
6
  ULONG           nNumberOfBytesToRead;
7
  ULONG           nBlockSize;
8
  ULONG           fulFlags;
9
  ULONG           ulGeneration;
10
  UCHAR           Data[1];
11
} ASYNC_READ_ORG, *PASYNC_READ_ORG;
12
13
// dummy structur für meinen memory dump
14
typedef struct _ASYNC_READ_DBG {
15
  ULONG           w1;
16
  ULONG           w2;
17
  ULONG           w3;
18
  ULONG           w4;
19
  ULONG           w5;
20
  ULONG           w6;
21
} ASYNC_READ_DBG, *PASYNC_READ_DBG;
22
23
// der hexdump (little endian)
24
FFFFCEFF 
25
000400F0 
26
10FBDB02 
27
00000000  
28
00040000
29
00000000 
30
// reihenfolge im speicher (big endian)
31
FFCEFFFF
32
F0000400
33
02DBFB10
34
00000000 
35
00000400
36
00000000
37
38
BYTE Reihenfolgen die Sinn ergeben
39
FFCE      -> BUS_NODE 10bit BusNr=0x3FF + 6Bit NodeNr=0x0E
40
FFFF      -> OffsetHigh
41
F0000400  -> Offset Low  
42
00000400  -> nNumberOfBytesToRead 
43
 
44
// so müsste die Struktur ohne padding aussehen 
45
typedef struct _ASYNC_READ {
46
  USHORT  Bus_Node; 
47
  USHORT  OffsetHigh;
48
  ULONG   OffsetLow;
49
  UCHAR   x1;
50
  UCHAR   x2;
51
  UCHAR   x3;
52
  ULONG   nNumberOfBytesToRead;
53
  ULONG   x4;
54
  UCHAR   x5;
55
} ASYNC_READ, *PASYNC_READ;

Wenn ich die Variablen so ausgebe ist BusNode und OffsetHigh vertauscht,
OffsetLow stimmt, und nNumberOfBytesToRead = 0.

Frage wie müsste die Struktur mit padding aussehen ?

Ein 3byte padding hätte ich doch nur wenn auf ein UCHAR ein ULONG folgt 
oder ?

von Nop (Gast)


Lesenswert?

Hans-Georg L. schrieb:

> Frage wie müsste die Struktur mit padding aussehen ?
1
typedef struct _ASYNC_READ {
2
  USHORT  Bus_Node;
3
  USHORT  OffsetHigh;
4
  ULONG   OffsetLow;
5
  UCHAR   x1;
6
  UCHAR   x2;
7
  UCHAR   x3;
8
  UCHAR   PAD1;
9
  ULONG   nNumberOfBytesToRead;
10
  ULONG   x4;
11
  UCHAR   x5;
12
  UCHAR   PAD2;
13
  UCHAR   PAD3;
14
  UCHAR   PAD4;
15
} ASYNC_READ, *PASYNC_READ;

von Hans-Georg L. (h-g-l)


Lesenswert?

Nop schrieb:
> Hans-Georg L. schrieb:
>
>> Frage wie müsste die Struktur mit padding aussehen ?
>
>
1
typedef struct _ASYNC_READ {
2
>   USHORT  Bus_Node;
3
>   USHORT  OffsetHigh;
4
>   ULONG   OffsetLow;
5
>   UCHAR   x1;
6
>   UCHAR   x2;
7
>   UCHAR   x3;
8
>   UCHAR   PAD1;
9
>   ULONG   nNumberOfBytesToRead;
10
>   ULONG   x4;
11
>   UCHAR   x5;
12
>   UCHAR   PAD2;
13
>   UCHAR   PAD3;
14
>   UCHAR   PAD4;
15
> } ASYNC_READ, *PASYNC_READ;

Das mit dem PAD1 funktioniert leider auch nicht ...
Warum brauche ich PAD2 bis PAD4 da kommt doch nichts mehr das alligned 
werden muss ?

Irgendwie drehe ich mich im Kreise
Wenn ich die z.B. die Reihenfolge der Beiden variablen vertausche
>   USHORT  Bus_Node;
>   USHORT  OffsetHigh;
Werden nicht die Werte getauscht sondern ich bekomme dann auch Müll.

Kennt der Microsoft Compiler (VisulStudio2013) ein flag wo er mir die 
Layouts der Datenstrukturen ausgeben kann die er generiert ?

von Hans-Georg L. (h-g-l)


Lesenswert?

Hans-Georg L. schrieb:
> Nop schrieb:
>> Hans-Georg L. schrieb:
>>>
>>> Frage wie müsste die Struktur mit padding aussehen ?
>>
>>
1
typedef struct _ASYNC_READ {
2
>>   USHORT  Bus_Node;
3
>>   USHORT  OffsetHigh;
4
>>   ULONG   OffsetLow;
5
>>   UCHAR   x1;
6
>>   UCHAR   x2;
7
>>   UCHAR   x3;
8
>>   UCHAR   PAD1;
9
>>   ULONG   nNumberOfBytesToRead;
10
>>   ULONG   x4;
11
>>   UCHAR   x5;
12
>>   UCHAR   PAD2;
13
>>   UCHAR   PAD3;
14
>>   UCHAR   PAD4;
15
>> } ASYNC_READ, *PASYNC_READ;
>

> Warum brauche ich PAD2 bis PAD4 da kommt doch nichts mehr das alligned
> werden muss ?
>
Padding is only inserted when a structure member is followed by a member 
with a larger alignment requirement or at the end of the structure.

Damit ist die Frage beantwortet

von Vlad T. (vlad_tepesch)


Lesenswert?

falls du den visualC-Compiler benutzt, kannst du mit -Wall alle 
warnungen aktivieren. Dann weist er dich auch auf paddings hin, dann 
must du nicht rumraten.

von foobar (Gast)


Lesenswert?

> Kennt der Microsoft Compiler (VisulStudio2013) ein flag wo er mir
> die Layouts der Datenstrukturen ausgeben kann die er generiert ?

Keine Ahnung, ob's so ein Flag gibt. Aber wenn du die Felder benutzen 
kannst, muß es irgendwo ein include-File geben, wo sie definiert werden.

von Nop (Gast)


Lesenswert?

Hans-Georg L. schrieb:

> Das mit dem PAD1 funktioniert leider auch nicht ...

So wird's jedenfalls aufgefüllt, wenn Du nicht gerade mit packed structs 
arbeitest. Andernfalls würde der nächste ULONG (nNumberOfBytesToRead) 
nicht an eine durch 4 teilbare Adresse gelangen.

> Warum brauche ich PAD2 bis PAD4 da kommt doch nichts mehr das alligned
> werden muss ?

Structs werden am Ende aufgefüllt, damit man daraus z.B. problemlos 
Arrays bauen kann und immer noch normale Pointerarithmetik hat. Würden 
structs nicht aufgefüllt, dann wäre ja das Alignment beim nächsten 
identischen Struct im Speicher nicht mehr gegeben.

von Nop (Gast)


Lesenswert?

Achja, noch ein Puzzlestück dazu: das Gesamt-Alignment eines struct 
richtet sich immer nach dem der größten Komponente. Da dieses struct 
ULONG enthält, wird die Startadresse des structs immer auf eine durch 4 
teilbare Adresse gelegt werden.

von Hans-Georg L. (h-g-l)


Lesenswert?

Die übergebene Struktur ist Bestandteil eines Programmes von dem ich nur 
ausfühbare Dateien habe und keine Header oder sonst etwas. Ich versuche 
mir eine Struktur zu zusammen zu fummeln die passt.

Was ich noch vergessen habe, die Struktur hat insgesammt 24Byte.

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Nop schrieb:
> Achja, noch ein Puzzlestück dazu: das Gesamt-Alignment eines struct
> richtet sich immer nach dem der größten Komponente. Da dieses struct
> ULONG enthält, wird die Startadresse des structs immer auf eine durch 4
> teilbare Adresse gelegt werden.

Das würde aber auch nicht zu dem hexdump passen.

von Nop (Gast)


Lesenswert?

Hans-Georg L. schrieb:

> Das würde aber auch nicht zu dem hexdump passen.

Zum Hexdump kann alles passen, weil keine Datendefinition dabeisteht. 
Abgesehen davon können außerdem auch noch packed structs vorliegen, weiß 
man nicht.

von Hans-Georg L. (h-g-l)


Lesenswert?

Hintergrund ist, ich habe einen WDF Kernel Filter Treiber der die 
Kommunikation mit einem Gerät das am Firewirebus hängt belauschen soll.

Siehe: Beitrag "R&S TSMU Radio Network Analyzer"

Da werden im Moment 8 verschiedene control codes verschickt und jeder 
hat seine eigene Struktur.

von Bernd K. (prof7bit)


Lesenswert?

Wenn das ein offizielles API von Windows ist muss es doch Header und 
Dokumentation geben.

von Hans-Georg L. (h-g-l)


Lesenswert?

Das sind userdefined structures die kennt Windows nicht.

Abe ich habe etwas gefunden das Macro offsetof kann den offset von 
Struktur Variablen ausgeben. Da wird das puzzeln etwas einfacher und ich 
kann es im user mode ohne lange turn-around Zeiten testen.

Der erste Test ergibt:
1
  typedef struct _ASYNC_READ {
2
    USHORT  Bus_Node;
3
    USHORT  OffsetHigh;
4
    ULONG   OffsetLow;
5
    ULONG   x1;
6
    ULONG   nNumberOfBytesToRead;
7
    ULONG   x2;
8
    UCHAR   x3;
9
  } ASYNC_READ, *PASYNC_READ; 
10
11
  o_Bus_Node    0x00000000  int
12
  o_OffsetHigh    0x00000002  int
13
  o_OffsetLow    0x00000004  int
14
  o_x1      0x00000008  int
15
  o_nNumberOfBytesToRead  0x0000000c  int
16
  o_x2           0x00000010  int
17
  o_x3      0x00000014  int
18
19
  size      0x00000018  int
Die 2 USHORT passen in einen ULONG
und es werden nur 3Byte am Ende aufgefüllt.

von Hans-Georg L. (h-g-l)


Lesenswert?

Manchmal muss man nur eine Nacht darüber schlafen ...

Ich habe heute Morgen nochmal die Bytes hin und her geschubst und mit 
anderen Parametern aufgerufen und nichts passt. Nochmal Google 
angeworfen und siehe da Firewire arbeitet mit BigEndian dann passt es 
auch. Jetzt kann es natürlich noch sein das es innerhalb der Struktur 
auch noch gemixt ist.

Naja einfach kann ja jeder ;-)

von Bernd K. (prof7bit)


Lesenswert?

Hans-Georg L. schrieb:
> Abe ich habe etwas gefunden das Macro offsetof kann den offset von
> Struktur Variablen ausgeben

Wenn Du offsetof anwenden kannst dann liegen doch die Quellen vor! Dann 
schau doch einfach wie es deklariert ist! Oder benutz es einfach so wie 
es ist!

von Nop (Gast)


Lesenswert?

Bernd K. schrieb:

> Wenn Du offsetof anwenden kannst dann liegen doch die Quellen vor!

Ja, aber nur seine eignen, wo er das mit verschiedenen Strukturvarianten 
durchprobiert und dank offsetof nicht manuell mit padding herumrechnen 
muß.

von Bernd K. (prof7bit)


Lesenswert?

Nop schrieb:
> dank offsetof nicht manuell mit padding herumrechnen
> muß.

Was muss an da groß rechnen? Alle Variablen sind self-aligned, d.h. ihr 
Offset ist durch ihre eigene Größe teilbar. Die Padding-Regeln sind also 
so simpel dass man Fehl-Alignment schon direkt mit zusammengekniffenen 
Augen sehen kann ohne zu rechnen wenn man sich gedanklich ein 2er, 4er 
und 8er Raster darunter legt.

Ich mach mir bei sowas als Gedächtnisstütze immer alle 8 Byte eine 
Leerzeile ins struct (oder eine Kommentarzeile als Trenner zwischen 8er 
Blöcken) und dann muss ich immer nur bis bis maximal 8 zählen (oder 
zweimal 4 oder viermal 2) um sofort zu sehen wo der Member überhaupt nur 
hinpassen kann bzw. wo vor diesem ein padding entstehen würde. Und da wo 
Padding entstehen würde schreib ich dann explizite dummy-Bytes hin damit 
meine 8er Blöcke alle voll sind.

So zum Beispiel:
1
typedef struct {
2
  // empty line every 8 bytes to help visualize alignment
3
4
  u32 magic;
5
  u16 scale_factor;
6
  u16 sample_time;
7
8
  u64 manufacture_date;
9
10
  u16 pid_kp;
11
  u16 pid_ki;
12
  u16 pid_kd;
13
  u16 pot_threshold_scale;
14
15
  u16 pot_light_dark_on_scale;
16
  u16 teach_threshold;
17
  out_type_t out_type;      // PNP, NPN, etc
18
  out_mode_t out_mode;      // switching or IO-Link
19
  u16 pulse_ext_millisec;    // pulse extension time
20
21
  light_dark_on_mode_t light_dark_on_mode;  // persisted state of pot hysteresis
22
} settings_t;

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Nop schrieb:
> Bernd K. schrieb:
>
>> Wenn Du offsetof anwenden kannst dann liegen doch die Quellen vor!
>
> Ja, aber nur seine eignen, wo er das mit verschiedenen Strukturvarianten
> durchprobiert und dank offsetof nicht manuell mit padding herumrechnen
> muß.

Ich definiere mir eine Struktur von der ich annehme das sie mit der 
unbekannten übereinstimmt und darauf kann ich offseof anwenden.

So sieht meine Struktur jetzt aus und es passt
1
  typedef struct _ASYNC_READ {
2
    USHORT  Bus_Node;     // BigEndian
3
    USHORT  OffsetHigh;   // BigEndian
4
    ULONG   OffsetLow;    // BigEndian
5
    ULONG   Unknown1;     // ?
6
    ULONG   Unknown2;     // ?
7
    ULONG   nNumberOfBytesToRead; // BigEndian
8
    UCHAR   data[1];      // Data Start
9
  } ASYNC_READ, *PASYNC_READ;

: Bearbeitet durch User
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.