064360e667
libgcc for boot environment isn't always present and compatible. libgcc is often absent if endianness or bit-size at boot is different from running OS. libgcc may use optimised opcodes that aren't available on boot time. So instead of relying on libgcc shipped with the compiler, supply the functions in GRUB directly. Tests are present to ensure that those replacement functions behave the way compiler expects them to.
404 lines
7.4 KiB
C
404 lines
7.4 KiB
C
/* compiler-rt.c - compiler helpers. */
|
|
/*
|
|
* GRUB -- GRand Unified Bootloader
|
|
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010-2014 Free Software Foundation, Inc.
|
|
*
|
|
* GRUB is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GRUB is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <grub/misc.h>
|
|
#include <grub/compiler-rt.h>
|
|
|
|
#ifndef GRUB_EMBED_DECOMPRESSOR
|
|
void * GRUB_BUILTIN_ATTR
|
|
memcpy (void *dest, const void *src, grub_size_t n)
|
|
{
|
|
return grub_memmove (dest, src, n);
|
|
}
|
|
void * GRUB_BUILTIN_ATTR
|
|
memmove (void *dest, const void *src, grub_size_t n)
|
|
{
|
|
return grub_memmove (dest, src, n);
|
|
}
|
|
int GRUB_BUILTIN_ATTR
|
|
memcmp (const void *s1, const void *s2, grub_size_t n)
|
|
{
|
|
return grub_memcmp (s1, s2, n);
|
|
}
|
|
void * GRUB_BUILTIN_ATTR
|
|
memset (void *s, int c, grub_size_t n)
|
|
{
|
|
return grub_memset (s, c, n);
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
|
|
void GRUB_BUILTIN_ATTR
|
|
__bzero (void *s, grub_size_t n)
|
|
{
|
|
grub_memset (s, 0, n);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if GRUB_DIVISION_IN_SOFTWARE
|
|
|
|
grub_uint32_t
|
|
__udivsi3 (grub_uint32_t a, grub_uint32_t b)
|
|
{
|
|
return grub_divmod64 (a, b, 0);
|
|
}
|
|
|
|
grub_int32_t
|
|
__divsi3 (grub_int32_t a, grub_int32_t b)
|
|
{
|
|
return grub_divmod64s (a, b, 0);
|
|
}
|
|
|
|
grub_uint32_t
|
|
__umodsi3 (grub_uint32_t a, grub_uint32_t b)
|
|
{
|
|
grub_uint64_t ret;
|
|
grub_divmod64 (a, b, &ret);
|
|
return ret;
|
|
}
|
|
|
|
grub_int32_t
|
|
__modsi3 (grub_int32_t a, grub_int32_t b)
|
|
{
|
|
grub_int64_t ret;
|
|
grub_divmod64s (a, b, &ret);
|
|
return ret;
|
|
}
|
|
|
|
grub_uint64_t
|
|
__udivdi3 (grub_uint64_t a, grub_uint64_t b)
|
|
{
|
|
return grub_divmod64 (a, b, 0);
|
|
}
|
|
|
|
grub_uint64_t
|
|
__umoddi3 (grub_uint64_t a, grub_uint64_t b)
|
|
{
|
|
grub_uint64_t ret;
|
|
grub_divmod64 (a, b, &ret);
|
|
return ret;
|
|
}
|
|
|
|
grub_int64_t
|
|
__divdi3 (grub_int64_t a, grub_int64_t b)
|
|
{
|
|
return grub_divmod64s (a, b, 0);
|
|
}
|
|
|
|
grub_int64_t
|
|
__moddi3 (grub_int64_t a, grub_int64_t b)
|
|
{
|
|
grub_int64_t ret;
|
|
grub_divmod64s (a, b, &ret);
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef NEED_CTZDI2
|
|
|
|
unsigned
|
|
__ctzdi2 (grub_uint64_t x)
|
|
{
|
|
unsigned ret = 0;
|
|
if (!x)
|
|
return 64;
|
|
if (!(x & 0xffffffff))
|
|
{
|
|
x >>= 32;
|
|
ret |= 32;
|
|
}
|
|
if (!(x & 0xffff))
|
|
{
|
|
x >>= 16;
|
|
ret |= 16;
|
|
}
|
|
if (!(x & 0xff))
|
|
{
|
|
x >>= 8;
|
|
ret |= 8;
|
|
}
|
|
if (!(x & 0xf))
|
|
{
|
|
x >>= 4;
|
|
ret |= 4;
|
|
}
|
|
if (!(x & 0x3))
|
|
{
|
|
x >>= 2;
|
|
ret |= 2;
|
|
}
|
|
if (!(x & 0x1))
|
|
{
|
|
x >>= 1;
|
|
ret |= 1;
|
|
}
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef NEED_CTZSI2
|
|
unsigned
|
|
__ctzsi2 (grub_uint32_t x)
|
|
{
|
|
unsigned ret = 0;
|
|
if (!x)
|
|
return 32;
|
|
|
|
if (!(x & 0xffff))
|
|
{
|
|
x >>= 16;
|
|
ret |= 16;
|
|
}
|
|
if (!(x & 0xff))
|
|
{
|
|
x >>= 8;
|
|
ret |= 8;
|
|
}
|
|
if (!(x & 0xf))
|
|
{
|
|
x >>= 4;
|
|
ret |= 4;
|
|
}
|
|
if (!(x & 0x3))
|
|
{
|
|
x >>= 2;
|
|
ret |= 2;
|
|
}
|
|
if (!(x & 0x1))
|
|
{
|
|
x >>= 1;
|
|
ret |= 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if defined (__clang__) && !defined(GRUB_EMBED_DECOMPRESSOR)
|
|
/* clang emits references to abort(). */
|
|
void __attribute__ ((noreturn))
|
|
abort (void)
|
|
{
|
|
grub_fatal ("compiler abort");
|
|
}
|
|
#endif
|
|
|
|
#if (defined (__MINGW32__) || defined (__CYGWIN__))
|
|
void __register_frame_info (void)
|
|
{
|
|
}
|
|
|
|
void __deregister_frame_info (void)
|
|
{
|
|
}
|
|
|
|
void ___chkstk_ms (void)
|
|
{
|
|
}
|
|
|
|
void __chkstk_ms (void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
union component64
|
|
{
|
|
grub_uint64_t full;
|
|
struct
|
|
{
|
|
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
|
grub_uint32_t high;
|
|
grub_uint32_t low;
|
|
#else
|
|
grub_uint32_t low;
|
|
grub_uint32_t high;
|
|
#endif
|
|
};
|
|
};
|
|
|
|
#if defined (__powerpc__) || defined (__arm__) || defined(__mips__)
|
|
|
|
/* Based on libgcc2.c from gcc suite. */
|
|
grub_uint64_t
|
|
__lshrdi3 (grub_uint64_t u, int b)
|
|
{
|
|
if (b == 0)
|
|
return u;
|
|
|
|
const union component64 uu = {.full = u};
|
|
const int bm = 32 - b;
|
|
union component64 w;
|
|
|
|
if (bm <= 0)
|
|
{
|
|
w.high = 0;
|
|
w.low = (grub_uint32_t) uu.high >> -bm;
|
|
}
|
|
else
|
|
{
|
|
const grub_uint32_t carries = (grub_uint32_t) uu.high << bm;
|
|
|
|
w.high = (grub_uint32_t) uu.high >> b;
|
|
w.low = ((grub_uint32_t) uu.low >> b) | carries;
|
|
}
|
|
|
|
return w.full;
|
|
}
|
|
|
|
/* Based on libgcc2.c from gcc suite. */
|
|
grub_uint64_t
|
|
__ashrdi3 (grub_uint64_t u, int b)
|
|
{
|
|
if (b == 0)
|
|
return u;
|
|
|
|
const union component64 uu = {.full = u};
|
|
const int bm = 32 - b;
|
|
union component64 w;
|
|
|
|
if (bm <= 0)
|
|
{
|
|
/* w.high = 1..1 or 0..0 */
|
|
w.high = ((grub_int32_t) uu.high) >> (32 - 1);
|
|
w.low = ((grub_int32_t) uu.high) >> -bm;
|
|
}
|
|
else
|
|
{
|
|
const grub_uint32_t carries = ((grub_uint32_t) uu.high) << bm;
|
|
|
|
w.high = ((grub_int32_t) uu.high) >> b;
|
|
w.low = ((grub_uint32_t) uu.low >> b) | carries;
|
|
}
|
|
|
|
return w.full;
|
|
}
|
|
|
|
/* Based on libgcc2.c from gcc suite. */
|
|
grub_uint64_t
|
|
__ashldi3 (grub_uint64_t u, int b)
|
|
{
|
|
if (b == 0)
|
|
return u;
|
|
|
|
const union component64 uu = {.full = u};
|
|
const int bm = 32 - b;
|
|
union component64 w;
|
|
|
|
if (bm <= 0)
|
|
{
|
|
w.low = 0;
|
|
w.high = (grub_uint32_t) uu.low << -bm;
|
|
}
|
|
else
|
|
{
|
|
const grub_uint32_t carries = (grub_uint32_t) uu.low >> bm;
|
|
|
|
w.low = (grub_uint32_t) uu.low << b;
|
|
w.high = ((grub_uint32_t) uu.high << b) | carries;
|
|
}
|
|
|
|
return w.full;
|
|
}
|
|
|
|
/* Based on libgcc2.c from gcc suite. */
|
|
int
|
|
__ucmpdi2 (grub_uint64_t a, grub_uint64_t b)
|
|
{
|
|
union component64 ac, bc;
|
|
ac.full = a;
|
|
bc.full = b;
|
|
|
|
if (ac.high < bc.high)
|
|
return 0;
|
|
else if (ac.high > bc.high)
|
|
return 2;
|
|
|
|
if (ac.low < bc.low)
|
|
return 0;
|
|
else if (ac.low > bc.low)
|
|
return 2;
|
|
return 1;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined (__powerpc__) || defined(__mips__) || defined(__sparc__) || defined(__arm__)
|
|
|
|
/* Based on libgcc2.c from gcc suite. */
|
|
grub_uint32_t
|
|
__bswapsi2 (grub_uint32_t u)
|
|
{
|
|
return ((((u) & 0xff000000) >> 24)
|
|
| (((u) & 0x00ff0000) >> 8)
|
|
| (((u) & 0x0000ff00) << 8)
|
|
| (((u) & 0x000000ff) << 24));
|
|
}
|
|
|
|
/* Based on libgcc2.c from gcc suite. */
|
|
grub_uint64_t
|
|
__bswapdi2 (grub_uint64_t u)
|
|
{
|
|
return ((((u) & 0xff00000000000000ull) >> 56)
|
|
| (((u) & 0x00ff000000000000ull) >> 40)
|
|
| (((u) & 0x0000ff0000000000ull) >> 24)
|
|
| (((u) & 0x000000ff00000000ull) >> 8)
|
|
| (((u) & 0x00000000ff000000ull) << 8)
|
|
| (((u) & 0x0000000000ff0000ull) << 24)
|
|
| (((u) & 0x000000000000ff00ull) << 40)
|
|
| (((u) & 0x00000000000000ffull) << 56));
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
#ifdef __arm__
|
|
grub_uint32_t
|
|
__aeabi_uidiv (grub_uint32_t a, grub_uint32_t b)
|
|
__attribute__ ((alias ("__udivsi3")));
|
|
grub_int32_t
|
|
__aeabi_idiv (grub_int32_t a, grub_int32_t b)
|
|
__attribute__ ((alias ("__divsi3")));
|
|
void *__aeabi_memcpy (void *dest, const void *src, grub_size_t n)
|
|
__attribute__ ((alias ("grub_memcpy")));
|
|
void *__aeabi_memset (void *s, int c, grub_size_t n)
|
|
__attribute__ ((alias ("memset")));
|
|
|
|
int
|
|
__aeabi_ulcmp (grub_uint64_t a, grub_uint64_t b)
|
|
{
|
|
return __ucmpdi2 (a, b) - 1;
|
|
}
|
|
|
|
grub_uint64_t
|
|
__aeabi_lasr (grub_uint64_t u, int b)
|
|
__attribute__ ((alias ("__ashrdi3")));
|
|
grub_uint64_t
|
|
__aeabi_llsr (grub_uint64_t u, int b)
|
|
__attribute__ ((alias ("__lshrdi3")));
|
|
|
|
grub_uint64_t
|
|
__aeabi_llsl (grub_uint64_t u, int b)
|
|
__attribute__ ((alias ("__ashldi3")));
|
|
|
|
#endif
|