Skip to content

Commit

Permalink
liblzma: Add ifunc implementation to crc64_fast.c.
Browse files Browse the repository at this point in the history
The ifunc method avoids indirection via the function pointer
crc64_func. This works on GNU/Linux and probably on FreeBSD too.
The previous __attribute((__constructor__)) method is kept for
compatibility with ELF platforms which do support ifunc.

The ifunc method has some limitations, for example, building
liblzma with -fsanitize=address will result in segfaults.
The configure option --disable-ifunc must be used for such builds.

Thanks to Hans Jansen for the original patch.
Closes: #53
  • Loading branch information
Larhzu authored and JiaT75 committed Jun 27, 2023
1 parent b72d212 commit ee44863
Showing 1 changed file with 26 additions and 9 deletions.
35 changes: 26 additions & 9 deletions src/liblzma/check/crc64_fast.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,26 +438,34 @@ is_clmul_supported(void)
}


typedef uint64_t (*crc64_func_type)(
const uint8_t *buf, size_t size, uint64_t crc);


static crc64_func_type
crc64_resolve(void)
{
return is_clmul_supported() ? &crc64_clmul : &crc64_generic;
}


#ifndef HAVE_FUNC_ATTRIBUTE_IFUNC

#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
# define CRC64_FUNC_INIT
# define CRC64_SET_FUNC_ATTR __attribute__((__constructor__))
static crc64_func_type crc64_func;
#else
# define CRC64_FUNC_INIT = &crc64_dispatch
# define CRC64_SET_FUNC_ATTR
static uint64_t crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc);
static crc64_func_type crc64_func = &crc64_dispatch;
#endif


// Pointer to the the selected CRC64 method.
static uint64_t (*crc64_func)(const uint8_t *buf, size_t size, uint64_t crc)
CRC64_FUNC_INIT;


CRC64_SET_FUNC_ATTR
static void
crc64_set_func(void)
{
crc64_func = is_clmul_supported() ? &crc64_clmul : &crc64_generic;
crc64_func = crc64_resolve();
return;
}

Expand All @@ -466,7 +474,8 @@ crc64_set_func(void)
static uint64_t
crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc)
{
// When __attribute__((__constructor__)) isn't supported, set the
// When __attribute__((__ifunc__(...))) and
// __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
Expand All @@ -477,8 +486,15 @@ crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc)
}
#endif
#endif
#endif


#if defined(CRC_GENERIC) && defined(CRC_CLMUL) \
&& defined(HAVE_FUNC_ATTRIBUTE_IFUNC)
extern LZMA_API(uint64_t)
lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
__attribute__((__ifunc__("crc64_resolve")));
#else
extern LZMA_API(uint64_t)
lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
{
Expand Down Expand Up @@ -528,3 +544,4 @@ lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
return crc64_generic(buf, size, crc);
#endif
}
#endif

0 comments on commit ee44863

Please sign in to comment.