mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-26 20:09:02 +09:00
![Måns Rullgård](/assets/img/avatar_default.png)
A number of headers define functions as "extern inline" which is causing problems with gcc5. The reason is that starting with version 5.1, gcc defaults to the standard C99 semantics for the inline keyword. Under the traditional GNU inline semantics, an "extern inline" function would never create an external definition, the same as inline *without* extern in C99. In C99, and "extern inline" definition is simply an external definition with an inline hint. In short, the meanings of inline with and without extern are swapped between GNU and C99. The upshot is that all these definitions in header files create an external definition wherever those headers are included, resulting in multiple definition errors at link time. Changing all these functions to "static inline" fixes the problem since this works as desired in all gcc versions. Although the semantics are slightly different (a static inline definition may result in an actual function being emitted), it works as intended in practice. This patch also removes extern prototype declarations for the changed functions where they existed. Signed-off-by: Mans Rullgard <mans@mansr.com>
85 lines
2.2 KiB
C
85 lines
2.2 KiB
C
#ifndef _PPC_BYTEORDER_H
|
|
#define _PPC_BYTEORDER_H
|
|
|
|
#include <asm/types.h>
|
|
|
|
#ifdef __GNUC__
|
|
|
|
static __inline__ unsigned ld_le16(const volatile unsigned short *addr)
|
|
{
|
|
unsigned val;
|
|
|
|
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
|
|
return val;
|
|
}
|
|
|
|
static __inline__ void st_le16(volatile unsigned short *addr, const unsigned val)
|
|
{
|
|
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
|
|
}
|
|
|
|
static __inline__ unsigned ld_le32(const volatile unsigned *addr)
|
|
{
|
|
unsigned val;
|
|
|
|
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
|
|
return val;
|
|
}
|
|
|
|
static __inline__ void st_le32(volatile unsigned *addr, const unsigned val)
|
|
{
|
|
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
|
|
}
|
|
|
|
/* alas, egcs sounds like it has a bug in this code that doesn't use the
|
|
inline asm correctly, and can cause file corruption. Until I hear that
|
|
it's fixed, I can live without the extra speed. I hope. */
|
|
#if !(__GNUC__ >= 2 && __GNUC_MINOR__ >= 90)
|
|
#if 0
|
|
# define __arch_swab16(x) ld_le16(&x)
|
|
# define __arch_swab32(x) ld_le32(&x)
|
|
#else
|
|
static __inline__ __attribute__((const)) __u16 ___arch__swab16(__u16 value)
|
|
{
|
|
__u16 result;
|
|
|
|
__asm__("rlwimi %0,%1,8,16,23"
|
|
: "=r" (result)
|
|
: "r" (value), "0" (value >> 8));
|
|
return result;
|
|
}
|
|
|
|
static __inline__ __attribute__((const)) __u32 ___arch__swab32(__u32 value)
|
|
{
|
|
__u32 result;
|
|
|
|
__asm__("rlwimi %0,%1,24,16,23\n\t"
|
|
"rlwimi %0,%1,8,8,15\n\t"
|
|
"rlwimi %0,%1,24,0,7"
|
|
: "=r" (result)
|
|
: "r" (value), "0" (value >> 24));
|
|
return result;
|
|
}
|
|
#define __arch__swab32(x) ___arch__swab32(x)
|
|
#define __arch__swab16(x) ___arch__swab16(x)
|
|
#endif /* 0 */
|
|
|
|
#endif
|
|
|
|
/* The same, but returns converted value from the location pointer by addr. */
|
|
#define __arch__swab16p(addr) ld_le16(addr)
|
|
#define __arch__swab32p(addr) ld_le32(addr)
|
|
|
|
/* The same, but do the conversion in situ, ie. put the value back to addr. */
|
|
#define __arch__swab16s(addr) st_le16(addr,*addr)
|
|
#define __arch__swab32s(addr) st_le32(addr,*addr)
|
|
|
|
#endif /* __GNUC__ */
|
|
|
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
|
#define __BYTEORDER_HAS_U64__
|
|
#endif
|
|
#include <linux/byteorder/big_endian.h>
|
|
|
|
#endif /* _PPC_BYTEORDER_H */
|