NSIS脚本源码分析: 如何判断CPU平台类型

做安装程序时,有时需要支持多个CPU平台。Windows下支持的CPU平台一般有三大类:x86, x64和ia64。

其中,x86就是我们最常用的32位平台,x64则是64位的x86平台,ia64比较特殊,它只存在于Intel Itanium系列芯片中。

好了,下面上源码了:

[php] view plaincopy

;
; Get the native system info
;
System::Alloc 32
Pop $0
System::Call “Kernel32::GetNativeSystemInfo(i) v (r0)”
System::Call “*$0(&i2 .r1)”
System::Free $0
StrCmp $1 9 0 +2
DetailPrint PROCESSOR_ARCHITECTURE_AMD64
StrCmp $1 6 0 +2
DetailPrint PROCESSOR_ARCHITECTURE_IA64
StrCmp $1 0 0 +2
DetailPrint PROCESSOR_ARCHITECTURE_INTEL
StrCmp $1 0xffff 0 +2
DetailPrint PROCESSOR_ARCHITECTURE_UNKNOWN

看到上面的代码是否有点云里雾里的感觉?反正第一眼看过去,我的感觉就是这样。不过,不要急,慢慢地一句一句地分析,自然会将它搞明白的。

首先看前两句:

[php] view plaincopy

System::Alloc 32
Pop $

System是NSIS的一个标准插件,可以在NSIS安装目录的Plugins子目录下可以找到,System.dll是也。System是NSIS中 的一个很重要的插件,安装中的很多高级功能都是通过它来实现的。System::Alloc也就是调用System插件的Alloc接口函数。

System插件的文档可以参考:中文文档 ,英文文档

其实这两句的意思很简单,就是分配32字节的地址空间并将空间地址保存到寄存器r0。可以想象得到,System::Alloc的返回值是压入到堆栈中的,所以要用Pop指令去将它取出来。至于为什么要分配32个字节呢,下面将会说明。

再看下一句:

System::Call “Kernel32::GetNativeSystemInfo(i) v (r0)”

System::Call是System插件中的一个函数调用接口,看到Kernel32::GetNativeSystemInfo,我们就知道它要调的是Windows API GetNativeSystemInfo。那么就将这个API的声明调出来看看:

void GetNativeSystemInfo( LPSYSTEM_INFO lpSystemInfo );

原来,这个API只有一个参数 — 指向一个名为SYSTEM_INFO结构的指针。这个结构又是怎么样的呢,再看:

[cpp] view plaincopy

typedef struct _SYSTEM_INFO {
union {
DWORD dwOemId;
struct {
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
} SYSTEM_INFO;

这个结构中我们感兴趣的是字段wProcessorArchitecture,这个字段可能有如下几种取值情况:

[cpp] view plaincopy

#define PROCESSOR_ARCHITECTURE_INTEL            0
#define PROCESSOR_ARCHITECTURE_IA64             6
#define PROCESSOR_ARCHITECTURE_AMD64            9
#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF

好,看看这个调用的后面参数部分:“(i) v (r0)”,这究竟是什么意思呢?

原来,(i)指的是参数类型,v 表示返回值是void类型,r0 表示指针地址。从上面就可以看出 r0 实际上指的是这个结构的地址,这个地址的空间大小是32。

再继续看:

System::Call “*$0(&i2 .r1)”

说NSIS脚本难以理解,主要就是因为它的插件调用参数字符串太难懂了。象这一句,参数就象天书一样。还好,NSIS参考文档网络上有很多,再不济还是有源代码参考的,这就是开源的好处了。

*$0 表示以寄存器0地址空间的结构,&i2 表示是2字节整数,.r1 表示这个2字节整数的值要存放到寄存器1去。

下一句:

System::Free $0

这应该很好理解,就是将寄存器0的地址空间释放掉。

详细解释前面的语句了,后面的应该不难理解。StrCmp $1 9 0 +2 的意思就是看寄存器1的值是否等于PROCESSOR_ARCHITECTURE_AMD64(9),若相等则执行下一句,若不等则执行下下句。这里需要 注意的是,StrCmp不光是指字符串比较,数字比较它也兼任了。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容