【发布时间】:2019-06-24 08:27:30
【问题描述】:
我在嵌入式 C 应用程序中遇到优化问题。指针的地址意外更改为 0x0 并破坏了我的代码。
我正在使用 GNU MCU Eclipse ARM Embedded GCC 工具链。我正在使用通过 SPI 与之通信的传感器。传感器有 8 个配置寄存器,每个寄存器 16 位。 我将配置的本地副本保存在一个名为“hallsensor_zTleConfig”的结构中 我定期读取传感器存储的配置(“zTleSensorConfig”)并将其与本地副本进行比较,以查看是否发生任何内存损坏。
在没有优化的情况下,此过程有效。
经过优化,在下面的代码中,指向主/本地副本的指针突然无故变为 0x0。
// Master copy of configuration of the TLE chips
static TLE5012B_zCONFIG hallsensor_zTleConfig[ HALLSENSOR_COUNT ];
static void Hallsensor_VerifyConfig( HALLSENSOR_eUNIT eUnit )
{
TLE5012B_zCONFIG zTleSensorConfig;
uint16* pu16MasterConfigPointer = &hallsensor_zTleConfig[ eUnit ];
uint16* pu16SensorConfigPointer = &zTleSensorConfig;
uint8 u8Index;
// Read all configuration parameters
(void)Hallsensor_ReadRegister( TLE5012B_MOD_2, &zTleSensorConfig, sizeof( TLE5012B_zCONFIG ) );
// Copy over configurations modified by Auto-calibration and reserved bits
hallsensor_zTleConfig[ eUnit ].zMod3.u12ANG_BASE = zTleSensorConfig.zMod3.u12ANG_BASE;
hallsensor_zTleConfig[ eUnit ].zSynch.i12AmpSynch = zTleSensorConfig.zSynch.i12AmpSynch;
hallsensor_zTleConfig[ eUnit ].zOffsetX.i12XOffset = zTleSensorConfig.zOffsetX.i12XOffset;
hallsensor_zTleConfig[ eUnit ].zOffsetY.i12YOffset = zTleSensorConfig.zOffsetY.i12YOffset;
hallsensor_zTleConfig[ eUnit ].zMod4.u7TCO_X_T = zTleSensorConfig.zMod4.u7TCO_X_T;
hallsensor_zTleConfig[ eUnit ].zTcoY.u7TCO_Y_T = zTleSensorConfig.zTcoY.u7TCO_Y_T;
hallsensor_zTleConfig[ eUnit ].zMod2.u1Reserved = zTleSensorConfig.zMod2.u1Reserved;
hallsensor_zTleConfig[ eUnit ].zMod4.u1Reserved = zTleSensorConfig.zMod4.u1Reserved;
hallsensor_zTleConfig[ eUnit ].zOffsetX.u4Reserved = zTleSensorConfig.zOffsetX.u4Reserved;
hallsensor_zTleConfig[ eUnit ].zOffsetY.u4Reserved = zTleSensorConfig.zOffsetY.u4Reserved;
hallsensor_zTleConfig[ eUnit ].zSynch.u4Reserved = zTleSensorConfig.zSynch.u4Reserved;
// Compare local Master config setting to sensor settings and look for corrupted data
for ( u8Index = 0; u8Index < TLE5012B_CONFIG_REG_COUNT; u8Index++ )
{
// Configuration invalid?
if ( pu16MasterConfigPointer[u8Index] != pu16SensorConfigPointer[u8Index] )
{
hallsensor_bConfigOk[ eUnit ] = FALSE;
}
}
// Data corrupted?
if ( !hallsensor_bConfigOk[ eUnit ] )
{
// Do stuff
}
}
在函数开始时,pu16MasterConfigPointer 和 pu16SensorConfigPointer 正确地保存了它们对应结构体的地址。但是,就在第一个 for 循环之前,pu16MasterConfigPointer 变为 0x0,并且所有 for 循环条件都为 TRUE。
我已经为不同的变量和指针尝试了多种 volatile 组合,结果仍然以各种其他方式破坏代码(例如,for 循环不会分支 if 语句查看 asm 代码导致语句总是转到“hallsensor_bConfigOk [ eUnit ] = FALSE;")
PS:非常欢迎学习如何保护您的代码免受优化问题的好资源。
显示指针 = 0x0 w/asm 代码的调试器屏幕截图
【问题讨论】:
-
您确定
Hallsensor_ReadRegister写入的字节数不超过sizeof(TLE5012B_zCONFIG)字节吗?如果是这样,那可能是您的指针被破坏的地方。 -
另外,结构是可分配的左值。
-
这将有助于显示
TLE5012B_zCONFIG的定义。 (发布 MCVE 会更有帮助) -
我猜 - 代码中的 UB。如果优化做了这样的事情,这意味着 - 错误在代码中的某个地方。它刚刚被揭开。在类似的情况下,您应该在代码中查找错误,只要需要找到它。顺便说一句 - 更难的优化是查看为特定行生成的代码。
-
不仅
pu16MasterConfigPointer和pu16SensorConfigPointer的初始化无效,而且通过这些指针访问指向的对象违反了严格的别名规则,产生未定义的行为。如果它们是指向字符类型的指针,例如(可能)uint8_t,那就没问题了。或者您有memcmp()可用吗?这是比较结构的可行替代方案吗?
标签: c optimization