西游记真相大揭秘:RISC 下非对齐访问的问题
来源:百度文库 编辑:九乡新闻网 时间:2024/04/25 09:26:34
1. 问题RISC 下使用访存指令读取或写入数据单元时,目标地址必须是所访问之数据单元字节数的整数倍,这个叫做地址对齐。比 如在 MIPS 平台上,lh 读取一个半字时,存储器的地址必须是 2 的整数倍; lw 读取一个字时,存储器的地址必须是 4的整数倍; sd 写入一个双字时,存储器的地址必须是 8 的整数倍。倘若访存时,目标地址不对齐,则会引起异常,典型的是系统提示“总线错误”后,直接杀死进程。看一个测试程序(龙芯2E平台): #include
#includeunsigned short data[] = {
0x1, 0x2, 0x3, 0x4,
0x55aa, 0x66bb, 0x77cc, 0x0000,
};inline void unaligned_access(unsigned short * const row)
{
asm volatile
(
".set mips3 "
".set noreorder " //"lwr $10, 1(%1) "
//"lwl $11, 4(%1) "
//"or $10, $11 "
"ld $10, 2(%1) " /* %1 is double word aligned, %1+2 is double word unaligned */
"sd $10, %0 " ".set reorder "
".set mips0 "
: "=m"(*(row))
: "r"(row+4)
: "$8", "$9", "$10"
);
}int main()
{
printf("--------------------------------------------------------- ");
printf(" Testing Godson2 unaligned access Instruction ");
printf("--------------------------------------------------------- ");// sysmips(MIPS_FIXADE, 0); unaligned_access(data); printf("result is: 0x%04x %04x %04x %04x ", data[3], data[2], data[1], data[0]);} 程序运行后系统提示“非法指令”后退出。
CISC 下(如x86)访存时,如果目标地址不对齐,CPU 不会陷入异常,因为其内部有处理非对齐访问的微程序。
2. 解决高级语言中一般不会遇到这种问题,编译器常常会处理好数据类型的对齐。但万一遇到、抑或在汇编里遇到,避不开怎么办?可以使用 MIPS 的指令集里提供的 lwr/lwl, swr/srl, ldr/ldl, sdr/sdl 指令对。关于他们的原理可以用下图来简单的示意一下(以ldr/ldl 为例,其他类似):
上图解释的是小端模式下的情况,大端模式的情况则相反:首先 ldl t0, 0(t1),然后再 ldr t0, 7(t1)。可 以看到无论大端模式还是小端模式,非对齐访问的解决都是将原来的一条指令(对齐访问)完成的事分两步完成,即首先取始地址 addr 到下一个对齐地址处的部分数据,置入寄存器右部(小端),(大端置入左部(高位)),然后取从该对齐地址到 addr + len - 1 处的部分数据(len 为数据单元长度,半字为2, 双字为8),置入寄存器左部(小端)。如小端机器上,始地址为 t1 = 0x1022,则:ldr t0, 0(t1) 取 0x1022~0x1027 到 t0 的右部
ldl t0, 7(t1) 取 0x1028~0x1029 到 t0 的左部注 意上述指令的后缀 r(right), l(left) 都是相对寄存器而言,load 操作是把取到的部分数据,置入寄存器的 left 或者 right, store 操作是将寄存器中数据的 left 或者 right 部分,写入目标地址而已。无论大端和小端寄存器的格式都是固定的,即右端为低位,左端为高位。任意第一条 ldr/ldl/lwr/lwl/sdr/sdl/swr/swl 只能访问内存的始地址到下一个对齐地址处。 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/comcat/archive/2007/07/31/1719217.aspx
#include
0x1, 0x2, 0x3, 0x4,
0x55aa, 0x66bb, 0x77cc, 0x0000,
};inline void unaligned_access(unsigned short * const row)
{
asm volatile
(
".set mips3 "
".set noreorder " //"lwr $10, 1(%1) "
//"lwl $11, 4(%1) "
//"or $10, $11 "
"ld $10, 2(%1) " /* %1 is double word aligned, %1+2 is double word unaligned */
"sd $10, %0 " ".set reorder "
".set mips0 "
: "=m"(*(row))
: "r"(row+4)
: "$8", "$9", "$10"
);
}int main()
{
printf("--------------------------------------------------------- ");
printf(" Testing Godson2 unaligned access Instruction ");
printf("--------------------------------------------------------- ");// sysmips(MIPS_FIXADE, 0); unaligned_access(data); printf("result is: 0x%04x %04x %04x %04x ", data[3], data[2], data[1], data[0]);} 程序运行后系统提示“非法指令”后退出。
CISC 下(如x86)访存时,如果目标地址不对齐,CPU 不会陷入异常,因为其内部有处理非对齐访问的微程序。
2. 解决高级语言中一般不会遇到这种问题,编译器常常会处理好数据类型的对齐。但万一遇到、抑或在汇编里遇到,避不开怎么办?可以使用 MIPS 的指令集里提供的 lwr/lwl, swr/srl, ldr/ldl, sdr/sdl 指令对。关于他们的原理可以用下图来简单的示意一下(以ldr/ldl 为例,其他类似):
上图解释的是小端模式下的情况,大端模式的情况则相反:首先 ldl t0, 0(t1),然后再 ldr t0, 7(t1)。可 以看到无论大端模式还是小端模式,非对齐访问的解决都是将原来的一条指令(对齐访问)完成的事分两步完成,即首先取始地址 addr 到下一个对齐地址处的部分数据,置入寄存器右部(小端),(大端置入左部(高位)),然后取从该对齐地址到 addr + len - 1 处的部分数据(len 为数据单元长度,半字为2, 双字为8),置入寄存器左部(小端)。如小端机器上,始地址为 t1 = 0x1022,则:ldr t0, 0(t1) 取 0x1022~0x1027 到 t0 的右部
ldl t0, 7(t1) 取 0x1028~0x1029 到 t0 的左部注 意上述指令的后缀 r(right), l(left) 都是相对寄存器而言,load 操作是把取到的部分数据,置入寄存器的 left 或者 right, store 操作是将寄存器中数据的 left 或者 right 部分,写入目标地址而已。无论大端和小端寄存器的格式都是固定的,即右端为低位,左端为高位。任意第一条 ldr/ldl/lwr/lwl/sdr/sdl/swr/swl 只能访问内存的始地址到下一个对齐地址处。 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/comcat/archive/2007/07/31/1719217.aspx
RISC 下非对齐访问的问题
windows下结构体的数据对齐
C语言中一个字节对齐问题的分析
常见的网上邻居访问问题
VFP访问ACCESS的问题.
访问非好友QQ空间的方法!
结构体字节对齐问题!!!
局域网XP访问XP无权限访问的问题处理
WinXP系统?添加静态路由表小试——解决外网不能访问下一层局域网的问题
常见的网上邻居访问问题汇集2
IE下中英文不对齐的原因和解决办法 – 学而得
设计应用:FPGA的八位RISC CPU的设计
访问非好友QQ空间的方法!(顶)
C语言结构体对齐问题
C struct 中字节对齐问题
图片与文字的对齐
局域网内共享文件 提示没有访问权限的问题
测试一下GCC字节对齐的效果
内存对齐的规则以及作用
结构体对齐的具体含义|结构体,对齐,含义,fdsfdsa
引用 使winxp能够通过网上邻居访问WIN7下的共享资源 - jf_du的日志 - 网易...
如何解决IE7频繁弹出“确实允许此网页访问剪贴板吗”的问题
非归档模式下的用户管理备份与恢复
让人出乎意料的非物质文化遗产(下)