环境:riscv64 裸机
asm volatile (
"auipc a1, 0\n"
"ori a1, a1, 3\n"
"lw a2, (0)(a1)\n"
);
以上汇编可以触发load misaligne exception
auipc是取pc相对地址, a1 =(0<<12) + pc
ori是立即数按位与指令,a1 = a1 & 3
lw load by word, a2 = a1+0,a1存储的已经是一个非4字节对齐的地址,所以这一步会触发misalign address load 异常
access align 的意义在与可以单指令访问到数据和用较低成本保证数据访问的原子性,之所有会有misaligne 异常
Self-alignment makes access faster because it facilitates generating single-instruction fetches and puts of the typed data. Without alignment constraints, on the other hand, the code might end up having to do two or more accesses spanning machine-word boundaries.
riscv-spec-v2.2有如下一段话描述align access 的好处
For best performance, the effective address for all loads and stores should be naturally aligned for each data type (i.e., on a four-byte boundary for 32-bit accesses, and a two-byte boundary for 16-bit accesses). The base ISA supports misaligned accesses, but these might run extremely slowly depending on the implementation. Furthermore, naturally aligned loads and stores are guaranteed to execute atomically, whereas misaligned loads and stores might not, and hence require additional synchronization to ensure atomicity
kernel文档中 Documentation/unaligned-memory-access.txt有对misalign access的定义和一些通俗的解释
The definition of an unaligned access
=====================================Unaligned memory accesses occur when you try to read N bytes of data starting
from an address that is not evenly divisible by N (i.e. addr % N != 0).
For example, reading 4 bytes of data from address 0x10004 is fine, but
reading 4 bytes of data from address 0x10005 would be an unaligned memory
access.The above may seem a little vague, as memory access can happen in different
ways. The context here is at the machine code level: certain instructions read
or write a number of bytes to or from memory (e.g. movb, movw, movl in x86
assembly). As will become clear, it is relatively easy to spot C statements
which will compile to multiple-byte memory access instructions, namely when
dealing with types such as u16, u32 and u64.
Why unaligned access is bad
===========================The effects of performing an unaligned memory access vary from architecture
to architecture. It would be easy to write a whole document on the differences
here; a summary of the common scenarios is presented below:- Some architectures are able to perform unaligned memory accesses
transparently, but there is usually a significant performance cost.
- Some architectures raise processor exceptions when unaligned accesses
happen. The exception handler is able to correct the unaligned access,
at significant cost to performance.
- Some architectures raise processor exceptions when unaligned accesses
happen, but the exceptions do not contain enough information for the
unaligned access to be corrected.
- Some architectures are not capable of unaligned memory access, but will
silently perform a different memory access to the one that was requested,
resulting in a subtle code bug that is hard to detect!It should be obvious from the above that if your code causes unaligned
memory accesses to happen, your code will not work correctly on certain
platforms and will cause performance problems on others.
以结构体对齐举例,程序不用太关心,编译器会帮助我们处理好access aligne的事情
as in most cases, the compiler
ensures that things will work for you. For example, take the following
structure::struct foo {
u16 field1;
u32 field2;
u8 field3;
};Let us assume that an instance of the above structure resides in memory
starting at address 0x10000. With a basic level of understanding, it would
not be unreasonable to expect that accessing field2 would cause an unaligned
access. You'd be expecting field2 to be located at offset 2 bytes into the
structure, i.e. address 0x10002, but that address is not evenly divisible
by 4 (remember, we're reading a 4 byte value here).Fortunately, the compiler understands the alignment constraints, so in the
above case it would insert 2 bytes of padding in between field1 and field2.
Therefore, for standard structure types you can always rely on the compiler
to pad structures so that accesses to fields are suitably aligned (assuming
you do not cast the field to a type of different length).Similarly, you can also rely on the compiler to align variables and function
parameters to a naturally aligned scheme, based on the size of the type of
the variable.
asm volatile (
"auipc a1, 0\n"
"ori a1, a1, 0xfffffffffffffff0\n"
"andi a1, a1, 0x2\n"
"lw a2, (0)(a1)\n"
);
如上的一些信息还是没有办法搞清楚到底这个misalign是4字节对齐,还是跟架构是32就是4字节对齐,64位机则8字节对齐,还是跟具体指令有关系,比如lw是加载4个字节就要求地址4字节对齐,ld是加载8字节地址就要求8字节对齐
从上面的这段汇编修改a1的地址结尾测试结果发现,当前的riscv的ip(不知道是不是跟ip有关系)是第三种情况