core: Take arrays into account when inferring if a struct is packed
Before: $ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o struct qrwlock { union { atomic_t cnts; /* 0 4 */ struct { u8 wlocked; /* 0 1 */ u8 __lstate[3]; /* 1 3 */ } __attribute__((__packed__)); /* 0 4 */ }; /* 0 4 */ arch_spinlock_t wait_lock; /* 4 4 */ /* size: 8, cachelines: 1, members: 2 */ /* last cacheline: 8 bytes */ }; I.e. __lstate's class_member->byte_size is 3, causing the misinference that that struct was packed, it is naturally aligned, we need to look at the size of the array's entries to figure out its natural alignment: After: $ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o struct qrwlock { union { atomic_t cnts; /* 0 4 */ struct { u8 wlocked; /* 0 1 */ u8 __lstate[3]; /* 1 3 */ }; /* 0 4 */ }; /* 0 4 */ arch_spinlock_t wait_lock; /* 4 4 */ /* size: 8, cachelines: 1, members: 2 */ /* last cacheline: 8 bytes */ }; $ To further test: $ cat packed_array_struct.c struct sarray { short array[3]; long long first; } __attribute__((__packed__)); void foo(struct sarray *s) {} $ gcc -g -c packed_array_struct.c $ pahole packed_array_struct.o struct sarray { short int array[3]; /* 0 6 */ long long int first; /* 6 8 */ /* size: 14, cachelines: 1, members: 2 */ /* last cacheline: 14 bytes */ } __attribute__((__packed__)); $ cat packed_array_struct.c struct sarray { short array[3]; long long first; }; void foo(struct sarray *s) {} $ gcc -g -c packed_array_struct.c $ pahole packed_array_struct.o struct sarray { short int array[3]; /* 0 6 */ /* XXX 2 bytes hole, try to pack */ long long int first; /* 8 8 */ /* size: 16, cachelines: 1, members: 2 */ /* sum members: 14, holes: 1, sum holes: 2 */ /* last cacheline: 16 bytes */ }; $ One more test: $ cat packed_array_struct.c struct sarray { short a; short array[3]; long long b; }; void foo(struct sarray *s) {} $ Before this patch: $ gcc -g -c packed_array_struct.c $ pahole packed_array_struct.o struct sarray { short int a; /* 0 2 */ short int array[3]; /* 2 6 */ long long int b; /* 8 8 */ /* size: 16, cachelines: 1, members: 3 */ /* last cacheline: 16 bytes */ } __attribute__((__packed__)); After: $ pahole packed_array_struct.o struct sarray { short int a; /* 0 2 */ short int array[3]; /* 2 6 */ long long int b; /* 8 8 */ /* size: 16, cachelines: 1, members: 3 */ /* last cacheline: 16 bytes */ }; $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
85c9936963
commit
f2641ce169
21
dwarves.c
21
dwarves.c
|
@ -1291,6 +1291,19 @@ void class__find_holes(struct class *class)
|
|||
class->holes_searched = true;
|
||||
}
|
||||
|
||||
static size_t class_member__byte_size_for_alignment(struct class_member *member, const struct cu *cu)
|
||||
{
|
||||
struct tag *type = tag__strip_typedefs_and_modifiers(&member->tag, cu);
|
||||
|
||||
if (type->tag == DW_TAG_array_type) {
|
||||
type = tag__strip_typedefs_and_modifiers(type, cu);
|
||||
|
||||
return tag__size(type, cu);
|
||||
}
|
||||
|
||||
return member->byte_size;
|
||||
}
|
||||
|
||||
bool class__infer_packed_attributes(struct class *cls, const struct cu *cu)
|
||||
{
|
||||
const struct type *ctype = &cls->type;
|
||||
|
@ -1319,17 +1332,19 @@ bool class__infer_packed_attributes(struct class *cls, const struct cu *cu)
|
|||
if (pos->is_static)
|
||||
continue;
|
||||
|
||||
size_t byte_size = class_member__byte_size_for_alignment(pos, cu);
|
||||
|
||||
/* Always aligned: */
|
||||
if (pos->byte_size == sizeof(char))
|
||||
if (byte_size == sizeof(char))
|
||||
continue;
|
||||
|
||||
if (pos->byte_size >= cu->addr_size) {
|
||||
if (byte_size >= cu->addr_size) {
|
||||
max_natural_alignment = cu->addr_size;
|
||||
if ((pos->byte_offset % cu->addr_size) == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t natural_alignment = __roundup_pow_of_two(pos->byte_size);
|
||||
uint16_t natural_alignment = __roundup_pow_of_two(byte_size);
|
||||
|
||||
if (max_natural_alignment < natural_alignment)
|
||||
max_natural_alignment = natural_alignment;
|
||||
|
|
Loading…
Reference in New Issue