c语言位运算 汇编代码分析
文章目录
- 位运算代码
- 汇编代码
- 分析
- 🧩 基础背景
- ⚙️ 分析逐步讲解
- 🧠 1️⃣ 定义变量 a、b
- 🧩 2️⃣ 按位与(AND)
- ➤ 执行过程:
- ➤ 结果:
- ➤ 汇编解释:
- 🧩 3️⃣ 按位或(OR)
- ➤ 执行过程:
- ➤ 结果:
- ➤ 汇编解释:
- 🧩 4️⃣ 按位异或(XOR)
- ➤ 执行过程:
- ➤ 结果:
- ➤ 汇编解释:
- 🧩 5️⃣ 按位取反(NOT)
- ➤ 执行过程:
- ➤ 结果:
- ➤ 汇编解释:
- 🧩 6️⃣ 左移(SHL)
- ➤ 执行过程:
- ➤ 结果:
- ➤ 汇编解释:
- 🧩 7️⃣ 右移(SHR)
- ➤ 执行过程:
- ➤ 结果:
- ➤ 汇编解释:
- 🧾 汇总表
- 🧠 编译器生成逻辑分析
- ✅ 总结要点
位运算代码
#include <iostream>
#include <bitset>void basicBitOperations() {unsigned int a = 0b11001100; // 204unsigned int b = 0b10101010; // 170//std::cout << "a = " << std::bitset<8>(a) << " (" << a << ")" << std::endl;//std::cout << "b = " << std::bitset<8>(b) << " (" << b << ")" << std::endl;// 位与运算unsigned int andResult = a & b;//std::cout << "a & b = " << std::bitset<8>(andResult) << " (" << andResult << ")" << std::endl;// 位或运算unsigned int orResult = a | b;//std::cout << "a | b = " << std::bitset<8>(orResult) << " (" << orResult << ")" << std::endl;// 位异或运算unsigned int xorResult = a ^ b;//std::cout << "a ^ b = " << std::bitset<8>(xorResult) << " (" << xorResult << ")" << std::endl;// 位非运算unsigned int notResult = ~a;//std::cout << "~a = " << std::bitset<8>(notResult) << " (" << notResult << ")" << std::endl;// 左移运算unsigned int leftShift = a << 2;//std::cout << "a << 2 = " << std::bitset<8>(leftShift) << " (" << leftShift << ")" << std::endl;// 右移运算unsigned int rightShift = a >> 2;//std::cout << "a >> 2 = " << std::bitset<8>(rightShift) << " (" << rightShift << ")" << std::endl;
}
int main()
{basicBitOperations();
}
汇编代码
--- D:\ReverseEngineering\CPP_Code\位运算\位运算\位运算.cpp -----------------------------1: #include <iostream>2: #include <bitset>3: 4: void basicBitOperations() {
002A1820 push ebp
002A1821 mov ebp,esp
002A1823 sub esp,120h
002A1829 push ebx
002A182A push esi
002A182B push edi
002A182C lea edi,[ebp-60h]
002A182F mov ecx,18h
002A1834 mov eax,0CCCCCCCCh
002A1839 rep stos dword ptr es:[edi]
002A183B mov ecx,offset _3428AB1E_位运算\位运算\位运算@cpp (02AC079h)
002A1840 call @__CheckForDebuggerJustMyCode@4 (02A1325h)
002A1845 nop 5: unsigned int a = 0b11001100; // 204
002A1846 mov dword ptr [a],0CCh 6: unsigned int b = 0b10101010; // 170
002A184D mov dword ptr [b],0AAh 7: 8: //std::cout << "a = " << std::bitset<8>(a) << " (" << a << ")" << std::endl;9: //std::cout << "b = " << std::bitset<8>(b) << " (" << b << ")" << std::endl;10: 11: // 位与运算12: unsigned int andResult = a & b;
002A1854 mov eax,dword ptr [a]
002A1857 and eax,dword ptr [b]
002A185A mov dword ptr [andResult],eax 13: //std::cout << "a & b = " << std::bitset<8>(andResult) << " (" << andResult << ")" << std::endl;14: 15: // 位或运算16: unsigned int orResult = a | b;
002A185D mov eax,dword ptr [a]
002A1860 or eax,dword ptr [b]
002A1863 mov dword ptr [orResult],eax 17: //std::cout << "a | b = " << std::bitset<8>(orResult) << " (" << orResult << ")" << std::endl;18: 19: // 位异或运算20: unsigned int xorResult = a ^ b;
002A1866 mov eax,dword ptr [a]
002A1869 xor eax,dword ptr [b]
002A186C mov dword ptr [xorResult],eax 21: //std::cout << "a ^ b = " << std::bitset<8>(xorResult) << " (" << xorResult << ")" << std::endl;22: 23: // 位非运算24: unsigned int notResult = ~a;
002A186F mov eax,dword ptr [a]
002A1872 not eax
002A1874 mov dword ptr [notResult],eax 25: //std::cout << "~a = " << std::bitset<8>(notResult) << " (" << notResult << ")" << std::endl;26: 27: // 左移运算28: unsigned int leftShift = a << 2;
002A1877 mov eax,dword ptr [a]
002A187A shl eax,2
002A187D mov dword ptr [leftShift],eax 29: //std::cout << "a << 2 = " << std::bitset<8>(leftShift) << " (" << leftShift << ")" << std::endl;30: 31: // 右移运算32: unsigned int rightShift = a >> 2;
002A1880 mov eax,dword ptr [a]
002A1883 shr eax,2
002A1886 mov dword ptr [rightShift],eax 33: //std::cout << "a >> 2 = " << std::bitset<8>(rightShift) << " (" << rightShift << ")" << std::endl;34: }
002A1889 pop edi
002A188A pop esi
002A188B pop ebx
002A188C add esp,120h
002A1892 cmp ebp,esp
002A1894 call __RTC_CheckEsp (02A1249h)
002A1899 mov esp,ebp
002A189B pop ebp
002A189C ret
分析
非常好 👏
你这段代码展示了 C++ 编译后,编译器如何将每一种位运算(&
, |
, ^
, ~
, <<
, >>
)翻译为底层汇编指令。
我们来逐行剖析 C 代码 ↔ 汇编指令 ↔ 实际寄存器行为 ↔ 位级变化。
🧩 基础背景
源代码:
unsigned int a = 0b11001100; // 204 (0xCC)
unsigned int b = 0b10101010; // 170 (0xAA)
unsigned int andResult = a & b;
unsigned int orResult = a | b;
unsigned int xorResult = a ^ b;
unsigned int notResult = ~a;
unsigned int leftShift = a << 2;
unsigned int rightShift = a >> 2;
在汇编中:
- 变量
a
、b
等都分配在函数栈上。 - 每次操作都是
mov → 运算 → mov
三步。 - 寄存器使用
EAX
(主运算寄存器)。
⚙️ 分析逐步讲解
🧠 1️⃣ 定义变量 a、b
002A1846 mov dword ptr [a],0CCh ; a = 0xCC (204)
002A184D mov dword ptr [b],0AAh ; b = 0xAA (170)
变量 | 二进制 | 十进制 | 十六进制 |
---|---|---|---|
a | 11001100 | 204 | 0xCC |
b | 10101010 | 170 | 0xAA |
这两行只是往栈上保存常数,没有计算。
🧩 2️⃣ 按位与(AND)
002A1854 mov eax,dword ptr [a]
002A1857 and eax,dword ptr [b]
002A185A mov dword ptr [andResult],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | 载入 a → EAX = 11001100b |
2️⃣ | 与 b 做 AND → EAX = 11001100 AND 10101010 = 10001000 |
3️⃣ | 保存结果到 andResult |
➤ 结果:
10001000b = 0x88 = 136
➤ 汇编解释:
and eax, [b]
是逐位逻辑与。- 对每一位:1 & 1 → 1,否则 0。
- 常用于 屏蔽(mask)操作。
🧩 3️⃣ 按位或(OR)
002A185D mov eax,dword ptr [a]
002A1860 or eax,dword ptr [b]
002A1863 mov dword ptr [orResult],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100 |
2️⃣ | OR b → 11001100 OR 10101010 = 11101110 |
3️⃣ | 保存结果 |
➤ 结果:
11101110b = 0xEE = 238
➤ 汇编解释:
or eax, [b]
:任一位为 1 → 结果为 1。- 用于 强制开启特定位,如 “设置标志位”。
🧩 4️⃣ 按位异或(XOR)
002A1866 mov eax,dword ptr [a]
002A1869 xor eax,dword ptr [b]
002A186C mov dword ptr [xorResult],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100 |
2️⃣ | XOR b → 11001100 XOR 10101010 = 01100110 |
3️⃣ | 保存结果 |
➤ 结果:
01100110b = 0x66 = 102
➤ 汇编解释:
-
xor eax, [b]
:相同为 0,不同为 1。 -
特性:
x ^ 0 = x
x ^ x = 0
-
常见技巧:
xor eax, eax
用来清零寄存器。
🧩 5️⃣ 按位取反(NOT)
002A186F mov eax,dword ptr [a]
002A1872 not eax
002A1874 mov dword ptr [notResult],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100 |
2️⃣ | NOT → 每一位取反 → 00110011 |
3️⃣ | 保存结果 |
➤ 结果:
00110011b = 0x33 = 51
➤ 汇编解释:
not eax
:1 → 0,0 → 1。- 用于 按位反转。
- 不影响标志位(ZF/SF/CF 不变)。
🧩 6️⃣ 左移(SHL)
002A1877 mov eax,dword ptr [a]
002A187A shl eax,2
002A187D mov dword ptr [leftShift],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100b |
2️⃣ | 左移 2 位 → 00110000b |
3️⃣ | 保存结果 |
➤ 结果:
00110000b = 0x30 = 48
➤ 汇编解释:
shl eax, 2
:逻辑左移 2 位。- 左移时 高位溢出 → CF,低位补 0。
- 相当于:
a * 2² = a * 4
。 - 常用于乘 2 的幂。
🧩 7️⃣ 右移(SHR)
002A1880 mov eax,dword ptr [a]
002A1883 shr eax,2
002A1886 mov dword ptr [rightShift],eax
➤ 执行过程:
步骤 | 内容 |
---|---|
1️⃣ | EAX = 11001100b |
2️⃣ | 右移 2 位 → 00110011b |
3️⃣ | 保存结果 |
➤ 结果:
00110011b = 0x33 = 51
➤ 汇编解释:
shr eax, 2
:逻辑右移 2 位。- 低位移出 → CF;高位补 0。
- 相当于:
a / 4
(对无符号数)。
🧾 汇总表
操作 | C 表达式 | 汇编指令 | 结果(二进制) | 十进制 | 说明 |
---|---|---|---|---|---|
AND | a & b | and eax,[b] | 10001000 | 136 | 按位与,清零特定位 |
OR | a | b | or eax,[b] | 11101110 | 238 |
XOR | a ^ b | xor eax,[b] | 01100110 | 102 | 按位异或,反转不同位 |
NOT | ~a | not eax | 00110011 | 51 | 取反 |
SHL | a << 2 | shl eax,2 | 00110000 | 48 | 左移(×4) |
SHR | a >> 2 | shr eax,2 | 00110011 | 51 | 右移(÷4) |
🧠 编译器生成逻辑分析
在汇编层,所有这些操作都遵循相同模板:
mov eax, [变量1]
<位运算指令> eax, [变量2或立即数]
mov [结果变量], eax
也就是三步:
1️⃣ 载入源操作数。
2️⃣ 执行位级运算。
3️⃣ 存回结果。
由于这些是 单指令逻辑操作(单周期执行),
它们在 CPU 中都由 ALU(算术逻辑单元) 直接完成。
✅ 总结要点
类型 | 汇编指令 | 操作特性 |
---|---|---|
逻辑运算 | and , or , xor , not , test | 不涉及进位,纯二进制位逻辑 |
移位运算 | shl , shr , sar , rol , ror | 位移动与标志控制 |
ALU 执行单元 | 硬件电路级并行完成 | 比加减更快 |
标志位变化 | ZF , SF , CF , PF 更新(NOT 不影响) | 用于分支和条件判断 |