Disclaimer: Whatever I suggested in my blog is what I would do, it does not necessarily mean the only way to do it.
AMD64 Memory Models
I recall the first production quality compiler I worked on was an 80286 in the mid 80's. Memory model such as "small", "medium" and "large" with common extended keywords "__far" and "__near" were popular with that 16-bit segmented memory architecure. Thereafter, 80386 "linearized" the address space with its 32-bit pointers and the model related terms simply became obsolete and disappeared.
It is interesting to see AMD64 ABI reintroduced the memory models to the x86 world, but this time with a 64-bit architecture. So why is there memory model in the x64 architecture? I would guess it is for performance's sake. The x64 architecture basically has only one instruction that truely loads a 64-bit address to register, namely "movabsq". All other memory related instructions contain only 4 bytes displacement which are then extended to 64-bit. If a greater that 32-bit address in the memory space is to be accessed, the compiler needs to load that "far" address with a movabsq instruction and then references it indirectly, which is not as efficient as a single, direct access. Hence the specified models of "small" and "kernel" in the x64 ABI assume certain address range limitation, so as to allow efficient memory access. "Medium" and "large" allows more flexibility with the address ranges in the expense of less efficient memory access.
To save time, let's talk about "small" and "medium" models only. "Small" being the default of most x64 compilers, is often mistaken to be equivalent to the defacto model in 32-bit x86, if there were one. I'm afraid the small model of x64 is actually smaller than the defacto 32-bit x86. We have encountered many people complaining their applications ran in 32-bit x86, but ran into linker's "address does not fit" error when ported to the default x64.
According to the AMD64 ABI, the small model allows a data address space of [-2^31, 2^31-1], with the linker limiting allocation of symbols between [0, 2^31-2^24-1]. What that means is
Effective address (i.e. offset+symbol at runtime) is limited to
[-2^31, 2^31-1]
If the "symbol" in offset+symbol is limited by the linker to
[0, 2^31-2^24-1]
The compiler can safely generate "offset" in the offset+symbol equation to
[-2^31, 2^24]
Note with the EA limitation, it means the upper 33 bits should be all 0s or all 1s to be valid, the ABI stated the linker must issue error otherwise. So only 31 bits are truely eligible for memory address computation in x64 small model, versus 32 bits in 32-bit x86, roughly half the space.
So what should be done when you have a linker "address does not fit" error? If changing source code is not an option, one option in Sun Studio 11 is to try the -xmodel=medium option.
In the recent x64 ABI, medium model is actually quite efficient. Not all static data are accessed with the "far" load 64-bit address followed by indirect reference. Medium model are now defined with extra data sections. Normally, there are the ".data", ".bss" etc data sections. Under medium model, data object larger than 65535 bytes are allocated in the corresponding ".ldata", ".lbss" data sections. Data in the "normal" data sections are referenced efficiently with direct access, whereas data in the ".l" data sections are referenced with the indirect access. What this means is performance hit may be minimized while data access range can be increased.
Posted at 09:57PM Jan 22, 2006 by alblog in Sun | Comments[0]
Today's Page Hits: 0