aboutsummaryrefslogtreecommitdiff
path: root/gencode.c
diff options
context:
space:
mode:
authorJessica Clarke <jrtc27@jrtc27.com>2023-01-27 23:45:29 +0000
committerJessica Clarke <jrtc27@jrtc27.com>2023-01-27 23:45:29 +0000
commit8f1f38224d1136d920156be08f3548fa3c9ad83b (patch)
tree83dd80d7a5a6143775cd51b5ec1607948f383153 /gencode.c
parent75f608b0da534fbd0652bf97e34fb8da31059593 (diff)
gencode: Unify NetBSD and non-NetBSD alignment, and make more general
Currently the non-NetBSD code assumes that long is the maximum alignment needed for anything allocated from the chunk allocator. In practice, on typical 32-bit and 64-bit Unix platforms, this is true, since all the structures stored in it have only pointers and 32-bit integers. However, CHERI (on 64-bit architectures) uses 128-bit capabilities to implement C language pointers, which are a combination of a traditional 64-bit address, 64 bits of metadata and an additional 129th validity tag bit. Due to the use of tagged memory to support this tag bit they must be stored at naturally aligned addresses, i.e. 16 byte aligned, but long is still only 64-bit, since that is the natural machine word size for integer arithmetic, and thus if sdup tries to allocate a string of between 0 and 7 bytes mod 16 a subsequent allocation of any other type will not be sufficiently aligned for storing a pointer. Technically on 64-bit Windows long is 32-bit and thus insufficient alignment is used but in practice unaligned accesses work even if they are strictly UB. Fix this by computing the actual alignment requirement for chunks based on the set of types that can be stored in a chunk, without making use of C11's _Alignof. Even if C11 were required, using an explicit list of types rather than max_align_t allows us to be slightly more efficient in memory usage, since there are types (like long double) that force it to be 16 byte aligned that we don't need.
Diffstat (limited to 'gencode.c')
-rw-r--r--gencode.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/gencode.c b/gencode.c
index 87a6e962..59201aac 100644
--- a/gencode.c
+++ b/gencode.c
@@ -232,6 +232,26 @@ struct chunk {
void *m;
};
+/*
+ * A chunk can store any of:
+ * - a string (guaranteed alignment 1 but present for completeness)
+ * - a block
+ * - an slist
+ * - an arth
+ * For this simple allocator every allocated chunk gets rounded up to the
+ * alignment needed for any chunk.
+ */
+struct chunk_align {
+ char dummy;
+ union {
+ char c;
+ struct block b;
+ struct slist s;
+ struct arth a;
+ } u;
+};
+#define CHUNK_ALIGN (offsetof(struct chunk_align, u))
+
/* Code generator state */
struct _compiler_state {
@@ -600,13 +620,8 @@ newchunk_nolongjmp(compiler_state_t *cstate, size_t n)
int k;
size_t size;
-#ifndef __NetBSD__
- /* XXX Round up to nearest long. */
- n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
-#else
- /* XXX Round up to structure boundary. */
- n = ALIGN(n);
-#endif
+ /* Round up to chunk alignment. */
+ n = (n + CHUNK_ALIGN - 1) & ~(CHUNK_ALIGN - 1);
cp = &cstate->chunks[cstate->cur_chunk];
if (n > cp->n_left) {