[PATCH v2 4/7] tlsf: give malloc 8-byte alignment on 32-bit as well
Ahmad Fatoum
a.fatoum at pengutronix.de
Mon Sep 11 08:24:30 PDT 2023
The current alignment of 4 bytes is too low. Access to 64-bit data via
ldrd/strd requires at least an eight byte alignment:
| Prior to ARMv6, if the memory address is not 64-bit aligned, the
| data read from memory is UNPREDICTABLE. Alignment checking (taking
| a data abort), and support for a big-endian (BE-32) data format are
| implementation options.
We already have at least an 8 byte alignment for dlmalloc, so have TLSF
follow suit by aligning the accounting structures appropriately.
Instead of adding manual padding, we could also enlarge block_header_t::size
to an uint64_t unconditionally, but mark block_header_t __packed. This
comes with a runtime cost though or ugly __builtin_assume_aligned
annotations, so we stick to the simpler version.
Reported-by: Enrico Scholz <enrico.scholz at sigma-chemnitz.de>
Link: https://lore.barebox.org/barebox/ly7d1z1qvs.fsf@ensc-pc.intern.sigma-chemnitz.de/
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
common/tlsf.c | 12 ++++++------
include/linux/bitops.h | 1 +
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/common/tlsf.c b/common/tlsf.c
index 0986c7c457e3..692dabbdedd9 100644
--- a/common/tlsf.c
+++ b/common/tlsf.c
@@ -30,13 +30,8 @@ enum tlsf_public
/* Private constants: do not modify. */
enum tlsf_private
{
-#if defined (TLSF_64BIT)
/* All allocation sizes and addresses are aligned to 8 bytes. */
ALIGN_SIZE_LOG2 = 3,
-#else
- /* All allocation sizes and addresses are aligned to 4 bytes. */
- ALIGN_SIZE_LOG2 = 2,
-#endif
ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2),
/*
@@ -122,6 +117,7 @@ typedef struct block_header_t
/* The size of this block, excluding the block header. */
size_t size;
+ u32 : BYTES_TO_BITS(ALIGN_SIZE - sizeof(size_t));
/* Next and previous free blocks. */
struct block_header_t* next_free;
@@ -142,7 +138,7 @@ typedef struct block_header_t
** The prev_phys_block field is stored *inside* the previous free block.
*/
#define block_header_shift offsetof(block_header_t, size)
-#define block_header_overhead sizeof(size_t)
+#define block_header_overhead ALIGN_SIZE
/* User data starts directly after the size field in a used block. */
#define block_start_offset (block_header_shift + block_header_overhead)
@@ -155,6 +151,8 @@ typedef struct block_header_t
#define block_size_min (sizeof(block_header_t) - sizeof(block_header_t*))
#define block_size_max (tlsf_cast(size_t, 1) << FL_INDEX_MAX)
+tlsf_static_assert(block_size_min % ALIGN_SIZE == 0);
+tlsf_static_assert(block_size_max % ALIGN_SIZE == 0);
/* The TLSF control structure. */
typedef struct control_t
@@ -165,10 +163,12 @@ typedef struct control_t
/* Bitmaps for free lists. */
unsigned int fl_bitmap;
unsigned int sl_bitmap[FL_INDEX_COUNT];
+ u32 : BYTES_TO_BITS(ALIGN_SIZE - sizeof(size_t));
/* Head of free lists. */
block_header_t* blocks[FL_INDEX_COUNT][SL_INDEX_COUNT];
} control_t;
+tlsf_static_assert(sizeof(control_t) % ALIGN_SIZE == 0);
/* A type used for casting when doing pointer arithmetic. */
typedef ptrdiff_t tlsfptr_t;
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index a5f6ac6545ee..b0d6ca6ac87f 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -19,6 +19,7 @@
#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u64))
#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u32))
#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char))
+#define BYTES_TO_BITS(nb) (((BITS_PER_LONG * (nb)) / sizeof(long)))
#endif
/*
--
2.39.2
More information about the barebox
mailing list