• 踩坑记 BSS段的初始化



    title: 踩坑记 BSS段的初始化
    category_bar: true
    categories:

    • blog
      tags:
    • embedded
      date: 2023-10-20 19:23:05

    前言

    接手一个项目,调试全靠串口日志,测试同事测试产品的时候无法拿到日志,刚好产品RAM够大,且刚好有SD卡。所以就诞生了将日志缓存在RAM上,在特定条件下将它写到SD卡上的想法。
    .
    .
    .
    开工。
    .
    .
    .
    写完代码之后发现机器偶尔会无法启动,无法开机,无任何日志。
    .
    有的时候是烧录完成代码后重启无法启动,有些情况下是烧录完成代码后运行正常,放置一段时间后无法启动
    .
    有时候有些无法启动的机器放置一段时间又成功启动
    .
    .
    .
    一段一段代码,屏蔽,编译,验证,发现一个非常无法理解的事,TFCardLogBufferPut函数注释后设备可以正常启动。
    .
    .
    .
    看代码:

    #define TF_CARD_LOG_BUFFER_SIZE     (64*1024ul)
    uint8_t tfCardLogBuffer[TF_CARD_LOG_BUFFER_SIZE] = {0};
    uint32_t tfCardLogBufferIndex = 0;
    
    void TFCardLogBufferPut(uint8_t data) {
        tfCardLogBuffer[tfCardLogBufferIndex] = data;
        tfCardLogBufferIndex++;
        if( tfCardLogBufferIndex>=(sizeof(tfCardLogBuffer)/sizeof(tfCardLogBuffer[0]))-1 ) {
            tfCardLogBufferIndex = 0;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    .
    .
    .
    我实在无法理解,这段代码是如何导致设备无法启动的,后面搁置了一段时间,遂归结于小众芯片不完善导致。
    .
    .
    .
    但是后面这个需求实在是过于旺盛,遂重新开始验证代码。

    当时代码是这样的:

    // main.c
    int main(int argc, char **argv) {
        
        hal_uartInit();
        ax32xx_uart0SendByte('a');
        ax32xx_uart0SendByte('b');
        hal_uartSendData('1');
        hal_uartSendData('2');
        ax32xx_uart0SendByte('c');
        
        hal_sysInit();
        
        //.... some code here
    }
    
    // uart.c
    void hal_uartSendData(u8 data)
    {
        ax32xx_uart0SendByte(data);
        
        TFCardLogBufferPut(data);
    }
    
    void ax32xx_uart0SendByte(u8 data)
    {
        R_UART_DATA0 = data;
        while((R_UART_PEND0 & 0x2)==0);
        R_UART_PEND0 |= 1;
    }
    
    #define TF_CARD_LOG_BUFFER_SIZE     (64*1024ul)
    uint8_t tfCardLogBuffer[TF_CARD_LOG_BUFFER_SIZE] = {0};
    uint32_t tfCardLogBufferIndex = 0;
    
    void TFCardLogBufferPut(uint8_t data) {
        tfCardLogBuffer[tfCardLogBufferIndex] = data;
        tfCardLogBufferIndex = (tfCardLogBufferIndex>=(sizeof(tfCardLogBuffer)/sizeof(tfCardLogBuffer[0]))-1) ? 0 : tfCardLogBufferIndex+1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    运行后日志是这样的:

    # 正常运行 的日志
    ab12c ...
    
    # 无法启动 的日志
    ab1
    
    • 1
    • 2
    • 3
    • 4
    • 5

    .
    .
    .
    后面我就猜想了很多:

    • 这个soc不能支持这么大的数值 64KB
    • 这个位置的内存被改写了
    • 和冷启动热启动有关
    • 芯片异常

    .
    .
    .

    后面我猜想,试试把TFCardLogBufferPut函数里面的tfCardLogBufferIndex的数值和data数值输出出来看看。
    .
    .

    这一看不得了,越界了!

    代码:
    代码

    输出日志:

    ab1z31m00327300
    
    • 1

    .
    .
    .

    这个tfCardLogBufferIndex越界了啊!而且初始化赋0并没有成功!这就非常坑爹了!
    .
    .
    .
    后面尝试在调用这个函数之前再次赋0,发现程序运行正常,设备也正常启动。

    查看map文件这个数组和变量也是存放在BSS段的,这就非常令人费解了。
    .
    .
    .
    .
    .
    看到这里我直接就怀疑,就是这个芯片的锅。

    但是别急这还不是让人最震惊的!后面还有让人更加鼻血飙升的。
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .

    最后找FAE排查问题很久,最后发现BSS段在hal_sysInit函数内初始化。

    看代码:

    void ax32xx_sysInit(u32 *saddr,u32 *eaddr)
    {
    	debg("sys init\n");			// 这个debg会调用 hal_uartSendData 函数输出日志
        
        //...
        
    	ax32xx_wdtClear();
    
    //-----cache set
    	ax32xx_sysIcacheInit();
    	ax32xx_sysDcacheInit();	
    //-----bss clear
    	ax32xx_sysBSSClear();
        
        // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    .
    .
    .

    实在是震惊,无法理解这个RAM的初始化为什么放在main函数里面,实在无法理解进入main函数了,c语言环境都没有OK。

    最烦的就是这种xx芯片,总是会有一些让人血压飙升的操作。

    .
    .
    .
    .
    .

    教训

    在对数组进行访问的时候一定要先检查范围。

    // 原函数
    void TFCardLogBufferPut(uint8_t data) {
        tfCardLogBuffer[tfCardLogBufferIndex] = data;
        tfCardLogBufferIndex = (tfCardLogBufferIndex>=(sizeof(tfCardLogBuffer)/sizeof(tfCardLogBuffer[0]))-1) ? 0 : tfCardLogBufferIndex+1;
    }
    
    // 改后
    void TFCardLogBufferPut(uint8_t data) {
        if( tfCardLogBufferIndex>=(sizeof(tfCardLogBuffer)/sizeof(tfCardLogBuffer[0]))-1 ) {
            tfCardLogBufferIndex = 0;
        }
        tfCardLogBuffer[tfCardLogBufferIndex] = data;
        tfCardLogBufferIndex++;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    Linux源码安装RabbitMQ高可用集群
    java-php-python-绿色生活基于PS、DW的绿色环保宣传网站计算机毕业设计
    多中机器学习模型对比可视化
    【R语言数据科学】:文本挖掘(以特朗普推文数据为例)
    redis desktop manager 0.9.3 免费版
    【暑期每日一题】洛谷 P6153 询问
    两数之和 II - 输入有序数组
    KubeCon热点报告:AIStation调度平台实现RoCE网络下大模型的高效稳定训练
    【计算机网络】运输层:为什么TCP在建立连接时不能每次都选择相同固定的初始序号?
    DNS 系列(三):如何免受 DNS 欺骗的侵害
  • 原文地址:https://blog.csdn.net/weixin_42078116/article/details/133952673