11
votes

I know that some CPU architectures don't support unaligned address access(e.g., ARM architectures prior to ARM 4 had no instructions to access half-word objects in memory). And some compiler(e.g., some version of GCC) for that architecture will use a series of memory access when it finds a misaligned address, so that the misaligned access is almost transparent to developers.(Refer to The Definitive Guide to GCC, By William von Hagen)

But I'm wondering how does a compiler know whether an address is aligned or not? After all, what a compiler sees is the virtual address(effective address, EA), if it can see anything. When the program is run, EA could be mapped to any physical address by OS. Even if virtual address is aligned, the resulting physical address could be misaligned, isn't it? The alignment of physical address is what really matters and transfers on CPU address lines.

Because a compiler is not aware of the physical address at all, how can it be smart enough to know if a variable's address is aligned?

2

2 Answers

16
votes

Virtual address is not mapped to just any physical address. Virtual memory comes in pages that are mapped in an aligned manner to physical pages. (generally aligned to 4096).

See: Virtual memory and alignment - how do they factor together?

2
votes

Alignment is a very useful attribute for object code, partly because some machines insist on "aligned access" but in modern computers because cache lines have huge impact on performance and thus cache-alignment of code/loops/data/locks is thus a requirement from your local friendly compiler.

Virtally all the loaders in the world support loading of code at power-of-two aligned boundaries of some modest size and on up. (Assemblers and linkers support this too with various ALIGNMENT directives). Often linkers and loaders just align the first loaded value anyway to a well-known boundary size; OSes with virtual memory often provide a convenient boundary based on VM page size (ties to other answer).

So a compiler can essentially know what the alignment of its emitted code/data is. And by keeping track of how much code it has emitted, it can know what the alignment of any emitted value is. If it needs alignment, it can issue a linker directive, or for modest sizes, simply pad until the emitted amount of code is suitably aligned.

Because of this, you can be pretty sure most compilers will not place code or data constructs in ways that cross cache line (or other architecture imposed) boundaries in a way that materially affects performance unless directed to do so.