Sie sind auf Seite 1von 5

64-Bit Insider

Volume I, Issue 2

Alignment in 64-bit Processors:


The 64-bit Advantage Part 2
The computer industry is chang-
ing, and 64-bit technology is the In the last issue of the 64-bit Insider newsletter, we de-
next, inevitable step. The 64-bit fined alignment and provided some examples of how data
Insider newsletter will help you
adopt this technology by provid- that was aligned on 32-bit processors could be unaligned
ing tips and tricks for a successful on 64-bit processors. In this issue, we continue our dis-
port. cussion of alignment and examine how offset assumptions
can become problematic when moving between architec-
64-bit development is not as com- tures.
plicated as the 16-bit to 32-bit
transition. However, as with any
new technology, there are several Hardcoding Structure Sizes in C++
areas that require close examina- In C++, a class type is associated with a vtable if the class
tion and consideration. The goal type contains one or more virtual functions or is derived
of the 64-bit Insider newsletter is from a class that contains one or more virtual functions. A
to identify potential migration
issues and provide viable, effec- pointer to this vtable is allocated along with the memory
tive solutions to these issues. With for any non-static member variables. On a 64-bit comput-
a plethora of Web sites already er, this vtable pointer is 64-bits long. Consequently, a
focused on 64-bit technology, the class without any member variables but with one virtual
intention of this newsletter is not function will be at least 8 bytes long.
to repeat previously published
information. Instead, it will focus
on 64-bit issues that are somewhat Note: On 64-bit platforms, a completely empty class and
isolated yet extremely important its alignment are both at least one byte in size.
to understand. It will also connect
you to reports and findings from
64-bit experts.

64-bit Insider Newsletter


Volume 1, Issue 2
Page 1/5
Miscalculating Offsets
When writing code to run on 64-bit processors, be careful to correctly specify the posi-
tion of a member within its enclosing type. The following code uses offsets to read the
contents from a list of mburst structures:

// Calculate total size of allocated bursts


int allocated_in_list(void *burst_list)
{
char* clist = (char*) list;
int size=0;
while(clist != NULL)
{
int* p = (int*)(clist+4); // find size member
size += *p; // sum size of burst
mburst** ppmburst =
(mburst**)(clist+12); // find next burst
clist = (char*) *ppmburst; // go to next burst
}
return size;
}
“When writing code to run on
While this code will work on 32-bit processors, it 64-bit processors, be careful
will fail when it runs on 64-bit processors. Similar to correctly specify the posi-
to the structure-size changes that occur on 64-bit tion of a member within its en-
processors, the offsets of individual members can closing type.”
change as well. Thus, you should not hardcode
these offsets.

If, however, you must access members of compound types in this way, use the macro
FIELD_OFFSET (type, member). This macro, which is implemented in the following
code, is used in C++ to query the offsets of fields within structures and classes.

// Calculate total size of allocated bursts


int allocated_in_list(void *burst_list)
{
char* clist = (char*) list;
int size=0;
while(clist != NULL)
{
int* p = (int*)(clist+
FIELD_OFFSET(mburst,size)); // find size member
size += *p; // sum size of burst
mburst** ppmburst =
(mburst**)(clist+
FIELD_OFFSET(mburst,next)); // find next burst
clist = (char*) *ppmburst; // go to next burst
}
return size;
}

64-bit Insider Newsletter


Volume 1, Issue 2
Page 2/5
Figure 1. 32-bit and 64-bit view of the mburst data structure

Custom Layouts
The most subtle result of the new alignment rules is that you must consider the effects of
how you write data to or read data from memory. The following function is used to se-
rialize mburst objects and writes a given list of mburst objects to a given buffer.

01: // Serialize the mburst list to the given buffer


02: // The buffer must be large enough to hold the list
03: char* serialize_bursts(char* buf, mburst* list)
04:{
05: while(list != NULL)
06: {
07: *((int*)buf) = list->seq_no;
08: buf += sizeof(int);
09: *((size_t*)buf) = list->size;
10: buf += sizeof(size_t);
11: buf = serialize_raw(buf, list->size, list->data);
12: list = list->next;
13: }
14: return buf;
15:}

This function is portable and does not make


assumptions regarding the size of members. “The most subtle result of the
Thus, one would expect that we could recon- new alignment rules is that you
struct the mburst objects by using the same must consider the effects of how
logic to write the de-serialize function— you write data to or read data
especially if we serialize and de-serialize on from memory.”
the same computer.

If we examine how this code will write or attempt to write the mburst object into the buf-
fer, we must first examine the diagram in Figure 1. Note that in the 64-bit drawing the
sizes of some fields have changed as expected. However, if you look closely at the offset
of the size field from the beginning of the structure, you will notice that this is an 8-byte
datatype that has written 4 bytes from the beginning of the buffer. As soon as you try to
write this size field to an area of memory that is not 8-byte aligned, the program will
throw an alignment fault exception at line 09.

There are several ways to avoid an alignment fault exception:


 Leave the size field where it is but change the code that writes to and reads
from it. This resolution conserves space in your buffer. Changing the code can be
done manually or through the compiler. If you let the compiler fix the alignment
issue replace line 09 with the following two lines of code:

UNALIGNED size_t* p = (size_t*)buf;


*p = list->size;

64-bit Insider Newsletter


Volume 1, Issue 2
Page 3/5
The UNALIGNED macro expands to the __unaligned keyword on 64-bit plat-
forms and tells the compiler to access unaligned size_t values through this poin-
ter. The compiler creates fix-up code accordingly. Note that on 32-bit processors,
it expands to nothing.

 Add your own padding to the serialized data. This resolution ensures that the
buffer is always 8-byte aligned. And while padding increases the use of space, it
eliminates alignment faults.

 Have the OS handle the alignment exception. This resolution can be used if you
are writing code intended for the Itanium architecture and is executed by using the
system call SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT). This method
is the simplest but slowest way to deal with misaligned data.

Packing
Packing is the mechanism that C and C++ programmers use to
override the rules that the compiler uses to lay out structures in
memory. Be careful when using this mechanism because the com-
piler’s rules are there for a reason, and the processor does not want
these rules to be bent or broken. Therefore, the compiler will gen-
erate extra code when building the object code, inserting instruc-
tions to prevent misaligned data from causing an exception in the
processor. This extra code will affect performance, however, so
use it with care in code that is performance sensitive.

In the Microsoft® Visual C++® development system, there are several mechanisms for
modifying the packing rules used by the compiler.

 /Zp. A compile-time flag that will modify the packing rules for an entire compila-
tion unit (including header files)
 pack(). A compiler pragma directive that can control the packing for a section of
code
 __declspec. A keyword that can be used to control the alignment of specific vari-
able declarations.

For more information about how to use these mechanisms, please see the documentation
for Visual C++.

Alignment Exceptions
Alignment exceptions can occur in any processor when data is written to or read from a
location in memory that is not appropriate for the alignment size of the data. However,
each processor may handle it in a different way.

On x86 processors, the exception never makes it to user code. Instead, when misaligned
data is read or written, the processor makes the necessary adjustments to complete the

64-bit Insider Newsletter


Volume 1, Issue 2
Page 4/5
operation, even though it may require some extra clock
cycles. This impact on performance is very minor because
the x86 processors are not optimized as much as modern “Alignment exceptions can occur
64-bit processors to improve access to aligned data. in any processor when data is
written to or read from a loca-
On x64 processors, an identical process occurs, however; tion in memory that is not appro-
the performance degradation is much more noticeable. priate for the alignment size of
the data.”
On the EM64T processor, it is possible to configure the
processor to pass the exceptions up to user code. The abili-
ty to enable these exceptions can be very useful for finding
areas of your code where misaligned data is affecting performance.

On the IA-64 processor, the exception is always passed up to user code and causes the
application to crash if the exception is not handled.

Summary
For performance reasons, processors prefer data to be aligned to certain boundaries in
memory. Misaligned data can cause degradation in performance or even result in your
application crashing. On 64-bit processors the alignment rules change. This change can
cause either abrupt crashes in your code or performance degradation. The crashes can be
due to bugs related to assumptions in your code about the layout of memory or due to the
new alignment exceptions.

Recommended Reading

Larry Osterman’s Weblog: Alignment (part 1)


http://blogs.msdn.com/larryosterman/archive/2005/04/07/406252.aspx

Intel article: Data Alignment when Migrating to 64-bit Architecture


http://www.intel.com/cd/ids/developer/asmo-na/eng/170533.htm

Microsoft Visual Studio technical article: Windows Data Alignment on IPF, x86, and x86-
64
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/dv_vstechart/html/vcconWindowsDataAlignmentOnIPFX86X86-64.asp

64-bit Insider Newsletter


Volume 1, Issue 2
Page 5/5

Das könnte Ihnen auch gefallen