]> git.ipfire.org Git - thirdparty/xz.git/commitdiff
liblzma: Move is_clmul_supported() back to crc_common.h.
authorJia Tan <jiat0218@gmail.com>
Fri, 20 Oct 2023 11:17:46 +0000 (19:17 +0800)
committerJia Tan <jiat0218@gmail.com>
Fri, 20 Oct 2023 16:01:29 +0000 (00:01 +0800)
This partially reverts creating crc_clmul.c
(8c0f9376f58c0696d5d6719705164d35542dd891) where is_clmul_supported()
was moved, extern'ed, and renamed to lzma_is_clmul_supported(). This
caused a problem when the function call to lzma_is_clmul_supported()
results in a call through the PLT. ifunc resolvers run very early in
the dynamic loading sequence, so the PLT may not be setup properly at
this point. Whether the PLT is used or not for
lzma_is_clmul_supported() depened upon the compiler-toolchain used and
flags.

In liblzma compiled with GCC, for instance, GCC will go through the PLT
for function calls internal to liblzma if the version scripts and
symbol visibility hiding are not used. If lazy-binding is disabled,
then it would have made any program linked with liblzma fail during
dynamic loading in the ifunc resolver.

src/liblzma/check/crc32_fast.c
src/liblzma/check/crc64_fast.c
src/liblzma/check/crc_clmul.c
src/liblzma/check/crc_common.h

index add93d55acc164a0e4e2260e4006070f7a86068e..736590497edb3cc8c3d71f204e790fb3fe12284c 100644 (file)
@@ -130,7 +130,7 @@ typedef uint32_t (*crc32_func_type)(
 static crc32_func_type
 crc32_resolve(void)
 {
-       return lzma_is_clmul_supported() ? &lzma_crc32_clmul : &crc32_generic;
+       return is_clmul_supported() ? &lzma_crc32_clmul : &crc32_generic;
 }
 
 #if defined(HAVE_FUNC_ATTRIBUTE_IFUNC) && defined(__clang__)
index 8acdc7135c8822c27ac8cc8c453987009fe7fac1..4e6633db5e15cae3fa4c5b0df4c9298f97ef6284 100644 (file)
@@ -94,7 +94,7 @@ typedef uint64_t (*crc64_func_type)(
 static crc64_func_type
 crc64_resolve(void)
 {
-       return lzma_is_clmul_supported() ? &lzma_crc64_clmul : &crc64_generic;
+       return is_clmul_supported() ? &lzma_crc64_clmul : &crc64_generic;
 }
 
 #if defined(HAVE_FUNC_ATTRIBUTE_IFUNC) && defined(__clang__)
index 7110fd7ef7bd035fa6bc448eb3b010b4921119df..640415e7c1e50ea3f95b587c17e77580fc356164 100644 (file)
@@ -372,48 +372,3 @@ lzma_crc64_clmul(const uint8_t *buf, size_t size, uint64_t crc)
                && defined(_M_IX86)
 #      pragma optimize("", on)
 #endif
-
-
-////////////////////////
-// Detect CPU support //
-////////////////////////
-
-extern bool
-lzma_is_clmul_supported(void)
-{
-       int success = 1;
-       uint32_t r[4]; // eax, ebx, ecx, edx
-
-#if defined(_MSC_VER)
-       // This needs <intrin.h> with MSVC. ICC has it as a built-in
-       // on all platforms.
-       __cpuid(r, 1);
-#elif defined(HAVE_CPUID_H)
-       // Compared to just using __asm__ to run CPUID, this also checks
-       // that CPUID is supported and saves and restores ebx as that is
-       // needed with GCC < 5 with position-independent code (PIC).
-       success = __get_cpuid(1, &r[0], &r[1], &r[2], &r[3]);
-#else
-       // Just a fallback that shouldn't be needed.
-       __asm__("cpuid\n\t"
-                       : "=a"(r[0]), "=b"(r[1]), "=c"(r[2]), "=d"(r[3])
-                       : "a"(1), "c"(0));
-#endif
-
-       // Returns true if these are supported:
-       // CLMUL (bit 1 in ecx)
-       // SSSE3 (bit 9 in ecx)
-       // SSE4.1 (bit 19 in ecx)
-       const uint32_t ecx_mask = (1 << 1) | (1 << 9) | (1 << 19);
-       return success && (r[2] & ecx_mask) == ecx_mask;
-
-       // Alternative methods that weren't used:
-       //   - ICC's _may_i_use_cpu_feature: the other methods should work too.
-       //   - GCC >= 6 / Clang / ICX __builtin_cpu_supports("pclmul")
-       //
-       // CPUID decding is needed with MSVC anyway and older GCC. This keeps
-       // the feature checks in the build system simpler too. The nice thing
-       // about __builtin_cpu_supports would be that it generates very short
-       // code as is it only reads a variable set at startup but a few bytes
-       // doesn't matter here.
-}
index 51ddd9d5c1515cb533e4f62e6bbb9f6d80d2ba4f..1783b5e76d519f7820675406efb4bb39ee63f0a4 100644 (file)
 #      elif defined(HAVE_CPUID_H)
 #              include <cpuid.h>
 #      endif
+
+// is_clmul_supported() must be inlined in this header file because the
+// ifunc resolver function may not support calling a function in another
+// translation unit. Depending on compiler-toolchain and flags, a call to
+// a function defined in another translation unit could result in a
+// reference to the PLT, which is unsafe to do in an ifunc resolver. The
+// ifunc resolver runs very early when loading a shared library, so the PLT
+// entries may not be setup at that time. Inlining this function duplicates
+// the function body in crc32_resolve() and crc64_resolve(), but this is
+// acceptable because the function results in very few instructions.
+static inline bool
+is_clmul_supported(void)
+{
+       int success = 1;
+       uint32_t r[4]; // eax, ebx, ecx, edx
+
+#if defined(_MSC_VER)
+       // This needs <intrin.h> with MSVC. ICC has it as a built-in
+       // on all platforms.
+       __cpuid(r, 1);
+#elif defined(HAVE_CPUID_H)
+       // Compared to just using __asm__ to run CPUID, this also checks
+       // that CPUID is supported and saves and restores ebx as that is
+       // needed with GCC < 5 with position-independent code (PIC).
+       success = __get_cpuid(1, &r[0], &r[1], &r[2], &r[3]);
+#else
+       // Just a fallback that shouldn't be needed.
+       __asm__("cpuid\n\t"
+                       : "=a"(r[0]), "=b"(r[1]), "=c"(r[2]), "=d"(r[3])
+                       : "a"(1), "c"(0));
 #endif
 
-/// Detect at runtime if the CPU supports the x86 CLMUL instruction when
-/// both the generic and CLMUL implementations are built.
-extern bool lzma_is_clmul_supported(void);
+       // Returns true if these are supported:
+       // CLMUL (bit 1 in ecx)
+       // SSSE3 (bit 9 in ecx)
+       // SSE4.1 (bit 19 in ecx)
+       const uint32_t ecx_mask = (1 << 1) | (1 << 9) | (1 << 19);
+       return success && (r[2] & ecx_mask) == ecx_mask;
+
+       // Alternative methods that weren't used:
+       //   - ICC's _may_i_use_cpu_feature: the other methods should work too.
+       //   - GCC >= 6 / Clang / ICX __builtin_cpu_supports("pclmul")
+       //
+       // CPUID decding is needed with MSVC anyway and older GCC. This keeps
+       // the feature checks in the build system simpler too. The nice thing
+       // about __builtin_cpu_supports would be that it generates very short
+       // code as is it only reads a variable set at startup but a few bytes
+       // doesn't matter here.
+}
+
+#endif
 
 /// CRC32 implemented with the x86 CLMUL instruction.
 extern uint32_t lzma_crc32_clmul(const uint8_t *buf, size_t size,