rtthread 字节对齐问题 int指针访问非对齐地址崩溃

rtthread 字节对齐问题 int指针访问非对齐地址崩溃
环境:
SOC: i.MX RT1050
底板: 野火 RT1052
Kernel: rt-thread

背景:
我正在实现解析udp包, 而udp包的结构不是字节对齐的, 这个时候我使用__packed来说明按照1字节对齐, 在解析udp包数据的地方, 取udp->srcaddr这个成员的值的时候, 出现 UNALIGN(未对齐) 错误. 我将该问题用以下代码来复现. 如果有更好的网络协议数据结构体定义方式, 还请告知, 谢谢

现象:
使用rtthread master版 生成的工程运行后会出现以下问题, 但使用裸机程序, 或者 rtthread nano版 运行后不会出现以下问题. 这个问题还未有答案, 如果有哪位道友, 遇到了, 一起学习探讨

/*
        1.内存 堆区
            a.uint32_t* 类型, 所指向的地址必须是四字节对齐
            b.uint16_t* 类型, 所指向的地址必须是两字节对齐
        2.内存 RW/ZI 区
            a.uint32_t* 类型, 所指向的地址必须是四字节对齐
            b.uint16_t* 类型, 所指向的地址必须是两字节对齐
        3.DTCM
            a.uint32_t* 类型, 非四字节对齐地址任然可以访问
            b.uint16_t* 类型, 非两字节对齐地址任然可以访问
        4.内存 栈区
            定义一字节对齐结构体, 任意成员可以访问
        5.内存 栈区 char数组
            a.uint32_t* 类型, 非四字节对齐地址无法访问
            a.uint16_t* 类型, 非两字节对齐地址无法访问
    */
    /* 内存 栈区 char数组 
    __packed char data[128];
    rt_kprintf("&data[0]: %p\n", &data[0]);
    __packed uint32_t* p = (__packed uint32_t*)(&data[0]);
    rt_kprintf("*p: %x\n", *p);
    p = (__packed uint32_t*)(&data[0]+1);
    rt_kprintf("p: %p\n", p);
    rt_kprintf("*p: %x\n", *p);
    
    __packed uint16_t* p2 = (__packed uint16_t*)(data);
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (__packed uint16_t*)(data+1);
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (__packed uint16_t*)(data+3);
    rt_kprintf("*p2: %x\n", *p2);*/
    
    rt_kprintf("sizeof(eth_hdr): %d; sizeof(ip_hdr): %d\n",sizeof(eth_hdr),sizeof(ip_hdr));
    uint8_t* tpoint = (uint8_t*)malloc(60);
    rt_kprintf("tpoint: %p\n", tpoint);
    eth_hdr* ethhdr = (eth_hdr*)tpoint;
    tpoint += sizeof(eth_hdr);
    ip_hdr* iphdr = (ip_hdr*)tpoint;
    rt_kprintf("tpoint: %p\n", tpoint);
    rt_kprintf("iphdr: %p\n", iphdr);
    iphdr->tlen = 0x10;
    rt_kprintf("iphdr->tlen: %x\n", iphdr->tlen);
    rt_kprintf("&iphdr->srcaddr: %p\n", &iphdr->srcaddr);
    iphdr->srcaddr = 0x1111;
    rt_kprintf("iphdr->srcaddr: %x\n", iphdr->srcaddr);
    
    /* 内存 栈区 一字节对齐结构体访问 
    ip_hdr iphdr;
    iphdr.srcaddr = 0x1111;
    rt_kprintf("sizeof(iphdr): %d\n", sizeof(iphdr));
    rt_kprintf("iphdr.srcaddr: %d\n", iphdr.srcaddr);*/
    
    /* DTCM 0x20000000 
    uint32_t* p = (uint32_t*)0x20000000;
    rt_kprintf("*p: %x\n", *p);
    p = (uint32_t*)0x20000004;
    rt_kprintf("*p: %x\n", *p);
    p = (uint32_t*)0x20000008;
    rt_kprintf("*p: %x\n", *p);
    
    uint16_t* p2 = (uint16_t*)0x20000000;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x20000002;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x20000004;
    rt_kprintf("*p2: %x\n", *p2);
    
    p = (uint32_t*)0x20000001;
    rt_kprintf("*p: %x\n", *p);
    p2 = (uint16_t*)0x20000001;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x20000003;
    rt_kprintf("*p2: %x\n", *p2);*/
    
    /* 内存 RW/ZI 区, 字节对齐测试 
    uint32_t* p = (uint32_t*)0x80200000;
    rt_kprintf("*p: %x\n", *p);
    p = (uint32_t*)0x80200004;
    rt_kprintf("*p: %x\n", *p);
    p = (uint32_t*)0x80200008;
    rt_kprintf("*p: %x\n", *p);
    
    uint16_t* p2 = (uint16_t*)0x80200000;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x80200002;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x80200004;
    rt_kprintf("*p2: %x\n", *p2);
    
    p = (uint32_t*)0x80200001;
    rt_kprintf("*p: %x\n", *p);
    p2 = (uint16_t*)0x80200001;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x80200003;
    rt_kprintf("*p2: %x\n", *p2);*/
    
    
    /* 堆区, 字节对齐测试
    uint32_t* p = (uint32_t*)0x802059a0;
    rt_kprintf("*p: %x\n", *p);
    p = (uint32_t*)0x802059a4;
    rt_kprintf("*p: %x\n", *p);
    p = (uint32_t*)0x802059a8;
    rt_kprintf("*p: %x\n", *p);
    
    uint16_t* p2 = (uint16_t*)0x802059a0;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x802059a2;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x802059a4;
    rt_kprintf("*p2: %x\n", *p2);
    
    p = (uint32_t*)0x802059a1;
    rt_kprintf("*p: %x\n", *p);
    p2 = (uint16_t*)0x802059a1;
    rt_kprintf("*p2: %x\n", *p2);
    p2 = (uint16_t*)0x802059a3;
    rt_kprintf("*p2: %x\n", *p2);*/

程序崩溃报错图示:
程序崩溃报错

在 rtthread nano版 中执行 “内存 RW/ZI 区” 测试, 测试结果如下
在这里插入图片描述

新的怀疑点
在这里插入图片描述
从图中第一行可以看出, 以太网协议数据头结构体大小为14个字节(不为4的整数倍), 而ARP协议数据头结构体, IP协议数据头结构体, UDP协议数据头结构体大小均为4的整数倍. 而保存数据的地址如图中的0x802114ac, 是可以被4整除的. 那么该地址偏移14个字节后地址为0x802114ba, 显然该地址不被4整除. 我在猜测问题是否出在这里呢? 如果数据偏移以太网协议数据头大小到达 ARP协议数据的初始位置. 该地址是4的整数倍, 情况有会是怎么样呢?
我尝试在循环前分别定义了

eth_hdr recv_eth_hdr;
ip_hdr recv_ip_hdr;
icmp_hdr recv_icmp_hdr;
arp_data recv_arp_data;

四个结构体, 然后在检测协议数据前, 从tpoint指针所指向的地址开始, 将接头体大小的数据拷贝到以上定义的结构体中, 然后再来做检测. 然而问题依旧存在, 但问题的范围更加小了, 那就是操作0x802114ba这个地址上的数据就会导致崩溃, 那为什么会这样呢? 我看后面只能通过看汇编源代码, 才能找到问题的症结所在啊.

最后对照代码发现跟以下代码有关系, 具体原因后面在研究

#if defined(BSP_USING_SDRAM)
    /* Region 7 setting */
    MPU->RBAR = ARM_MPU_RBAR(7, 0x80000000U);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_32MB);

    /* Region 8 setting */
    MPU->RBAR = ARM_MPU_RBAR(8, 0x81E00000U);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 1, 0, 0, 0, ARM_MPU_REGION_SIZE_2MB);
#endif

搜索到的相关信息
1
mpu内存保护单元寄存器种类及相关编程
ARM存储器之:存储保护单元MPU
M=0: 禁止MPU
M=1: 使能MPU
A(bit[1])选择是否支持内存访问地址对齐检查
B=0: 禁止地址对齐检查
B=1: 使能地址对齐检查

2
【安富莱STM32F407之uCOS-III教程】第6章 内存保护单元MPU
SCB->CCR |= SCB_CCR_STKALIGN_Msk; // 使能堆栈的双字对齐模式

3
访问未对齐的内存引起硬件异常的解决方法
该代码初始化MPU,使得SDRAM存储器区域被认为是Normal Memory type,而不是Device Memory type。 这将禁用访问对齐限制。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值