Contents
  1. 1. 什么是LAA(LARGE ADDRESS AWARE)
  2. 2. Windows的内存和地址空间限制
    1. 2.1. 什么是4GT(4 Gigabyte Tuning)
    2. 2.2. 什么是PAE(Physical Address Extension)
  3. 3. 如何设置LAA(LARGE ADDRESS AWARE)
    1. 3.1. 给C++程序设置LAA(LARGE ADDRESS AWARE)
    2. 3.2. 给C#程序设置LAA(LARGE ADDRESS AWARE)
  4. 4. 设置LAA对程序做了什么(Windows PE文件格式简介)
    1. 4.1. DOS Stub
    2. 4.2. PE头
  5. 5. 如何检查应用程序有没有设置LAA(LARGE ADDRESS AWARE)
    1. 5.1. 用Dumpbin
    2. 5.2. 用PE Insider
    3. 5.3. 用代码

什么是LAA(LARGE ADDRESS AWARE)

如果我们的应用程序是32位的,那么即使在64位的Windows上运行,默认也最多只能用2G的物理内存。升级程序成64位不是一件特别容易的事情,在升级之前,可以用先LAA(LARGE ADDRESS AWARE)技术来让应用程序可以使用4G内存。

LAA(LARGE ADDRESS AWARE)是应用程序的一个选项,它告诉操作系统,这个应用程序可以处理大于2G的内存。

Windows的内存和地址空间限制

Memory Limits for Windows and Windows Server Releases介绍了Windows各个系统上不同内存类型可用的内存限制,下面表格列举了不同位的应用程序在不同位的操作系统上的内存限制。
























内存类型 32位Windows操作系统 64位Windows操作系统

32位程序用户态虚拟地址空间



2G


最多3G(指定IMAGE_FILE_LARGE_ADDRESS_AWARE和4GT)



2G (没指定IMAGE_FILE_LARGE_ADDRESS_AWARE) (默认)


4G (指定IMAGE_FILE_LARGE_ADDRESS_AWARE)



64位程序用户态虚拟地址空间



不能运行



指定IMAGE_FILE_LARGE_ADDRESS_AWARE(默认):


x64:  8 TB


Intel Itanium-based systems:  7 TB


Windows 8.1 and Windows Server 2012 R2:  128 TB


2G (没指定IMAGE_FILE_LARGE_ADDRESS_AWARE)



内核态虚拟地址空间



2G


1G到2G (指定4GT)



8 TB


Windows 8.1 and Windows Server 2012 R2:  128 TB


什么是4GT(4 Gigabyte Tuning)

4GT也叫/3GB开关,是一种允许增加用户态应用程序可用内存大小的技术。32位Windows只能使用最多4G内存,一般是2G内存给内核态,2G内存给用户态。4GT技术通过降低内核态使用的内存(最多降到1G)来增大用户态可以使用的内存。

4GT只适用于32位Windows。

什么是PAE(Physical Address Extension)

PAE(Physical Address Extension)是另外一种处理器的功能,它可以允许特定版本的32位Windows使用超过4G的物理内存。

PAE只适用于32位Windows。

如何设置LAA(LARGE ADDRESS AWARE)

给C++程序设置LAA(LARGE ADDRESS AWARE)

在程序的链接选项中制定Enalbe Large Addresses,如下图所示。

给C#程序设置LAA(LARGE ADDRESS AWARE)

editbin命令。

1
editbin /LARGEADDRESSAWARE <your exe>

设置LAA对程序做了什么(Windows PE文件格式简介)

上面那些设置到底对应用程序做了什么呢?这就需要了解一些Windows Portable Executable文件格式了。PE文件包含下面几个组成部分,详细信息可以参见Microsoft Portable Executable and Common Object File Format Specification。也可以直接看winnt.h头文件,里面有PE格式的详细定义。

PE figure from osdev

DOS Stub

PE文件的第一个部分是DOS Stub,它包含1个DOS头和一个DOS可执行代码。

DOS头的开始是e_magic,值一定是0x5A4D(是ASCII码的Mark Zbikowski首字母缩写,Mark Zbikowski是DOS系统的架构师)。DOS头偏移0x3C的位置是e_lfanew (File address of new exe header),它表明了PE头的位置。可以参加_IMAGE_DOS_HEADER的定义。

DOS的可执行代码就只是简单的输出"This program cannot be run in DOS mode."

PE头

通过上面的e_lfanew可以找到PE头,它一开始就是一个固定值0x4550。接着是文件头,定义是IMAGE_FILE_HEADER

1
2
3
4
5
6
7
8
9
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

PE头的开始表明程序可以运行的机器类型。它的取值范围是:

1
2
3
IMAGE_FILE_MACHINE_I386, 0x014c	
IMAGE_FILE_MACHINE_IA64, 0x0200
IMAGE_FILE_MACHINE_AMD64, 0x8664

PE头偏移0x12Characteristics,它表明了这个应用程序的一些属性。其中一个属性就是IMAGE_FILE_LARGE_ADDRESS_AWARE(0x0020),它表明这个程序可以处理大于2G的内存。

设置应用程序的LAA(LARGE ADDRESS AWARE)就是在应用程序的PE头里面设置这个属性。

如何检查应用程序有没有设置LAA(LARGE ADDRESS AWARE)

知道了设置LAA(LARGE ADDRESS AWARE)对程序做了什么,那么怎么检查应用程序有没有设置LAA(LARGE ADDRESS AWARE)就非常简单了,我们只需要检查文件的PE头,看看Characteristics里有没有设置IMAGE_FILE_LARGE_ADDRESS_AWARE(0x0020)这个属性。

用Dumpbin

首先可以使用DUMPBIN 命令。

1
dumpbin /headers <your exe>

会列出文件的PE头信息,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
FILE HEADER VALUES
14C machine (x86)
6 number of sections
557E68AE time date stamp Mon Jun 15 13:54:54 2015
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
123 characteristics
Relocations stripped
Executable
Application can handle large (>2GB) addresses
32 bit word machine

用PE Insider

也可以使用一些专门的查看PE头的工具来看。比如可以用PE Insider,它是一个免费的看PE头的工具,非常方便,如下所示。

可以点击Description来看具体的Characteristics,如下所示:

用代码

当然我们也可以用代码来打开应用程序检查。下面是C#的示例代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static bool isLargeAware(string file)
{
const int DOS_MZ_HEADER = 0x5A4D;
const int PE_HEADER_OFFSET = 0x3C;
const int NT_HEADER = 0x4550;
const int CHARACTERISTICS_OFFSET = 0x12;
const int IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x20;

using (var fileStream = File.OpenRead(file))
{
using (var binaryReader = new BinaryReader(fileStream))
{
if (binaryReader.ReadInt16() != DOS_MZ_HEADER)
return false;

binaryReader.BaseStream.Position = PE_HEADER_OFFSET;
var peLocation = binaryReader.ReadInt32();

binaryReader.BaseStream.Position = peLocation;
if (binaryReader.ReadInt32() != NT_HEADER)
return false;

binaryReader.BaseStream.Position += CHARACTERISTICS_OFFSET;
return (binaryReader.ReadInt16() & IMAGE_FILE_LARGE_ADDRESS_AWARE) != 0;
}
}
}
Contents
  1. 1. 什么是LAA(LARGE ADDRESS AWARE)
  2. 2. Windows的内存和地址空间限制
    1. 2.1. 什么是4GT(4 Gigabyte Tuning)
    2. 2.2. 什么是PAE(Physical Address Extension)
  3. 3. 如何设置LAA(LARGE ADDRESS AWARE)
    1. 3.1. 给C++程序设置LAA(LARGE ADDRESS AWARE)
    2. 3.2. 给C#程序设置LAA(LARGE ADDRESS AWARE)
  4. 4. 设置LAA对程序做了什么(Windows PE文件格式简介)
    1. 4.1. DOS Stub
    2. 4.2. PE头
  5. 5. 如何检查应用程序有没有设置LAA(LARGE ADDRESS AWARE)
    1. 5.1. 用Dumpbin
    2. 5.2. 用PE Insider
    3. 5.3. 用代码