最近在调试导致一块网卡不能发包的驱动,最后追踪到这样一段代码:
// Memory-mapped buffer
struct Registers
{
unsigned long DeviceCtrl;
..
};
#define DEVICE_RESET (1 << 26)
..
// m_pReg是一段memory-mapped I/O的起始地址,DeviceCtrl对应的是一个32位硬件寄存器
m_pReg->DeviceCtrl |= DEVICE_RESET;
如果改成下面的代码就可以正常工作:
m_pReg->DeviceCtrl = m_pReg->DeviceCtrl | DEVICE_RESET;
百思不得其解。我的印象中,这两个运算结果应该是完全一样的。决定打开编译器开关(msvc60, /FAs),看看生成的汇编有何不同。
#1
m_pReg->DeviceCtrl = m_pReg->DeviceCtrl | DEVICE_RESET;
汇编
mov eax, DWORD PTR [esi+180] ; 1.把指针变量m_pReg的值load到eax寄存器中
mov eax, DWORD PTR [eax] ; 2.把DeviceCtrl的值load到eax寄存器中,eax+0
or eax, 67108864 ; 3.把(1<<26)和DeviceCtrl取或,再存入eax
mov ecx, DWORD PTR [esi+180] ; 4.同1
mov DWORD PTR [ecx], eax