Discussion:
LARGEADDRESSAWARE linker flag, IMAGE_FILE_LARGE_ADDRESS_AWARE exe header bit
(too old to reply)
Ricardo E. Gayoso
2013-04-29 20:34:54 UTC
Permalink
Hi,
Did somebody play with the LARGEADDRESSAWARE linker flag to duplicate the
address space of 32bit exes under Win7 64bit?

I wrote mem_frag.cpp test program (see below) to fill available virtual
address
space, calling heap_dump() to check memory fragmentation.
When I set the exe header bit:
LOADED_IMAGE img;
img.FileHeader->FileHeader.Characteristics |=
IMAGE_FILE_LARGE_ADDRESS_AWARE;
the exe allocates 3.9 Gbytes of RAM on Win7 64bit (instead of the usual 1.9
Gbytes)

Use editbin.exe and dumpbin.exe from VS .NET 2003 or newer.

Compile and set flag:
wcl386 -d2 -w4 -zq mem_frag
editbin /LARGEADDRESSAWARE mem_frag.exe

Check flag:
dumpbin /HEADERS mem_frag.exe

FILE HEADER VALUES
14C machine (x86)
5 number of sections
517EC036 time date stamp Mon Apr 29 15:47:18 2013
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
1A2 characteristics
Executable
Application can handle large (>2GB) addresses <=====
Bytes reversed
32 bit word machine

What about pointer math, like placing a FIFO crossing the boundary address
0x7FFFFFFF, or located above 0x80000000?
I checked and the usual function to calculate the nbr of bytes inside FIFO
still works ok:
if ( (size = fi - fo) < 0 ) {
size += capacity;
}
See ptr32.cpp test program below.

What happens if STL allocates a container crossing the 0x7FFFFFFF boundary?
And if it allocates it 100% above 0x80000000?

Thanks,
Ricardo

********* mem_frag.cpp ************************
/*
This test program plays with heap up to 4 GB.
Must be run on a 64bit Win7.

Use editbin.exe and dumpbin.exe from VS .NET 2003 or newer.

Compile and set flag:
wcl386 -d2 -w4 -zq mem_frag
editbin /LARGEADDRESSAWARE mem_frag.exe

The /LARGEADDRESSAWARE does:
LOADED_IMAGE img;
img.FileHeader->FileHeader.Characteristics |=
IMAGE_FILE_LARGE_ADDRESS_AWARE;


Check flag
dumpbin /HEADERS mem_frag.exe


FILE HEADER VALUES
14C machine (x86)
5 number of sections
517EC036 time date stamp Mon Apr 29 15:47:18 2013
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
1A2 characteristics
Executable
Application can handle large (>2GB) addresses <=====
Bytes reversed
32 bit word machine
*/
/* ----------------------------------------------------------------------------------
*/
#include <stdio.h>
#include <malloc.h>
#include <string.h>
/* ----------------------------------------------------------------------------------
*/
void heap_dump( char *msg, int details )
/*
Check C heap. Prints msg if not NULL.
If details = 0, prints only totals.
If details = 1, prints whole list of used-free blocks.
*/
{
struct _heapinfo h_info;
int heap_status;
unsigned __int64 tot_used = 0;
unsigned __int64 tot_free = 0;

static unsigned __int64 lcl_used = 0;
static unsigned __int64 lcl_free = 0;

h_info._pentry = NULL;
for(;;) {
heap_status = _heapwalk( &h_info );
if( heap_status != _HEAPOK ) {
break;
}
if ( details ) {
printf( " %s block at %Fp of size %u\n",
(h_info._useflag == _USEDENTRY ? "USED" :
"FREE"),
h_info._pentry, h_info._size );
}
if ( h_info._useflag == _USEDENTRY ) {
tot_used += h_info._size;
} else {
tot_free += h_info._size;
}
}
if ( msg != NULL ) {
printf( "%s->", msg );
}
printf( "Used:%8I64u Free:%8I64u Both:%8I64u DUSed:%8I64d
DFree:%8I64d ",
tot_used, tot_free, tot_used + tot_free,
tot_used - lcl_used, tot_free - lcl_free );
lcl_used = tot_used;
lcl_free = tot_free;

switch( heap_status ) {
case _HEAPEND:
printf( "OK - end of heap\n" );
break;
case _HEAPEMPTY:
printf( "OK - heap is empty\n" );
break;
case _HEAPBADBEGIN:
printf( "ERROR - heap is damaged\n" );
break;
case _HEAPBADPTR:
printf( "ERROR - bad pointer to heap\n" );
break;
case _HEAPBADNODE:
printf( "ERROR - bad node in heap\n" );
}
}
/* ----------------------------------------------------------------------------------
*/
#define NUM_BLOCKS 20

void main()
{
int i, j;
void *temp;
void *pp[ NUM_BLOCKS ];
void *qq[ NUM_BLOCKS ];

memset( pp, 0, sizeof(pp) );
memset( qq, 0, sizeof(qq) );

// Alloc a large block, free it, and call _heapenable() to force all
OS mem requests to fail
#if 0
if ( (pp[0] = malloc( 400000000 )) == NULL ) {
printf( "error in initial large blk\n" );
} else {
free( pp[0] );
}
_heapenable(false);
#endif
heap_dump( "Heap:", 1 );

for ( i = 0; i < NUM_BLOCKS; ++i ) {
if ( (pp[i] = malloc( 100000000 )) == NULL ) {
printf( "error in malloc blk %d\n", i );
break;
}
if ( (qq[i] = new char[ 100000000 ]) == NULL ) {
printf( "error in new blk %d\n", i );
break;
}
}
if ( (temp = malloc( 1000000 )) == NULL ) {
printf( "error in malloc tamp\n" );
}
for ( j = 0; j < i; ++j ) {
if ( pp[j] ) {
free( pp[j] );
}
if ( qq[j] ) {
delete [] qq[j];
}
}
heap_dump( "Heap:", 1 );

if ( (pp[0] = malloc( 800000000 )) == NULL ) {
printf( "error in large blk\n" );
} else {
free( pp[0] );
}
heap_dump( "Heap:", 1 );

_heapshrink();
heap_dump( "Heap:", 1 );

}
/* ------------------------------------------------------------------------------------------------------------------------------
*/

******** ptr32.cpp ********************
// wcl386 -d2 -w4 -zq ptr32

#include <stdio.h>
#include <assert.h>
#include <stddef.h>


int calc( char *fi, char *fo )
{
ptrdiff_t size; // May be negative
size_t capacity = 256;

if ( fo > fi ) {
printf( "fo > fi\n" );
} else if ( fo == fi ) {
printf( "fo == fi\n" );
} else {
printf( "fo < fi\n" );
}
if ( (size = fi - fo) < 0 ) {
size += capacity;
}
printf( "bytes in fifo: %d\n", size );
return( size );
}

void main()
{
char *fi;
char *fo;

// Note: 'up to' doesn't include the end limit

// From 0x7FFFFFF0 up to 0x800000F0
// Empty ==========================
fo = (char*)0x7FFFFFF0;
fi = (char*)0x7FFFFFF0;
assert( calc( fi, fo ) == 0 );

// 18 bytes
fo = (char*)0x7FFFFFF0;
fi = (char*)0x80000002;
assert( calc( fi, fo ) == 18);

// 18 bytes
fo = (char*)0x80000000;
fi = (char*)0x80000012;
assert( calc( fi, fo ) == 18);

// 2 bytes
fo = (char*)0x800000EF;
fi = (char*)0x7FFFFFF1;
assert( calc( fi, fo ) == 2);

// 16 bytes
fo = (char*)0x800000EF;
fi = (char*)0x7FFFFFFF;
assert( calc( fi, fo ) == 16);

// 18 bytes
fo = (char*)0x800000EF;
fi = (char*)0x80000001;
assert( calc( fi, fo ) == 18);


// From 0x80000000 up to 0x80000100
// Empty ==========================
fo = (char*)0x80000000;
fi = (char*)0x80000000;
assert( calc( fi, fo ) == 0);

// 1 byte
fo = (char*)0x80000000;
fi = (char*)0x80000001;
assert( calc( fi, fo ) == 1);

// 1 byte
fo = (char*)0x800000FF;
fi = (char*)0x80000000;
assert( calc( fi, fo ) == 1);
}
Ricardo E. Gayoso
2013-05-10 21:23:51 UTC
Permalink
This post might be inappropriate. Click to display it.
Loading...