Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I align a buffer on the stack?

Tags:

c++

gcc

embedded

I'm trying to achieve a memory buffer that's aligned by it's size so I can use the modulo feature of a DMA controller to implement a ring buffer. I know I can do this with memalign, but I'm wondering if its possible to do so on the stack as so far I've been able to avoid dynamic memory. I'm using GCC 4.4.1 and I don't care about portability (embedded system).

I want to do something like:

template<uint16_t num_channels, uint16_t buffer_size>
class sampler {
    __attribute__((aligned(buffer_size * num_channels * 2)))
    uint16_t buffer[buffer_size][num_channels];
};

but of course GCC won't accept non-constant alignment (and seems to indicate that alignments > 8 may not be honored anyway).

I think I could use C++0x alignas() to achieve this, but it doesn't seem to appear in GCC until version 4.8.

I guess one option might be to double the size of the buffer, but that seems to waste a bunch of space (I'm planning on trying to use a substantial fraction of the device memory for this buffer). Maybe I should just give up and use dynamic memory. Is memalign going to be relatively efficient in terms of wasted space?

Any ideas?

like image 828
Christopher Mason Avatar asked Dec 01 '12 21:12

Christopher Mason


2 Answers

You don't need to double the storage's size, you only need to add (alignment - 1) to it -- basically the same thing that memalign does behind the scenes. For a power of two alignment:

char buf[size + (alignment -1)];
char *aligned = (char*)((intptr_t)buf + (alignment - 1) & ~intptr_t(alignment - 1));
like image 142
Cory Nelson Avatar answered Oct 26 '22 12:10

Cory Nelson


It has been a long time since I have used linker command files but I think it would go like this.

Create file buffer.cpp with

char buffer[ BUFFER_SIZE ];

An object file has sections named .bss (for uninitialized data), .data (for initialized data), and .text (for executable code). buffer[] will go in .bss since it is not initialized.

So a (gnu) linker file like this should do the trick

SECTIONS {
   .bss 0x0  : {
        buffer.o(.bss)
        *(.bss)
    }
   .data : {
        *(.data)
    }
   .text : {
        *(.text)
    }
}

The 0x0 tells the linker to load buffer[] at address 0x0.

like image 44
brian beuning Avatar answered Oct 26 '22 13:10

brian beuning