最新消息:

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

nsis 永恒心锁 2514浏览 0评论

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

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

好了,下面上源码了:

[php] view plaincopy

  1. ;
  2. ; Get the native system info
  3. ;
  4. System::Alloc 32
  5. Pop $0
  6. System::Call “Kernel32::GetNativeSystemInfo(i) v (r0)”
  7. System::Call “*$0(&i2 .r1)”
  8. System::Free $0
  9. StrCmp $1 9 0 +2
  10. DetailPrint PROCESSOR_ARCHITECTURE_AMD64
  11. StrCmp $1 6 0 +2
  12. DetailPrint PROCESSOR_ARCHITECTURE_IA64
  13. StrCmp $1 0 0 +2
  14. DetailPrint PROCESSOR_ARCHITECTURE_INTEL
  15. StrCmp $1 0xffff 0 +2
  16. DetailPrint PROCESSOR_ARCHITECTURE_UNKNOWN

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

首先看前两句:

[php] view plaincopy

  1. System::Alloc 32
  2. 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

  1. typedef struct _SYSTEM_INFO {
  2. union {
  3. DWORD dwOemId;
  4. struct {
  5. WORD wProcessorArchitecture;
  6. WORD wReserved;
  7. };
  8. };
  9. DWORD dwPageSize;
  10. LPVOID lpMinimumApplicationAddress;
  11. LPVOID lpMaximumApplicationAddress;
  12. DWORD_PTR dwActiveProcessorMask;
  13. DWORD dwNumberOfProcessors;
  14. DWORD dwProcessorType;
  15. DWORD dwAllocationGranularity;
  16. WORD wProcessorLevel;
  17. WORD wProcessorRevision;
  18. } SYSTEM_INFO;

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

[cpp] view plaincopy

  1. #define PROCESSOR_ARCHITECTURE_INTEL            0
  2. #define PROCESSOR_ARCHITECTURE_IA64             6
  3. #define PROCESSOR_ARCHITECTURE_AMD64            9
  4. #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不光是指字符串比较,数字比较它也兼任了。

 

永恒心锁,版权所有丨如未注明,均为转载丨本网站采用BY-NC-SA协议进行授权

转载请注明:永恒心锁-分享互联网 » NSIS脚本源码分析: 如何判断CPU平台类型

您必须 登录 才能发表评论!