现在查看的简短程序实现如下操作:读取一个文件,对其进行加密,再将其输出到另一个文件。函数 TranslateBuffer 用一个 __asm 块定义语句,在一个字符数组内进行循环,并把每个字符与预定义值进行 XOR 运算。
内嵌语言可以使用函数形参、局部变量和代码标号。由于本例是由 Microsoft Visual C++ 编译的 Win32 控制台应用,因此其无符号整数类型为 32 位:
void TranslateBuffer(char * buf,
unsigned count, unsigned char eChar)
{
__asm {
mov esi, buf
mov ecx, count
mov al, eChar
L1:
xor [esi],al
inc esi
loop L1
} // asm
}
C++ 启动程序从命令行读取输入和输出文件名。在循环内调用 TranslateBuffer 从文件读取数据块,加密,再将转换后的缓冲区写入新文件:
// ENCODE.CPP 复制并加密文件。
#include <iostream>
#include <fstream>
#include "translat.h"
using namespace std;
int main( int argcount, char * args[] )
{
// 从命令行读取输入和输出文件
if( argcount < 3 ) {
cout << "Usage: encode infile outfile" << endl;
return -1;
}
const int BUFSIZE = 2000;
char buffer[BUFSIZE];
unsigned int count; // 字符计算
unsigned char encryptCode;
cout << "Encryption code [0-255]? ";
cin >> encryptCode;
ifstream infile( args[1], ios::binary );
ofstream outfile( args[2], ios::binary );
cout << "Reading " << args[1] << " and creating "
<< args[2] << endl;
while (!infile.eof() )
{
infile.read(buffer, BUFSIZE );
count = infile.gcount();
TranslateBuffer(buffer, count, encryptCode);
outfile.write(buffer, count);
}
return 0;
}
用命令提示符运行该程序,并传递输入和输岀文件名是最容易的。比如,下面的命令行读取 infile.txt,生成 encoded.txt:
头文件 translat.h 包含了 TranslateBuffer 的一个函数原型:
如果在调试器调试程序时查看 Disassembly 窗口,那么,看到函数调用和返回究竟有多少开销是很有趣的。下面的语句将三个实参送入堆栈,并调用 TranslateBuffer。在 Visual C++ 的 Disassembly 窗口,激活 Show Source Code 和 Show Symbol Names 选项:
下面的代码对 TranslateBuffer 进行反汇编。编译器自动插入了一些语句用于设置 EBP,以及保存标准寄存器集合,集合内的寄存器不论是否真的会被过程修改,总是被保存。
push ebp
mov ebp, esp
sub esp,40h
push ebx
push esi
push edi
;内嵌代码从这里开始。
mov esi,dword ptr [buf]
mov ecx,dword ptr [count]
mov al,byte ptr [eChar]
L1:
xor byte ptr [esi],al
inc esi
loop L1 (41D762h)
;内嵌代码结束。
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
若关闭了调试器 Disassembly 窗口的 Display Symbol Names 选项,则将参数送入寄存器的三条语句如下:
编译器按要求生成 Debug 目标代码,这是非优化代码,适合于交互式调试。如果选择 Release 目标代码,那么编译器生成的代码就会更加有效(但易读性更差)。
本节前面给出的 TranslateBuffer 中有 6 条内嵌指令,其执行总共需要 8 条指令。
如果函数被调用几千次,那么其执行时间就比较可观了。为了消除这种开销,把内嵌代码插入调用 TranslateBuffer 的循环,得到更为有效的程序:
while (!infile.eof() )
{
infile.read(buffer, BUFSIZE );
count = infile.gcount();
__asm {
lea esi,buffer
mov ecx,count
mov al, encryptCode
L1:
xor [esi],al
inc esi
Loop L1
} // asm
outfile.write(buffer, count);
}