Live data from Hacker News

A bug story: data alignment on x86

pzemtsov.github.io

71–80 of 111 posts

Re: A bug story: data alignment on x86

#71
post #70

Earlier quoted context omitted.

This is documented as not working[1] in all but the most recent GCC versions. E.g. gcc-5.4 documents: > "The aligned attribute can only increase the alignment; but you can decrease it by specifying packed as well. See below." but gcc-6.2 documentation adds: > "When used as part of a typedef, the aligned attribute can both increase and decrease alignment, and specifying the packed attribute generates a warning." FWIW,…

Must have been supported for a while because this stuff is even used in Linux: #define __packed2__ __attribute__((packed, aligned(2))) /* * SystemV FS comes in two variants: * sysv2: System V Release 2 (e.g. Microport), structure elements aligned(2). * sysv4: System V Release 4 (e.g. Consensys), structure elements aligned(4). */ struct sysv2_super_block { __fs16 s_isize; /* index of first data zone */ __fs32 s_fsize…

Note the use of `packed`. `packed` causes the alignment to be set as small as possible (1 byte). The aligned(2) that follows then increases the alignment from 1 byte to 2 bytes.

Re: A bug story: data alignment on x86

#72
post #69

Note that even if you try to manually correct the pointer to work on aligned data (read any initial bytes via char pointer and read the rest via uint32_t pointer), you still generally have undefined behavior: strict-aliasing violation. And the worst thing here is that whether you do have a violation depends on how other code accesses the same data / how the object is initially declared. E.g., you're fine if the origi…

For what it's worth, people like Linus seem to despise the strict aliasing optimization. https://lkml.org/lkml/2003/2/26/158

Re: A bug story: data alignment on x86

#73
post #71
post #70

Earlier quoted context omitted.

Must have been supported for a while because this stuff is even used in Linux: #define __packed2__ __attribute__((packed, aligned(2))) /* * SystemV FS comes in two variants: * sysv2: System V Release 2 (e.g. Microport), structure elements aligned(2). * sysv4: System V Release 4 (e.g. Consensys), structure elements aligned(4). */ struct sysv2_super_block { __fs16 s_isize; /* index of first data zone */ __fs32 s_fsize…

Note the use of `packed`. `packed` causes the alignment to be set as small as possible (1 byte). The aligned(2) that follows then increases the alignment from 1 byte to 2 bytes.

Yeah, you're right. Add packed then if you want but I swear the code I posted works on 5.4 as it is.

Re: A bug story: data alignment on x86

#74
post #67
post #32

Earlier quoted context omitted.

Have you actually tried and verified that? Reading the docs I've had an impression that it says that the "aligned" is for the alignment inside of the structures , and you here declare the simple type?

I wouldn't have posted this without checking. And as far as documentation goes, they say this attribute applies to "types" and the example they give is struct S { short f[3]; } __attribute__ ((aligned (8))); where it actually is used outside of a struct so that this whole 6B thing is aligned to 8B instead of the default 2B.

Thanks! Are you able to post how the generated asm of their innermost loop looks like with SSE2 turned on? I mean the equivalent of theirs

    .L13:
         movdqa   (%r8), %xmm2
         ...

Re: A bug story: data alignment on x86

#75
post #69

Note that even if you try to manually correct the pointer to work on aligned data (read any initial bytes via char pointer and read the rest via uint32_t pointer), you still generally have undefined behavior: strict-aliasing violation. And the worst thing here is that whether you do have a violation depends on how other code accesses the same data / how the object is initially declared. E.g., you're fine if the origi…

Strict aliasing can worked around by casting through a union, essentially introducing a new type which can alias any of its component types. Mike Acton has a good description of it with lots of assembly examples here:

http://cellperformance.beyond3d.com/articles/2006/06/underst...

Re: A bug story: data alignment on x86

#76
post #74
post #67

Earlier quoted context omitted.

I wouldn't have posted this without checking. And as far as documentation goes, they say this attribute applies to "types" and the example they give is struct S { short f[3]; } __attribute__ ((aligned (8))); where it actually is used outside of a struct so that this whole 6B thing is aligned to 8B instead of the default 2B.

Thanks! Are you able to post how the generated asm of their innermost loop looks like with SSE2 turned on? I mean the equivalent of theirs .L13: movdqa (%r8), %xmm2 ...

movdqu, obviously. And the code is shorter now, I guess it drops this part responsible for processing the first 1~3 elements of the array to reach 16B alignment.

Re: A bug story: data alignment on x86

#77
post #39

Earlier quoted context omitted.

The correct and portable solution is to not use uint32_t, but to use uint8_t, and construct the integers manually.

Well, portable except for `uint8_t` not being guaranteed to exist. =)

It isn't?

At least that would be a failure at compile-time, rather than run-time.

Re: A bug story: data alignment on x86

#78

Compiler is allowed to assume alignment of pointers (what are you doing is creating a pointer to a value with invalid alignment, hence undefined behaviour (just creating a pointer is undefined behaviour)). The correct solution would be to read values indirectly. For example, a function like that could be used to replace every access to "q" variable. static uint32_t read(const char *p, size_t index) { uint32_t out; me…

Is this equivalent ? At least to me this seems a more common pattern than using memcpy(), and I expect to work better on old compilers.

  static uint32 read(const void *ptr) {
    const uint8 *b = (const uint8 *)ptr;
    return (b[3] 

Re: A bug story: data alignment on x86

#79
What if you put the array in a struct and made a union of both uint32_t and uint8_t? Would the union with the larger size force the compiler to generate a 4-byte aligned array for the bytes?

I suggest this because it would be portable without any compiler specific stuff.

Post reply on HN