Not sure if this quote from Mr. Hyde's book helps but..
"Large Address Unaware Applications
One advantage of 64-bit addresses is that they can access a frightfully large
amount of memory (something like 8TB under Windows). By default, the
Microsoft linker (when it links together the C++ and assembly language
code) sets a flag named LARGEADDRESSAWARE to true (yes). This makes it possible
for your programs to access a huge amount of memory. However, there is a
price to be paid for operating in LARGEADDRESSAWARE mode: the const component
of the [reg64 + const] addressing mode is limited to 32 bits and cannot
span the entire address space.
Because of instruction-encoding limitations, the const value is limited
to a signed value in the range ±2GB. This is probably far more than enough
when the register contains a 64-bit base address and you want to access
a memory location at a fixed offset (less than ±2GB) around that base
address. A typical way you would use this addressing mode is as follows:
lea rcx, someStructure
mov al, [rcx+fieldOffset]
Prior to the introduction of 64-bit addresses, the const offset appearing
in the (32-bit) indirect-plus-offset addressing mode could span the entire
(32-bit) address space. So if you had an array declaration such as
.data
buf byte 256 dup (?)
you could access elements of this array by using the following addressing
mode form:
mov al, buf[ebx] ; EBX was used on 32-bit processors
If you were to attempt to assemble the instruction mov al, buf[rbx] in
a 64-bit program (or any other addressing mode involving buf other than
PC-relative), MASM would assemble the code properly, but the linker would
report an error:
error LNK2017: 'ADDR32' relocation to 'buf' invalid without /LARGEADDRESSAWARE:NO
The linker is complaining that in an address space exceeding 32 bits,
it is impossible to encode the offset to the buf buffer because the machine
instruction opcodes provide only a 32-bit offset to hold the address of buf.
However, if we were to artificially limit the amount of memory that our
application uses to 2GB, then MASM can encode the 32-bit offset to buf into
the machine instruction. As long as we kept our promise and never used any
more memory than 2GB, several new variations on the indirect-plus-offset
and scaled-indexed addressing modes become possible.
To turn off the large address–aware flag, you need to add an extra command
line option to the ml64 command. This is easily done in the build.bat
file; let’s create a new build.bat file and call it sbuild.bat. This file will have
the following lines:
echo off
ml64 /nologo /c /Zi /Cp %1.asm
cl /nologo /O2 /Zi /utf-8 /EHa /Fe%1.exe c.cpp %1.obj /link /largeaddressaware:no
This set of commands tells MASM to pass a
command to the linker that turns off the large address–aware file. MASM,
MSVC, and the Microsoft linker will construct an executable file that
requires only 32-bit addresses (ignoring the 32 HO bits in the 64-bit registers
appearing in addressing modes).
Once you’ve disabled LARGEADDRESSAWARE, several new variants of the
indirect-plus-offset and scaled-indexed addressing modes become available
to your programs:
variable[reg64]
variable[reg64 + const]
variable[reg64 - const]
variable[reg64 * scale]
variable[reg64 * scale + const]
variable[reg64 * scale - const]
variable[reg64 + reg_not_RSP64 * scale]
variable[reg64 + reg_not_RSP64 * scale + const]
variable[reg64 + reg_not_RSP64 * scale - const]
where variable is the name of an object you’ve declared in your source file
by using directives like byte, word, dword, and so on; const is a (maximum
32-bit) constant expression; and scale is 1, 2, 4, or 8. These addressing mode
forms use the address of variable as the base address and add in the current
value of the 64-bit registers."