diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2020-08-24 08:25:19 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-08-24 08:25:19 -0700 |
commit | 1cf4652639d22e0e3ed7385e20cdcad6c5a6df2f (patch) | |
tree | 5d0ed41db4c0666e43845ac87297229962a544c4 /ffi.c | |
parent | 2b088c2de1e23cc7c01533a49746fbdca55034d7 (diff) | |
download | txr-1cf4652639d22e0e3ed7385e20cdcad6c5a6df2f.tar.gz txr-1cf4652639d22e0e3ed7385e20cdcad6c5a6df2f.tar.bz2 txr-1cf4652639d22e0e3ed7385e20cdcad6c5a6df2f.zip |
ffi/doc: bugfixes to bitfield alignment.
Three issues issues. The documentation is wrong about the
concept of a "leading bitfield" whose alignment matters.
The alignment of all named bitfields matters. Secondly,
the alignment of unnamed bitfields doesn't matter.
Thirdly, there is a flaw in the treatment of bitfields
in unions, from both alignment and sizing.
* ffi.c (make_ffi_type_struct): A bitfield member contributes
to alignment regardless of its offset within an allocation
unit: no bits_alloc == 0 check should be applied. Secondly, a
bitfield member that is unnamed has an alignment of 1,
otherwise the alignment of its declared type.
(make_ffi_type_union): The size and alignment of a bitfield
member is not simply that of its type. The size of a bitfield
is the number of bytes required to store all of the bits. The
alignment is 1 if it is unnamed, otherwise that of its type.
The sizing of bitfields now means that alignment can add
padding to a union. For instance, a uint32_t x : 17 bitfield
has size 3, but alignment 4, requiring one byte of alignment
padding in the union so that its size is 4. This means that we
must now do the padding alignment calculation for unions
to adjust the size, just like we do for structures.
Diffstat (limited to 'ffi.c')
-rw-r--r-- | ffi.c | 29 |
1 files changed, 17 insertions, 12 deletions
@@ -3293,6 +3293,7 @@ static val make_ffi_type_struct(val syntax, val lisp_type, ucnum unit_offs = offs & align_mask; ucnum bits_alloc = 8 * (offs - unit_offs) + bit_offs; ucnum room = bits_type - bits_alloc; + ucnum align = if3(slot, mtft->align, 1); if (bits == 0) { if (offs != unit_offs || bit_offs > 0) @@ -3307,11 +3308,6 @@ static val make_ffi_type_struct(val syntax, val lisp_type, bit_offs = bits_alloc = 0; } - if (bits_alloc == 0) { - if (most_align < (ucnum) mtft->align) - most_align = mtft->align; - } - memb[i].offs = offs; #if HAVE_LITTLE_ENDIAN @@ -3326,6 +3322,9 @@ static val make_ffi_type_struct(val syntax, val lisp_type, bit_offs += bits; offs += bit_offs / 8; bit_offs %= 8; + + if (most_align < align) + most_align = align; } else { ucnum align = mtft->align; ucnum almask = align - 1; @@ -3451,14 +3450,10 @@ static val make_ffi_type_union(val syntax, val use_existing, val self) setcheck(obj, slot); setcheck(obj, type); - if (most_align < (ucnum) mtft->align) - most_align = mtft->align; - - if (biggest_size < (ucnum) mtft->size) - biggest_size = mtft->size; - if (mtft->bitfield) { ucnum bits = mtft->nelem; + ucnum size = (bits + 7) / 8; + ucnum align = if3(slot, mtft->align, 1); if (bits == 0) { nmemb--, i--; @@ -3474,6 +3469,16 @@ static val make_ffi_type_union(val syntax, val use_existing, val self) mtft->mask = UINT_MAX; else mtft->mask = ((1U << bits) - 1) << mtft->shift; + + if (most_align < align) + most_align = align; + if (biggest_size < size) + biggest_size = size; + } else { + if (most_align < (ucnum) mtft->align) + most_align = mtft->align; + if (biggest_size < (ucnum) mtft->size) + biggest_size = mtft->size; } } @@ -3486,7 +3491,7 @@ static val make_ffi_type_union(val syntax, val use_existing, val self) tft->nelem = i; - tft->size = biggest_size; + tft->size = (biggest_size + most_align - 1) & ~(most_align - 1); tft->align = most_align; #if HAVE_LIBFFI |