@ -97,24 +97,14 @@ crc32_generic(const uint8_t *buf, size_t size, uint32_t crc)
// If both the generic and arch-optimized implementations are built, then
// the function to use is selected at runtime because the system running
// the binary might not have the arch-specific instruction set extension(s)
// available. The three dispatch methods in order of priority:
// available. The dispatch methods in order of priority:
//
// 1. Indirect function (ifunc). This method is slightly more efficient
// than the constructor method because it will change the entry in the
// Procedure Linkage Table (PLT) for the function either at load time or
// at the first call. This avoids having to call the function through a
// function pointer and will treat the function call like a regular call
// through the PLT. ifuncs are created by using
// __attribute__((__ifunc__("resolver"))) on a function which has no
// body. The "resolver" is the name of the function that chooses at
// runtime which implementation to use.
//
// 2. Constructor. This method uses __attribute__((__constructor__)) to
// 1. Constructor. This method uses __attribute__((__constructor__)) to
// set crc32_func at load time. This avoids extra computation (and any
// unlikely threading bugs) on the first call to lzma_crc32() to decide
// which implementation should be used.
//
// 3 . First Call Resolution. On the very first call to lzma_crc32(), the
// 2. First Call Resolution. On the very first call to lzma_crc32(), the
// call will be directed to crc32_dispatch() instead. This will set the
// appropriate implementation function and will not be called again.
// This method does not use any kind of locking but is safe because if
@ -124,22 +114,7 @@ crc32_generic(const uint8_t *buf, size_t size, uint32_t crc)
typedef uint32_t ( * crc32_func_type ) (
const uint8_t * buf , size_t size , uint32_t crc ) ;
// Clang 16.0.0 and older has a bug where it marks the ifunc resolver
// function as unused since it is static and never used outside of
// __attribute__((__ifunc__())).
# if defined(CRC_USE_IFUNC) && defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
# endif
// This resolver is shared between all three dispatch methods. It serves as
// the ifunc resolver if ifunc is supported, otherwise it is called as a
// regular function by the constructor or first call resolution methods.
// The __no_profile_instrument_function__ attribute support is checked when
// determining if ifunc can be used, so it is safe to use here.
# ifdef CRC_USE_IFUNC
__attribute__ ( ( __no_profile_instrument_function__ ) )
# endif
// This resolver is shared between all dispatch methods.
static crc32_func_type
crc32_resolve ( void )
{
@ -147,11 +122,6 @@ crc32_resolve(void)
? & crc32_arch_optimized : & crc32_generic ;
}
# if defined(CRC_USE_IFUNC) && defined(__clang__)
# pragma GCC diagnostic pop
# endif
# ifndef CRC_USE_IFUNC
# ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
// Constructor method.
@ -176,8 +146,7 @@ crc32_set_func(void)
static uint32_t
crc32_dispatch ( const uint8_t * buf , size_t size , uint32_t crc )
{
// When __attribute__((__ifunc__(...))) and
// __attribute__((__constructor__)) isn't supported, set the
// When __attribute__((__constructor__)) isn't supported, set the
// function pointer without any locking. If multiple threads run
// the detection code in parallel, they will all end up setting
// the pointer to the same value. This avoids the use of
@ -189,14 +158,8 @@ crc32_dispatch(const uint8_t *buf, size_t size, uint32_t crc)
# endif
# endif
# endif
# ifdef CRC_USE_IFUNC
extern LZMA_API ( uint32_t )
lzma_crc32 ( const uint8_t * buf , size_t size , uint32_t crc )
__attribute__ ( ( __ifunc__ ( " crc32_resolve " ) ) ) ;
# else
extern LZMA_API ( uint32_t )
lzma_crc32 ( const uint8_t * buf , size_t size , uint32_t crc )
{
@ -239,4 +202,3 @@ lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
return crc32_generic ( buf , size , crc ) ;
# endif
}
# endif