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.

Summary

This is just a quick array to recall some of the specifics of the architectures found in the Debian project.

feature

alpha

arm

armel

armhf

arm64

avr32

hppa

*-i3861

?x32

*-amd642

ia64

m68k

mips

mipsel

mips64el

powerpc

ppc64

ppc64el

s390

s390x

sparc

sparc64

sh4

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

?

4

size of long

8

4

8

4

4

4

8

8

4

4

8

4

8

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

-

?

?

?

?

?

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

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

8

4

8

4

8

4

max alignment

8

4

8

?

?

?

?

8

?

8

?

?

8

?

?

?

?

?

?

?

4

unaligned access4

T

M/T

M

T

O

T

Y?

N

?

Y

Y

N

?

N

endian5

L

L

B

B

L

L

B

B

L

B

L

B

B

L

char

±

+

+

±

±

±

±

±

+

?

+

±

?

±

stack grows6

func param location7

R

R

?

?

S

R

R

S

R

?

R

R

R

R

?

R

func return ptr location8

R

R

?

?

S

R

S

R

?

R

R

?

?

R

?

R

page size(s)

8K

4K

4K, 64K

?

?

4K, 2M/4M

4K, 2M

?

4K

4K-64K

?

?

4K- 64K- 16M

4K

?

?

4k

float 9

?

S

H

?

?

?

H+

H

H

S?

?

?

?

?

?

H

?

?

?

?

double 9

?

S

H

?

?

?

H+

H

H

S?

?

?

?

?

?

H

?

?

?

?

long double 9

?

S

H

?

?

?

H10

H10

H

S?

?

?

?

?

?

H~

?

?

?

?

feature

alpha

arm

armel

armhf

arm64

avr32

hppa

*-i3861

?x32

*-amd642

ia64

m68k

mips

mipsel

mips64el

powerpc

ppc64

ppc64el

s390

s390x

sparc

sparc64

sh4

  1. i386, kfreebsd-i386, hurd-i386 (1 2)

  2. amd64, kfreebsd-amd64 (3 4)

  3. long double changed size from 8 to 16 in Lenny (5 6 7 8)

  4. 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)

  5. L for little endian,B for big endian (10)

  6. ↑ for growing up,↓ for growing down (11)

  7. R=registers,S=stack (12)

  8. R=register,S=stack (13)

  9. H=hard, S=soft, P=partial, +=excess precission, ~=not usual standard (14 15 16)

  10. Use 80bits extended precision see extended precision (17 18)

Alignment

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 (especially 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:

But:

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 (but not as much as with other architectures as done is hardware and not in software). 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()