1. I've heard reads and writes of aligned int's are atomic and safe, I wonder when does the system make non malloc'd globals unaligned other than packed structures and casting/pointer arithmetic byte buffers?

  2. [X86-64 linux] In all of my normal cases, the system always chooses integer locations that don't get word torn, for example, two byte on one word and the other two bytes on the other word. Can any one post a program/snip (C or assembly) that forces the global variable to unaligned address such that the integer gets torn and the system has to use two reads to load one integer value ?

    When I print the below program, the addresses are close to each other such that multiple variables are within 64bits but never once word tearing is seen (smartness in the system or compiler ?)

    #include <stdio.h>
    int a;
    char  b;
    char c;
    int      d;
    int e = 0;
    int isaligned(void *p, int N)
        if (((int)p % N) == 0)
            return 1;
            return 0;
    int main()
        printf("processor is %d byte mode \n", sizeof(int *));
        printf ( "a=%p/b=%p/c=%p/d=%p/f=%p\n", &a, &b, &c, &d, &e );
        printf ( " check for 64bit alignment of test result of 0x80 = %d \n", isaligned( 0x80, 64 ));
        printf ( " check for 64bit alignment of a result = %d \n", isaligned( &a, 64 ));
        printf ( " check for 64bit alignment of d  result = %d \n", isaligned( &e, 64 ));
    return 0;}


    processor is 8 byte mode 
     check for 64bit alignment of test result of 0x80 = 1 
     check for 64bit alignment of a result = 0 
     check for 64bit alignment of d  result = 0 
  3. How does a read of a char happen in the above case ? Does it read from 8 byte aligned boundary (in my case 0x601030 ) and then go to 0x60103c ?

  4. Memory access granularity is always word size isn't it ?


  • You may find the alignof() operator an interesting addition to your test jig. You may find C99§6.2.8 an interesting read as well. – WhozCraig Jan 31 '13 at 23:01
  • Is there a problem you're trying to solve, or is this just curiosity? – Useless Jan 31 '13 at 23:01
  • @useless I am writing tests to break a multi threaded application. some use std::atomic <int> some dont. – resultsway Jan 31 '13 at 23:26
  • Well, that's one instruction then. – Mats Petersson Feb 1 '13 at 2:12

1) Yes, there is no guarantee that unaligned accesses are atomic, because [at least sometimes, on certain types of processors] the data may be written as two separate writes - for example if you cross over a memory page boundary [I'm not talking about 4KB pages for virtual memory, I'm talking about DDR2/3/4 pages, which is some fraction of the total memory size, typically 16Kbits times whatever the width is of the actual memory chip - which will vary depending on the memory stick itself]. Equally, on other processors than x86, you get a trap for reading unaligned memory, which would either cause the program to abort, or the read be emulated in software as multiple reads to "fix" the unaligned read.

2) You could always make an unaligned memory region by something like this:

char *ptr = malloc(sizeof(long long) * number+1);
long long *unaligned = (long long *)&ptr[2];

   temp = unaligned[i]; 

By the way, your alignment check checks if the address is aligned to 64 bytes, not 64 bits. You'll have to divide by 8 to check that it's aligned to 64 bits.

3) A char is a single byte read, and the address will be on the actual address of the byte itself. The actual memory read performed is probably for a full cache-line, starting at the target address, and then cycling around, so for example:

0x60103d is the target address, so the processor will read a cache line of 32 bytes, starting at the 64-bit word we want: 0x601038 (and as soon as that's completed the processor goes on to the next instruction - meanwhile the next read will be performed to fill the cacheline), then cacheline is filled with 0x601020, 0x601028, 0x601030. But should we turn the cache off [if you want your 3GHz latest x86 processor to be slightly slower than a 66MHz 486, disabling the cache is a good way to achieve that], the processor would just read one byte at 0x60103d.

4) Not on x86 processors, they have byte addressing - but for normal memory, reads are done on a cacheline basis, as explained above.

Note also that "may not be atomic" is not at all the same as "will not be atomic" - so you'll probably have a hard time making it go wrong by will - you really need to get all the timings of two different threads just right, and straddle cachelines, straddle memory page boundaries, and so on to make it go wrong - this will happen if you don't want it to happen, but trying to make it go wrong can be darn hard [trust me, I've been there, done that].

  • Thx, using packed I am able to align my int such that it over flows into the adjacent word boundary. How do I prove that it is takes more than one operation or just one in my system. – resultsway Feb 1 '13 at 1:46
  • Read the code from your compiler - but if it's x86_64, it will be one instruction! – Mats Petersson Feb 1 '13 at 2:00
  • main: .LFB2: pushq %rbp .LCFI0: movq %rsp, %rbp .LCFI1: subq $16, %rsp .LCFI2: movl $t+29, %ecx movl $t+28, %edx movl $t, %esi movl $.LC0, %edi movl $0, %eax call printf leave ret – resultsway Feb 1 '13 at 2:10
  • it is "movl $t+29, %ecx" – resultsway Feb 1 '13 at 2:11
  • That's nearly impossible to read, and I have no idea what your original code was, so it's hard to say what actually happens here. – Mats Petersson Feb 1 '13 at 2:11
  1. It probably doesn't, outside of those cases.

  2. In assembly it's trivial. Something like:

         .org 0x2
         .word SOME_NUMBER

    But on Intel, the processor can safely read unaligned memory. It might not be atomic, but that might not be apparent from the generated code.

  3. Intel, right? The Intel ISA has single-byte read/write opcodes. Disassemble your program and see what it's using.

  4. Not necessarily - you might have a mismatch between memory word size and processor word size.

  • The ARM7 processor may require 2 fetches for unaligned data, especially data spanning an alignment boundary. For example, reading an unaligned 32-bit integer would require 2 fetches: fetching the first n bytes and then the bytes that crossed the boundary. This basically slows your program by 50%. – Thomas Matthews Jan 31 '13 at 23:56
  • I thought ARM would trap on unaligned access? And then the trap handler may decide to "fix it up", but much more than 50% slowdown. – Mats Petersson Feb 1 '13 at 1:45

1) This answer is platform-specific. In general, though, the compiler will align variables unless you force it to do otherwise.

2) The following will require two reads to load one variable when run on a 32-bit CPU:

uint64_t huge_variable;

The variable is larger than a register, so it will require multiple operations to access. You can also do something similar by using packed structures:

struct unaligned __attribute__ ((packed))
    char buffer[2];
    int  unaligned;
    char buffer2[2];
} sample_struct;

3) This answer is platform-specific. Some platforms may behave like you describe. Some platforms have instructions capable of fetching a half-register or quarter-register of data. I recommend examining the assembly emitted by your compiler for more details (make sure you turn off all compiler optimizations first).

4) The C language allows you to access memory with byte-sized granularity. How this is implemented under the hood and how much data your CPU fetches to read a single byte is platform-specific. For many CPUs, this is the same as the size of a general-purpose register.

  1. The C standards guarantee that malloc(3) returns a memory area that complies to the strictest alignment requirements, so this just can't happen in that case. If there are unaligned data, it is probably read/written by pieces (that depends on the exact guarantees the architecture provides).
  2. On some architectures unaligned access is allowed, on others it is a fatal error. When allowed, it is normally much slower than aligned access; when not allowed the compiler must take the pieces and splice them together, and that is even much slower.
  3. Characters (really bytes) are normally allowed to have any byte address. The instructions working with bytes just get/store the individual byte in that case.
  4. No, memory access is according to the width of the data. But real memory access is in terms of cache lines (read up on CPU cache for this).

Non-aligned objects can never come into existence without you invoking undefined behavior. In other words, there is no sequence of actions, all having well-defined behavior, which a program can take that will result in a non-aligned pointer coming into existence. In particular, there is no portable way to get the compiler to give you misaligned objects. The closest thing is the "packed structure" many compilers have, but that only applies to structure members, not independent objects.

Further, there is no way to test alignedness in portable C. You can use the implementation-defined conversions of pointers to integers and inspect the low bits, but there is no fundamental requirement that "aligned" pointers have zeros in the low bits, or that the low bits after conversion to integer even correspond to the "least significant" bits of the pointer, whatever that would mean. In other words, conversions between pointers and integers are not required to commute with arithmetic operations.

If you really want to make some misaligned pointers, the easiest way to do it, assuming alignof(int)>1, is something like:

char buf[2*sizeof(int)+1];
int *p1 = (int *)buf, *p2 = (int *)(buf+sizeof(int)+1);

It's impossible for both buf and buf+sizeof(int)+1 to be simultaneously aligned for int if alignof(int) is greater than 1. Thus at least one of the two (int *) casts gets applied to a misaligned pointer, invoking undefined behavior, and the typical result is a misaligned pointer.

Your Answer

