This page is a draft. Please help enhancing it by adding lines and filling tables. Comments at the bottom of the text are also welcome.
This is just a quick array to recall some of the specifics of the architectures found in the Debian project.
feature |
alpha |
arm |
avr32 |
hppa |
*-i3861 |
?x32 |
*-amd642 |
ia64 |
s390 |
s390x |
||||||||||
size of short |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
||||||||
size of int |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
||||||||
size of long |
8 |
4 |
8 |
4 |
4 |
4 |
8 |
8 |
4 |
4 |
8 |
4 |
4 |
8 |
4 |
4 |
||||
size of long long |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
||||||||
alignment of long long |
? |
8 |
4 |
- |
4 |
8 |
- |
? |
? |
? |
? |
? |
- |
? |
4 |
|||||
size of float |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
4 |
||||||||
size of double |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
8 |
||||||||
size of long double |
163 |
8 |
16 |
8 |
8 |
12 |
16 |
16 |
12 |
8 |
16 |
163 |
16 3 |
16 |
163 |
8 |
||||
alignment of long double |
? |
? |
8 |
? |
4 |
- |
4 |
16 |
? |
? |
? |
? |
? |
8 |
? |
4 |
||||
size of data pointer |
8 |
4 |
8 |
4 |
4 |
4 |
8 |
8 |
4 |
4 |
8 |
4 |
4 |
8 |
4 |
4 |
||||
max alignment |
8 |
4 |
8 |
? |
? |
? |
4(16) |
8 |
? |
8 |
? |
? |
8 |
? |
? |
? |
? |
? |
4 |
|
unaligned access OK4 |
N |
M/T |
M |
T |
O |
T |
Y? |
N |
? |
Y |
Y |
N |
N |
|||||||
endian5 |
L |
L |
B |
B |
L |
L |
B |
B |
L |
B |
B |
B |
L |
|||||||
char |
± |
+ |
+ |
± |
± |
± |
± |
± |
+ |
+ |
± |
± |
||||||||
stack grows6 |
↓ |
↓ |
↓ |
↑ |
↓ |
↓ |
↓ |
↓ |
↓ |
↓ |
↓ |
↓ |
||||||||
func param location |
regs |
regs |
? |
? |
stack |
regs |
regs |
stack |
regs |
? |
regs |
regs |
regs |
regs |
||||||
func return ptr location |
reg |
reg |
? |
? |
stack |
reg |
stack |
reg |
? |
reg |
? |
? |
reg |
reg |
||||||
page size(s) |
8K |
4K |
4K, 64K |
? |
? |
4K, 2M/4M |
4K, 2M |
? |
4K |
4K-64K |
? |
? |
4K |
? |
4k |
|||||
float 7 |
? |
S |
H |
? |
? |
? |
H+ |
H |
H |
S? |
? |
? |
? |
? |
? |
? |
? |
|||
double 7 |
? |
S |
H |
? |
? |
? |
H+ |
H |
H |
S? |
? |
? |
? |
? |
? |
? |
? |
|||
long double 7 |
? |
S |
H |
? |
? |
? |
H~ |
H |
H |
S? |
? |
? |
? |
? |
? |
? |
? |
|||
feature |
alpha |
arm |
avr32 |
hppa |
*-i3861 |
?x32 |
*-amd642 |
ia64 |
s390 |
s390x |
Y=Yes, O=Often generally ok but ma fail in some specific case, T=Traps may be fixed by kernel (super slow),M=Maybe generally not ok, N=No raise SIGBUS. See detail below (9)
L for little endian,B for big endian (10)
↑ for growing up,↓ for growing down (11)
H=hard, S=soft, P=partial, +=excess precission, ~=not usual standard (12 13 14)
Alignement
Note that there is alignment on the machine language level and alignment in C. Proper misalignment (for example in a packed struct) is no problem in C and allowed everywhere and the compiler will do the right thing (like translating a read of a variable to two loads at machine language level). On the other hand most of the constructs that lead to unaligned access not properly handled by the C compiler (especialy most constructs involving pointer casting) have undefined behaviour anyway, so compiling them with optimisation enabled can cause strange effects on all architectures.
alpha
Some alpha may emulate see kernel source
armel/armhf/arm64
High-level summary for software engineers: Don't do unaligned access. It's always inefficient, sometimes extremely inefficent, and in various cases is not permitted at all.
The short answer for the ARM case is that ARMv6 and up guarantee that the processor can be configured such that some unaligned accesses are fine (or at least just inefficient). Linux by default enable this mode and trap:
All <=32-bit load/store operations can be unaligned.
- NEON load-stores can be unaligned (unless an explicit alignment is specified in the encoding).
But:
- VFP load/stores must be naturally aligned.
Load-multiple/store-multiple and ldrd/strd do not work with <32-bit alignment, but can sometimes get fixed up by the kernel at a substantial performance penalty.
PUSH/POP usually requires 32-bit alignment, but then the ABI requires 64-bit alignment of the stack, so that is less of an issue.
Unaligned load-exclusive/store-exclusive operations are not supported.
No unaligned accesses are permitted to memory regions of Device or Strongly-ordered type. But some permutation of this will be true for most architectures, and in user-space this would only affect things prodding /dev/mem or otherwise mmaping from a device driver.
ARM64 similarly makes it possible to trap unaligned accesses, but if that is not enabled (which it isn't by Linux), everything apart from load-exclusive/store-exclusive, load-acquire/store-release and Device memory accesses will be handled by hardware.
avr32
Unaligned access is ok for 32bits word but not for 16bits or 64bits word see kernel source
i386/x32/amd64
Unaligned access is slower in recent processor. Moreover some MMX/SSE/vector operation need proper alignement.
ia64
Depending of config may fix with trap handler unaligned access
Floating point
First read academic paper about the pitfall of doing multi arch floating point computation and the classical "What Every Computer Scientist Should Know About Floating-Point Arithmetic" from here.
i386
i387 is a strange beast that suffer from excess precision. Moreover long double is only 80 bits
Internal computation are done with 80 bits of precision that lead to strange and not intuitive result.
C/C++ Preprocessor Symbols
Generally, GNU C tends to define the symbol
__arch__
A list of some common arch-specific symbols can be found on the Pre-defined Architecture Macros page.
Signedness
When programming in C, variables can be signed or unsigned.
Example:
unsigned char c; |
explicit unsigned, 0 <= c <= 255 |
signed char c; |
explicit signed, -128 <= c <= 127 |
char c; |
implicit (un)signedness, depending on architecture |
To force a signedness, either declare it explicitly or use the gcc command line option -f(un)signed-char. The gcc defaults differ only due to optimisation. Other compilers may not have this issue.
Obtaining this information
via a special tool
#include <alloca.h> #include <endian.h> #include <stddef.h> #include <stdio.h> static void test_size_align(const char *name, size_t size, size_t align) { printf("sizeof(%s) = %zu\n", name, size); if (size != align) printf("alignment(%s) = %zu\n", name, align); } #define TEST_SIZE_ALIGN(type, name) \ struct test_align_##name { char a; type b; }; \ test_size_align(#type, sizeof(type), offsetof(struct test_align_##name, b)) static void test_endian(void) { #if __BYTE_ORDER == __LITTLE_ENDIAN printf("byte order = little endian\n"); #elif __BYTE_ORDER == __BIG_ENDIAN printf("byte order = big endian\n"); #endif } static void test_char(void) { if ((int)(char)-1 == -1) printf("char signedness = signed\n"); else if ((int)(char)-1 == 255) printf("char signedness = unsigned\n"); } static void test_stack(void) { void *a = alloca(8); void *b = alloca(8); if (a > b) printf("stack = grows down\n"); else printf("stack = grows up\n"); } int main(void) { TEST_SIZE_ALIGN(short, short); TEST_SIZE_ALIGN(int, int); TEST_SIZE_ALIGN(long, long); TEST_SIZE_ALIGN(long long, long_long); TEST_SIZE_ALIGN(float, float); TEST_SIZE_ALIGN(double, double); TEST_SIZE_ALIGN(long double, long_double); TEST_SIZE_ALIGN(void *, pointer); test_endian(); test_char(); test_stack(); return 0; }
via autoconf
AC_INIT(archtest, 0.1) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(float) AC_CHECK_SIZEOF(double) AC_CHECK_SIZEOF(long double) AC_CHECK_SIZEOF(void*) AC_C_BIGENDIAN() AC_C_CHAR_UNSIGNED()