• Masahiro Yamada's avatar
    types: use int-ll64 for both aarch32 and aarch64 · 0a2d5b43
    Masahiro Yamada authored
    Since commit 031dbb12
    
     ("AArch32: Add essential Arch helpers"),
    it is difficult to use consistent format strings for printf() family
    between aarch32 and aarch64.
    
    For example, uint64_t is defined as 'unsigned long long' for aarch32
    and as 'unsigned long' for aarch64.  Likewise, uintptr_t is defined
    as 'unsigned int' for aarch32, and as 'unsigned long' for aarch64.
    
    A problem typically arises when you use printf() in common code.
    
    One solution could be, to cast the arguments to a type long enough
    for both architectures.  For example, if 'val' is uint64_t type,
    like this:
    
      printf("val = %llx\n", (unsigned long long)val);
    
    Or, somebody may suggest to use a macro provided by <inttypes.h>,
    like this:
    
      printf("val = %" PRIx64 "\n", val);
    
    But, both would make the code ugly.
    
    The solution adopted in Linux kernel is to use the same typedefs for
    all architectures.  The fixed integer types in the kernel-space have
    been unified into int-ll64, like follows:
    
        typedef signed char           int8_t;
        typedef unsigned char         uint8_t;
    
        typedef signed short          int16_t;
        typedef unsigned short        uint16_t;
    
        typedef signed int            int32_t;
        typedef unsigned int          uint32_t;
    
        typedef signed long long      int64_t;
        typedef unsigned long long    uint64_t;
    
    [ Linux commit: 0c79a8e29b5fcbcbfd611daf9d500cfad8370fcf ]
    
    This gets along with the codebase shared between 32 bit and 64 bit,
    with the data model called ILP32, LP64, respectively.
    
    The width for primitive types is defined as follows:
    
                       ILP32           LP64
        int            32              32
        long           32              64
        long long      64              64
        pointer        32              64
    
    'long long' is 64 bit for both, so it is used for defining uint64_t.
    'long' has the same width as pointer, so for uintptr_t.
    
    We still need an ifdef conditional for (s)size_t.
    
    All 64 bit architectures use "unsigned long" size_t, and most 32 bit
    architectures use "unsigned int" size_t.  H8/300, S/390 are known as
    exceptions; they use "unsigned long" size_t despite their architecture
    is 32 bit.
    
    One idea for simplification might be to define size_t as 'unsigned long'
    across architectures, then forbid the use of "%z" string format.
    However, this would cause a distortion between size_t and sizeof()
    operator.  We have unknowledge about the native type of sizeof(), so
    we need a guess of it anyway.  I want the following formula to always
    return 1:
    
      __builtin_types_compatible_p(size_t, typeof(sizeof(int)))
    
    Fortunately, ARM is probably a majority case.  As far as I know, all
    32 bit ARM compilers use "unsigned int" size_t.
    Signed-off-by: default avatarMasahiro Yamada <yamada.masahiro@socionext.com>
    0a2d5b43
plat_common.c 2.53 KB