2

In Computer Systems: a Programmer's Perspective,

Alignment is enforced by making sure that every data type is organized and allocated in such a way that every object within the type satisfies its alignment restrictions. The compiler places directives in the assembly code indicating the desired alignment for global data. For example, the assembly-code declaration of the jump table on page 271 contains the following directive on line 2:

.align 8

This ensures that the data following it (in this case the start of the jump table) will start with an address that is a multiple of 8. Since each table entry is 8 bytes long, the successive elements will obey the 8-byte alignment restriction.

I think that alignment is enforced by computer automatically. If a compiler can also enforce alignment by the directive in assembly, how do the two ways of enforcing alignment work together and what is the priority between them?

Does "every object within the type" mean "every object having the type", or "every element in the type (when it is a structure type or an array type)"?

Thanks.

4
  • 1
    what do you mean alignment would be enforced by the computer automatically? An instruction being used for a non-aligned read or write could at most trigger an interrupt at runtime. But the section you've quoted is about the data section which is mapped directly into memory.
    – amon
    Commented Oct 9, 2020 at 17:04
  • I might be wrong. What enforces alignment? Can a computer run a non-aligned program in assembly or machine language? Is alignment enforced only by compiler from C to assembly? What do you mean by "An instruction being used for a non-aligned read or write could at most trigger an interrupt at runtime. But the section you've quoted is about the data section which is mapped directly into memory"?
    – Tim
    Commented Oct 9, 2020 at 17:36
  • 1
    Some CPU architectures (ARM, not x86) impose a requirement (a need) that multi-byte memory accesses to be aligned to their multi-byte boundary. The consequence of running a program that violates this imposed requirement is that an invalid memory access exception will be generated and the program is terminated. The compiler fulfills that requirement by using an algorithm to compute (generate) the alignment and padding for each member of a composite data structure or data record. I hope that this clarification of the word "requirement" would have answered your question.
    – rwong
    Commented Oct 10, 2020 at 11:46
  • 1
    Message to moderators ... I appreciate the effort that answerers put into Tim's question - this seems like a collaboration to help improve the wording and the pedagogy for the computer science text books, making them suitable and unambiguous for self-learners. I hope that there is an organized effort to preserve the answers, that these effort do not go into the trash bin in case the question was deleted. I believe the best place for such collaboration is the Wikibooks project. Let's start organizing before questions like these are deleted.
    – rwong
    Commented Oct 10, 2020 at 11:52

1 Answer 1

6

Computer memory does not care about types, but does care about word size. A word consists of multiple bytes. The CPU's instruction set has instructions for reading or writing (or atomically modifying) a word of memory, but not all addresses can be used for such instructions: the pointer used for such instructions must be suitably aligned. Which alignments are allowed depends on the exact instruction set.

An address is n-byte aligned if the address is a multiple of n. Equivalently, the last log(n) bits in the address should be zero.

Assuming a word size of 8 and an alignment of n=8, here are some memory addresses of which some are aligned:

  0               1                 addr aligned
  0123456789ABCDEF0123456789ABCDEF

1         XXXXXXXX                  0x08 yes
2          XXXXXXXX                 0x09 no
3              XXXXXXXX             0x0D no
4                XXXXXXXX           0x0F no
5                 XXXXXXXX          0x10 yes
6                  XXXXXXXX         0x11 no

In pseudo-assembly notation, mov eax, [10H] would be an aligned access, but mov eax, [11H] would not be.

We want any accesses to variables to be aligned. For example, stacks are usually aligned to 16 bytes, and on Linux the malloc() function typically returns word-aligned pointers. But we want global variables to be aligned as well.

The layout of global variables is not decided at run time through assembly instructions, but is largely determined at compile time by creating a data segment in the executable. This data segment is then copied verbatim into memory.

For example, we might want to have two initialized variables: a zero-terminated string "Hello" and an 8-byte number with value 5. Even if we start at an aligned address, not all variables will end up being aligned:

  0               1                addr
  0123456789ABCDEF0123456789ABCDEF

          Hello0                   0x08
                50000000           0x0E !!!

So instead, the compiler or assembler must insert padding so that the variable is aligned (= can be accessed with an aligned memory access):

  0               1                addr
  0123456789ABCDEF0123456789ABCDEF

          Hello0                   0x08
                --                      unused bytes as padding
                  50000000         0x10

So in summary: the .align 8 directive tells the assembler to insert padding so that all variables/objects have aligned addresses. This allows them to be accessed via aligned memory addresses. The compile-time layout and the run-time accesses don't have precedence over each other, but they work together.


Types are sometimes viewed as sets, where the members of the set are instances of the type. Thus, the term “every object within the type” talks about objects that have a type. However, variables within an object also need alignment. So the compiler will also insert padding as needed between members of a structure and at the end of the structure. The result is that this structure will likely have sizeof(struct T) == 24:

struct T {
  bool x;   /* 1 byte */
            /* 7 byte inserted padding for size_t */
  size_t y; /* 8 byte */
  bool z;   /* 1 byte */
            /* 7 byte inserted padding for struct T */
};
1
  • 1
    Note that a C compiler can also be instructed by hints (directives added to the structure declaration), saying that the strict order of members is nor required, so it could reorder them by placing first the members with the largest alignement before placing others (possibly filling padding gaps left between members with larger alignment) So that structure could be compiled as if it was: ` struct /*compacting directive here*/ T { size_t y; (8 byte) bool x; (1 byte) bool z; (1 byte) (6 byte inserted padding for struct T) };` Commented Oct 10, 2020 at 17:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.