C++与汇编的混合编程
一个人不应该用猜的方式,或是等待某大师的宣判,才确定"何时提供一个copy construtor而何时不需要"。--- Stanley B.Lippman
之所以用到汇编,一是关键程序需要极高的效率,需要用汇编来优化;二是有些功能高级语言是做不到的。
混合汇编一般有两种形式:内置汇编和外置汇编。
内置汇编比较简单,主要是因为:
(1)一般不需要考虑寄存器的保存与恢复;
(2)不需要考虑函数的命名问题和调用规则;
(3)可以在程序中直接访问C/C++的局部变量和全局变量,访问C++中的成员变量也是比较容易的;
其不足是失去了模块性。
外置汇编刚好反过来了,有较好的模块性,便于重用和移植,但是相对于内置汇编要复杂一些,具体体现在上述的几点相反。
下面的程序是我最近在做的一个小东西里的一个小模块,主要作用是获取CPU的一些信息,如是否支持MMX指令。
汇编采用外置汇编,nasm格式;C++采用VC6作为编译器。
为了简单起见,我去掉了头文件。所以一共两个文件:(1)cpu.cpp;(2)cpuAsm.asm
(1)cpu.cpp:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
(2)cpuAsm.asm:
[section .text class = code use32]
; void _stdcall setCPUInfo_via_asm(BMCPU * bmcpu);
global _setCPUInfo_via_asm@ 4
_setCPUInfo_via_asm@ 4 :
; -------------------------------------------------
push ebp ; save ebp
mov ebp, esp ; esp -> ebp
push ebx ; save ebx, esi, edi
push esi
push edi
; -------------------------------------------------
mov ebx, [ebp + 8 ] ; R[ebx] = bmcpu, then
; M[ebx] = int m_iCPUID
; M[ebx + 4 ] = int m_iFPU
; M[ebx + 8 ] = int m_iMMX
; M[ebx + 12 ] = int m_i3DNow
; M[ebx + 16 ] = char m_szOEM[ 16 ]
; M[ebx + 32 ] = char m_szSpecification[ 52 ];
; set int m_iFPU
.setfpu_start:
fninit
mov eax, 0x5a5a
fnstsw ax
cmp eax, 0
jne .nofpu
mov [ebx + 4 ], dword 1 ; int m_iFPU = 1 ;
jmp .setfpu_end
.nofpu:
mov [ebx + 4 ], dword 0 ; int m_iFPU = 0 ;
.setfpu_end:
; set int m_iCPUID
.setcpuid_start:
pushfd ; get extended flags
pop eax;
mov ecx, eax ; save current flags
xor eax, 0x200000 ; toggle bit 21
push eax ; put new flags on stack
popfd ; flags updated now in flags
pushfd ; get extended flags
pop eax
xor eax, ecx ; if bit 21 r / w then supports cpuid
jz .nocpuid
mov [ebx], dword 1 ; int m_iCPUID = 1 ;
jmp .setcpuid_end
.nocpuid:
mov [ebx], dword 0 ; int m_iCPUID = 0 ;
mov [ebx + 8 ], dword 0 ; int m_iMMX = 0 ;
mov [ebx + 12 ], dword 0 ; int m_i3DNow = 0 ;
mov [ebx + 16 ], byte 0 ; set char m_szOEM[ 16 ] null string
mov [ebx + 32 ], byte 0 ; set char m_szSpecification[ 52 ] null string
jmp .returnAsm ; cupid not supported, then return
.setcpuid_end:
; set int m_iMMX
.setmmx_start:
mov esi, ebx ; save ebx to esi
mov eax, 1
cpuid
and edx, 0x800000
jz .nommx
mov [esi + 8 ], dword 1 ; int m_iMMX = 1 ;
jmp .setmmx_end
.nommx:
mov [esi + 8 ], dword 0 ; int m_iMMX = 0 ;
.setmmx_end:
mov ebx, esi ; restore ebx from esi
; set int m_i3DNow
.set3dnow_start:
mov esi, ebx ; save ebx to esi
mov eax, 0x80000001
cpuid
and edx, 0x80000000
jz .no3dnow
mov [esi + 12 ], dword 1 ; int m_i3DNow = 1 ;
jmp .set3dnow_end
.no3dnow:
mov [esi + 12 ], dword 0 ; int m_i3DNow = 0 ;
.set3dnow_end:
mov ebx, esi ; restore ebx from esi
; set char m_szOEM[ 16 ]
.setoem_start:
mov esi, ebx ; save ebx to esi
mov eax, 0
cpuid
mov [esi + 16 ], ebx ; char m_szOEM[ 0 - 3 ] = ebx;
mov [esi + 20 ], edx ; char m_szOEM[ 4 - 7 ] = edx;
mov [esi + 24 ], ecx ; char m_szOEM[ 8 - 11 ] = edx;
mov [esi + 28 ], byte 0 ; char m_szOEM[ 12 ] = 0 ;
mov ebx, esi ; restore ebx from esi
.setoem_end:
; set char char m_szSpecification[ 52 ]
.setspec_start:
mov esi, ebx ; save ebx to esi
mov eax, 0x80000002
cpuid
mov [esi + 32 ], eax ; char m_szSpecification[ 0 - 3 ] = eax;
mov [esi + 36 ], ebx ; char m_szSpecification[ 4 - 7 ] = ebx;
mov [esi + 40 ], ecx ; char m_szSpecification[ 8 - 11 ] = ecx;
mov [esi + 44 ], edx ; char m_szSpecification[ 12 - 15 ] = edx;
mov eax, 0x80000003
cpuid
mov [esi + 48 ], eax
mov [esi + 52 ], ebx
mov [esi + 56 ], ecx
mov [esi + 60 ], edx
mov eax, 0x80000004
cpuid
mov [esi + 64 ], eax
mov [esi + 68 ], ebx
mov [esi + 72 ], ecx
mov [esi + 76 ], edx
mov [esi + 77 ], byte 0 ; char m_szSpecification[ 48 ] = 0 ;
mov ebx, esi ; restore ebx from esi
.setspec_end:
; -------------------------------------------------
.returnAsm:
pop edi ; restore ebx, esi, edi
pop esi
pop ebx
mov esp, ebp ; restore ebp
pop ebp
ret 4
运行结果:
在自己机器上:
Support CPUID : 1
Support FPU : 1
Support MMX : 1
Support 3DNow : 0
O E M : GenuineIntel
Specification : Intel(R) Pentium(R) 4 CPU 2.80G
在一台CPU为AMD的机器上:
Support CPUID : 1
Support FPU : 1
Support MMX : 1
Support 3DNow : 1
O E M : AuthenticAMD
Specification : AMD Athlon(tm) XP 1700+
几点小结:
(1)环境:把nasmw拷贝到VC的bin下,建好工程文件后,右键单击cpuAsm.asm,Settings->Custom Build中Commands填入nasmw $(InputName).asm -f win32 -o $(IntDir)/$(InputName).obj,Outputs一栏填入$(IntDir)/$(InputName).obj。如果工程的文件分布复杂一点,Commands是要根据需要作一点变动的。^_^。
(2)函数的命名(C++和C的函数命名是不同的,考虑到可移植性,这里仍然用C函数命名)和函数的调用规则是要注意的。例如stdcall是要自己来进行参数退栈的,用ret XXX 来进行,这也是_setCPUInfo_via_asm@4为什么@符号带上一个数字的原因。
(3)变量访问的问题。这个涉及到C++的对象模型以及内存对齐等一些细节,因而不太确定的情况下需要试验,而且一般尽量保证4字节对齐会使问题简化很多。这也是在cpu.cpp把本应该是bool类型的变量设置成int类型,字符数组的大小设置成4×的原因。
^_^,就这么多。