ARMLinux下Alignment trap的一些测试
常用的是使用等级3来处理,即提示错误并进行修复。
上面只讲到如何使用代码出现字节对齐错误,但没涉及如何排查问题。示例代码十分简单,很容易定位错误地方,但如果在大型项目中,就很难定位,尤其是在嵌入 式中,——嵌入式的调试也相对比较困难、麻烦。以我的经验,与其用gdbserver来调试,不如靠经验及printf大法解决问题来得更快(当然,仅个 人看法)。
本来想用工具调试来发现出错的代码位置,但尝试了,没结果。
在代码编写中,需要注意一下以下的事:
1、结构体尽量使用4字节对齐,比如设置一个传输长度len的类型时,用short表示的范围已经足够,当然也可以用int。像制定一些网络协议,最好考虑一下4字节对齐。
2、分配内存时也尽量4字节对齐,无论是申请的内存还是定义数组大小。
3、对指针进行访问的时候也要十分注意4字节对齐,特别是一些为了避免编译警告的强制类型转换。
http://simplemachines.it/arm-linux/book/afaq.html
项目中有时会遇到字节对齐的问题,英文为“Alignment trap”,如果直译,意思为“对齐陷阱”,不过这个说法不太好理解,还是直接用英文来表达。
ARM平台下一般是4字节对齐,可以参考文后的给出的文章链接。此处不细说。后面提及“字节对齐”
下面的例子使用了几种重现Alignment trap的方法,例子1是将char*指针直接转换成int*指针,经测试,未发现有字节对齐的问题。例子2和例子3相似,主要是结构体中的字段没有进行对齐(或者访问的地址没有4字节对齐)。例子4是直接访问了没有字节对齐的指针。后3个例子在测试时均出现了错误。
/**
*
Linux下对Alignment trap的处理有下面几种方式:
0 (ignored)
1 (warn)
2 (fixup)
3 (fixup+warn)
4 (signal)
5 (signal+warn)
使用方法:
# echo 3 > /proc/cpu/alignment
*/
#include <stdio .h>
#include <stdlib .h>
/// case 1
void fool( unsigned char* buf, int len)
{
unsigned int* p = ( unsigned int*)buf;
int i;
for (i = 0; i < len; i++)
{
*p++ = i+ 1;
printf( "%d ", *p);
}
}
void foolish()
{
unsigned char poor[ 100];
fool(poor, sizeof(poor)/ sizeof( int));
}
// case 1 end
/// case 2
struct rte_unpacked_struct_t
{
char c1;
int i;
char c2;
short s1;
char c3;
};
struct rte_packed_struct_t
{
char c1;
int i;
char c2;
short s1;
char c3;
}__attribute__((__packed__));
struct rte_unpacked_struct_t unpacked;
struct rte_packed_struct_t packed;
void print_addr()
{
printf( "sizeof(unpacked) = %d sizeof(packed) = %d\n", sizeof(unpacked), sizeof(packed));
printf( "Addr of unpacked: %p\n", &unpacked);
printf( "Addr of unpacked.c1: %p\n", &unpacked .c1);
printf( "Addr of unpacked.i: %p\n", &unpacked .i);
printf( "Addr of unpacked.c2: %p\n", &unpacked .c2);
printf( "Addr of unpacked.s1: %p\n", &unpacked .s1);
printf( "Addr of unpacked.c3: %p\n", &unpacked .c3);
printf( "Addr of packed: %p\n", &packed);
printf( "Addr of packed.c1: %p\n", &packed .c1);
printf( "Addr of packed.i: %p\n", &packed .i);
printf( "Addr of packed.c2: %p\n", &packed .c2);
printf( "Addr of packed.s1: %p\n", &packed .s1);
printf( "Addr of packed.c3: %p\n", &packed .c3);
}
short* rte_get_s1( void)
{
return &unpacked .s1;
}
void case2()
{
print_addr();
int* val = ( int *)rte_get_s1();
printf( "val = %d\n", *val);
}
/// case 2 end
/// case 3
struct foo_t
{
short a;
short b;
short c;
short d;
};
struct foo_t foo;
short* get_foo_c( void)
{
return &foo . c;
}
void case3()
{
printf( "sizeof(foo) = %d\n", sizeof(foo));
// 注意!!此处将short*强制转换为int*,造成出错
int* val = ( int *)get_foo_c();
printf( "val: %d\n", *val);
}
// case 3 end
//
/// case 4
void case4()
{
char* str = "01234567";
unsigned* u = ( unsigned *)(str+ 1);
printf( "0x%08x\n", *u);
}
/// case 4 end
int main()
{
printf( "test of alignment trap...\n");
//foolish();
//case2();
//case3();
case4();
return 0;
}
*
Linux下对Alignment trap的处理有下面几种方式:
0 (ignored)
1 (warn)
2 (fixup)
3 (fixup+warn)
4 (signal)
5 (signal+warn)
使用方法:
# echo 3 > /proc/cpu/alignment
*/
#include <stdio .h>
#include <stdlib .h>
/// case 1
void fool( unsigned char* buf, int len)
{
unsigned int* p = ( unsigned int*)buf;
int i;
for (i = 0; i < len; i++)
{
*p++ = i+ 1;
printf( "%d ", *p);
}
}
void foolish()
{
unsigned char poor[ 100];
fool(poor, sizeof(poor)/ sizeof( int));
}
// case 1 end
/// case 2
struct rte_unpacked_struct_t
{
char c1;
int i;
char c2;
short s1;
char c3;
};
struct rte_packed_struct_t
{
char c1;
int i;
char c2;
short s1;
char c3;
}__attribute__((__packed__));
struct rte_unpacked_struct_t unpacked;
struct rte_packed_struct_t packed;
void print_addr()
{
printf( "sizeof(unpacked) = %d sizeof(packed) = %d\n", sizeof(unpacked), sizeof(packed));
printf( "Addr of unpacked: %p\n", &unpacked);
printf( "Addr of unpacked.c1: %p\n", &unpacked .c1);
printf( "Addr of unpacked.i: %p\n", &unpacked .i);
printf( "Addr of unpacked.c2: %p\n", &unpacked .c2);
printf( "Addr of unpacked.s1: %p\n", &unpacked .s1);
printf( "Addr of unpacked.c3: %p\n", &unpacked .c3);
printf( "Addr of packed: %p\n", &packed);
printf( "Addr of packed.c1: %p\n", &packed .c1);
printf( "Addr of packed.i: %p\n", &packed .i);
printf( "Addr of packed.c2: %p\n", &packed .c2);
printf( "Addr of packed.s1: %p\n", &packed .s1);
printf( "Addr of packed.c3: %p\n", &packed .c3);
}
short* rte_get_s1( void)
{
return &unpacked .s1;
}
void case2()
{
print_addr();
int* val = ( int *)rte_get_s1();
printf( "val = %d\n", *val);
}
/// case 2 end
/// case 3
struct foo_t
{
short a;
short b;
short c;
short d;
};
struct foo_t foo;
short* get_foo_c( void)
{
return &foo . c;
}
void case3()
{
printf( "sizeof(foo) = %d\n", sizeof(foo));
// 注意!!此处将short*强制转换为int*,造成出错
int* val = ( int *)get_foo_c();
printf( "val: %d\n", *val);
}
// case 3 end
//
/// case 4
void case4()
{
char* str = "01234567";
unsigned* u = ( unsigned *)(str+ 1);
printf( "0x%08x\n", *u);
}
/// case 4 end
int main()
{
printf( "test of alignment trap...\n");
//foolish();
//case2();
//case3();
case4();
return 0;
}
# echo 0 > /proc/cpu/alignment
# ./a.out
test of alignment trap...
0x30333231
# echo 1 > /proc/cpu/alignment
# ./a.out
testAlignment trap: a.out (1125) PC=0x000086c8 Instr=0xe5931000 Address=0x00008961 FSR 0x001
of alignment trap...
0x30333231
# echo 2 > /proc/cpu/alignment
# ./a.out
test of alignment trap...
0x34333231
# echo 3 > /proc/cpu/alignment
# ./a.out
testAlignment trap: a.out (1127) PC=0x000086c8 Instr=0xe5931000 Address=0x00008961 FSR 0x001
of alignment trap...
0x34333231
# echo 4 > /proc/cpu/alignment
# ./a.out
test of alignment trap...
Bus error
# echo 5 > /proc/cpu/alignment
# ./a.out
testAlignment trap: a.out (1129) PC=0x000086c8 Instr=0xe5931000 Address=0x00008961 FSR 0x001
of alignment trap...
Bus error
# ./a.out
test of alignment trap...
0x30333231
# echo 1 > /proc/cpu/alignment
# ./a.out
testAlignment trap: a.out (1125) PC=0x000086c8 Instr=0xe5931000 Address=0x00008961 FSR 0x001
of alignment trap...
0x30333231
# echo 2 > /proc/cpu/alignment
# ./a.out
test of alignment trap...
0x34333231
# echo 3 > /proc/cpu/alignment
# ./a.out
testAlignment trap: a.out (1127) PC=0x000086c8 Instr=0xe5931000 Address=0x00008961 FSR 0x001
of alignment trap...
0x34333231
# echo 4 > /proc/cpu/alignment
# ./a.out
test of alignment trap...
Bus error
# echo 5 > /proc/cpu/alignment
# ./a.out
testAlignment trap: a.out (1129) PC=0x000086c8 Instr=0xe5931000 Address=0x00008961 FSR 0x001
of alignment trap...
Bus error
常用的是使用等级3来处理,即提示错误并进行修复。
上面只讲到如何使用代码出现字节对齐错误,但没涉及如何排查问题。示例代码十分简单,很容易定位错误地方,但如果在大型项目中,就很难定位,尤其是在嵌入 式中,——嵌入式的调试也相对比较困难、麻烦。以我的经验,与其用gdbserver来调试,不如靠经验及printf大法解决问题来得更快(当然,仅个 人看法)。
本来想用工具调试来发现出错的代码位置,但尝试了,没结果。
在代码编写中,需要注意一下以下的事:
1、结构体尽量使用4字节对齐,比如设置一个传输长度len的类型时,用short表示的范围已经足够,当然也可以用int。像制定一些网络协议,最好考虑一下4字节对齐。
2、分配内存时也尽量4字节对齐,无论是申请的内存还是定义数组大小。
3、对指针进行访问的时候也要十分注意4字节对齐,特别是一些为了避免编译警告的强制类型转换。
参考资料:
http://www.rt-embedded.com/blog/archives/resolving-alignment-traps/http://simplemachines.it/arm-linux/book/afaq.html