1 /*****************************************************************************/
5 /* Allocate an aligned memory block */
9 /* (C) 2004-2005 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
41 /* This is a very simple version of an aligned memory allocator. We will
42 * allocate a greater block, so we can place the aligned block within it
43 * that is returned. We use our knowledge about the internal heap
44 * structures to free the unused parts of the bigger block (the two chunks
45 * below and above the aligned block).
50 void* __fastcall__ _aligned_malloc (size_t size, size_t alignment)
51 /* Allocate a block of memory with the given size, which is aligned to a
52 * memory address that is a multiple of alignment. alignment MUST NOT be
53 * zero and MUST be a power of two, otherwise a call to this function will
54 * cause undefined behaviour. The function returns NULL if not enough memory
55 * is available to satisfy the request. To free the allocated block, use the
62 register struct usedblock* b;
63 register struct usedblock* u;
64 register struct usedblock* p;
66 /* Handle requests for zero sized blocks */
71 /* We don't really need alignment, but alignment-1 */
74 /* Round up the block size and allocate memory. We don't need to account
75 * for the additional admin data needed to manage the used block, since
76 * the block returned by malloc has this overhead added one time, and
77 * the worst thing that may happen is that we cannot free the upper and
80 b = malloc (size + alignment);
82 /* Handle out of memory */
87 /* Create a new pointer that points to the user visible aligned block. */
88 u = (struct usedblock*) (((unsigned)b + alignment) & ~alignment);
90 /* Get the raw block pointer, which is located just below the user visible
91 * block. The first word of this raw block is the total size of the block
92 * including the admin space.
97 /* Get a pointer to the (raw) upper block */
98 p = (struct usedblock*) (size + (unsigned)u);
100 /* Check if we can free the space above the allocated block. This is the
101 * case if the size of the block is at least sizeof (struct freeblock)
102 * bytes and the size of the remaining block is at least of this size,
103 * too. If the upper block is smaller, we will just pass it to the caller
104 * together with the requested aligned block.
106 uppersize = rawsize + (unsigned)b - (unsigned)p;
107 if (uppersize >= sizeof (struct freeblock) &&
108 (rawsize - uppersize) >= sizeof (struct freeblock)) {
110 /* Setup the usedblock structure */
114 /* Generate a pointer to the user space and free the block */
117 /* Decrement the raw block size by the amount of space just free'd */
118 rawsize -= uppersize;
121 /* Check if we can free the space below the allocated block. This is the
122 * case, if the size of the block is at least sizeof (struct freeblock)
123 * bytes and the size of the remaining block is at least of this size,
124 * too. If the lower block is smaller, we will just pass it to the caller
125 * together with the requested aligned block.
126 * Beware: We need an additional struct usedblock in the lower block which
127 * is part of the block that is passed back to the caller.
129 lowersize = ((unsigned)u - (unsigned)b) - sizeof (struct usedblock);
130 if (lowersize >= sizeof (struct freeblock) &&
131 (rawsize - lowersize) >= sizeof (struct freeblock)) {
133 /* b does already point to the raw lower block. Setup the usedblock
139 /* Generate a pointer to the user space and free the block */
142 /* Decrement the raw block size by the amount of space just free'd */
143 rawsize -= lowersize;
145 /* Set b to the raw user block */
149 /* u does now point to the user visible block, while b points to the raw
150 * block, and rawsize contains the size of the raw block. Setup the
151 * usedblock structure but beware: If we didn't free the lower block, it
152 * is splitted, which means that we must use u to write the start field,
153 * and b to write the size.
158 /* Return the user portion of the aligned block */