This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] 编译器/MSP432P401R:非对齐uint64的间接分配会导致运行时故障

Guru**** 2540720 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/578111/compiler-msp432p401r-indirect-assignment-of-non-aligned-uint64-causes-runtime-fault

部件号:MSP432P401R

工具/软件:TI C/C++编译器

大家好,

TI v 16.9 0 LTS编译器。

我在不对齐访问时遇到一些问题。  以下是一个示例:

typedef结构
{
uint8_t a_u8;
uint64_t b_u64;
uint8_t e_u8;
}__attribute__(packed) myStruct;

myStruct m_st;

uint8_t f_u8;
uint8_t *g_u8_ptr;

uint64_c;
uINT64_t *d_u64_ptr;

// uint8_t非对齐访问
f_u8 = 0xAA;
g_u8_ptr =&(m_st.e_u8);// e_u8不是32位对齐

的m_st.e_u8 = f_u8; //直接访问工作
*g_u8_ptr = g_u8_ptr; //间接访问工作

// uint64_t非对齐访问
c_u64 = 0xabcdabcdabcdabcdcd;
d_u64_ptr =&(m_st.b_u64);// b_u64未对齐32位。 
m_st.b_u64 = c_u64; //直接访问工作

*d_u64_ptr = c_u64; //间接访问导致崩溃

指定(直接或间接)不对齐的uint8_t没有问题-编译器知道如何处理此问题。

但对于uint64_t,我发现间接分配会导致微系统崩溃。

我正在TIRTOS项目中运行此程序,所以我看到System_exit()带有以下转储:

FSR = 0x0100
HFSR = 0x4000万
DFSR = 0x0.0001万
MMAR = 0xe000ed34
BFAR = 0xe000ed38
AFSR = 0x0万

谢谢

朱利安

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我尚未找到关于这一点的任何权威文件。  但我很肯定这句话...

    Julian Kolodko 说:
    d_u64_ptr =&(m_st.b_u64);// b_u64位未对齐。

    ...导致违反严格别名规则。  此规则非常详细,但底线是用于执行内存访问的类型,必须与用于定义原始变量的类型近似匹配。  在此语句中,您将结构的打包成员的地址复制到常规的非打包指针中。  以后使用指针时违反了规则。

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    格代·乔治

    我承认我所做的最多也是淘气的。  (我猜这个问题比我所理解的要深得多- TI编译器和GCC都有相同的问题)。

    但是,至少表面上看,如果编译器可以检测8位不对齐的间接访问并生成工作代码,编译器至少不能在不对齐的64位间接访问的情况下生成警告??

    实际上,如下面的示例所示,8位,16位和32位访问都可以正常工作,并且完全按照您的期望执行,尽管通过非对齐指针进行间接访问。  为什么不使用64位?

    typedef结构

     uINT8_t d1_u8; //混乱的对齐
     uINT64_t t_u64;
     uINT8_t t_u8;
     uINT8_t d2_u8; //混乱的对齐
     UINT16_t T_U16;
     uINT32_t t_u32;
    }__attribute__((cpacked) myStruct;

       myStruct m_st;

       uINT8_t data_u8;
       uINT8_t *t_u8_ptr;

       UINT16_t DATA_U16;
       UINT16_t *t_U16_ptr;

       uINT32_t data_u32;
       uINT32_t *t_u32_ptr;

       uINT64_t data_u64;
       uINT64_t *t_u64_ptr;


       // uint8_t不对齐访问
       data_u8 = 0xab;
       t_u8_ptr =&(m_st.t_u8);  // t_u8_ptr未对齐32位

       m_st.t_u8 = data_u8;      //直接访问工作
       *t_u8_ptr = data_u8;      //间接访问工作


       // uint16_t不对齐访问
       DATA_U16 = 0xabcd;
       T_U16_PTR =&(m_st.t_U16);// t_U16_PTR未32位对齐

       m_st.t_U16 = DATA_U16;    //直接访问工作
       *T_U16_PTR = DATA_U16;    //间接访问工作


       // UINT32_t不对齐访问
       data_u32 = 0xabcdabcd;
       t_u32_ptr =&(m_st.t_u32);// t_u32_ptr未对齐32位

       m_st.t_u32 = data_u32;    //直接访问工作
       *t_u32_ptr = data_u32;    //间接访问工作


       // uint64_t不对齐访问
       data_u64 = 0xabcdabcdabcdabcd;
       t_u64_ptr =&(m_st.t_u64);// t_u64_ptr未对齐32位。

       m_st.t_u64 = data_u64;    //直接访问工作
       *t_u64_ptr = data_u64;    //间接访问导致崩溃;  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,George,

    我在编译器手册中找到了以下内容(SPNU151N  部分5.16。4)

    "隐式或显式地将压缩结构成员的地址转换为指向除无符号字符之外的任何非压缩类型的指针是非法的。 "

    如果我理解这一点(我不确定我是否正确,因为我认为这里没有任何类型的铸造),则意味着我的示例中的以下行是非法的。

    T_U16_PTR =&(m_st.t_U16);  

    t_u32_ptr =&(m_st.t_u32);

    t_u64_ptr =&(m_st.t_u64);

    哪一项是好的-但如果是非法的,应该有警告或错误?????

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    无论是否存在显式强制类型转换,每个赋值中都有指针类型转换。 手册中的文本在技术语言方面有点松散;关键点是不能通过指向不同打包类型的指针来访问对象,除非其中一种类型是指向无符号字符的指针。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Julian Kolodko 说:
    我在编译器手册中找到了以下内容[/QUOT]

    感谢你找到了这个。  我通常会找到这样的信息。

    [引用用户="Julian Kolodko"]

    "隐式或显式地将压缩结构成员的地址转换为指向除无符号字符之外的任何非压缩类型的指针是非法的。 "

    如果我理解这一点(我不确定我是不是,因为我认为这里没有任何类型的铸造)

    [/引述]

    您说没有使用显式强制类型转换是正确的。  但也有隐式强制类型转换。  隐式强制类型转换很常见。  在此表达式中...

    Int_var + char_var 

    ... char_var被隐式强制类型转换为int。  具体针对您的示例,请在以下陈述中...

    t_u64_ptr =&(m_st.t_u64); 

    ...封装的64位无符号int的地址被隐式地强制转换为正常(未封装的) 64位无符号int的地址。

    为什么只有64位宽访问失败?  8位宽访问的作用是因为8位宽的指令适用于每个地址。  16位宽和32位宽访问之所以有效,是因为使用的指令依赖于特殊的硬件功能来执行正确的访问,即使地址未对齐也是如此。  64位宽访问使用不同的指令,这些指令缺少这些硬件功能。  有关这些说明的更多背景以及它们与对齐的关系,请参阅 ARM中的这篇文章。  请注意,文章还提到了ARM编译器提供的build开关和关键字。  这些详细信息均不适用于TI编译器。

    Julian Kolodko 说:
    如果非法,应该出现警告或错误????[/QUOT]

    从同样的意义上说,缺少分号也是非法的。  如果使用"未定义"一词而不是"非法"一词,可能会更加明确。  捕获违反此限制的情况比最初出现的情况更困难。  请考虑从编译器手册中获取的此违规示例...

    void foo(int *param);
    struct packed_struct ps;
    
    foo(&ps.i);
    

    实际违规行为发生在FOO内部。  

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    谢谢你,George,

    我学到了很多!
    我没有意识到“封装”是这种类型的一部分,硬件可以处理多达32位的事务。

    感谢你能抽出时间。

    谢谢
    朱利安