Compare commits

...

8 Commits

Author SHA1 Message Date
Lasse Collin 109cddca95 liblzma: Use lzma_always_inline in memcmplen.h. 2023-10-22 21:16:12 +03:00
Lasse Collin 1cd2790ff4 sysdefs.h: #define lzma_always_inline. 2023-10-22 21:16:12 +03:00
Lasse Collin 34aa4725ed Build: Add a check for __attribute__((__always_inline__)).
All even remotely relevant GCC and Clang versions support this
attribute. The test is useful to detect support in compilers that
don't define __GNUC__ or __clang__, for example, Solaris Studio.
2023-10-22 21:16:12 +03:00
Lasse Collin 4a1ef58ae7 CMake: Check for func attributes without -Werror.
This matches the modified m4/ax_gcc_func_attribute.m4.
Only constructor and ifunc attribute checks were implemented.

CMake-based build doesn't have the trouble of Autoconf confdefs.h
but writing warning-free tests would still some extra care.
If looking for attribute-related warnings works well enough then
this method should be nicer than the -Werror method in CMake too.
2023-10-22 21:16:12 +03:00
Lasse Collin 146664519f Build: Use AX_GCC_FUNC_ATTRIBUTE to detect __attribute__ support.
This way -Werror isn't needed for these checks as
AX_GCC_FUNC_ATTRIBUTE looks at compiler's warning messages to see
if an unsupported attribute was present. Both methods have their
own problems but I'm hoping that this is the better method.

It is known that the check for the ifunc attribute this doesn't
work with CompCert 3.12. It silently ignores unknown attributes
in function declarations and in static functions if the function
appears unused (even though the unknown attribute would make it used).
2023-10-22 21:16:12 +03:00
Lasse Collin 8a8b8042e7 Build: Fix ax_gcc_func_attribute.m4 for compilers other than GCC >= 4.6.
With other compilers it accepted all attributes as it didn't recognize
the warning messages about unsupported attributes. The problem occurs
only with compilers that warn instead of error when an unsupported
attribute is seen.

FIXME? gnu_format is broken but so it was before.
2023-10-22 21:13:11 +03:00
Lasse Collin ab2e9be00a Build: Add m4/ax_gcc_func_attribute.m4 from Autoconf-archive. 2023-10-22 19:10:21 +03:00
Lasse Collin a9a5174852 CMake: Don't assume that -fvisibility=hidden is supported outside Windows.
The original code was good enough for supporting GNU/Linux
and a few others but it wasn't very portable.

CMake doesn't support Solaris Studio's -xldscope=hidden.
If it ever does, things should still work with this commit
as Solaris Studio supports not only its own __global but also
the GNU C __attribute__((visibility("default"))). Support for the
attribute was added in 2007 to Sun Studio 12 compiler version 5.9.
2023-10-22 19:10:21 +03:00
6 changed files with 387 additions and 92 deletions

View File

@ -53,6 +53,7 @@ include(CheckSymbolExists)
include(CheckStructHasMember)
include(CheckCSourceCompiles)
include(cmake/tuklib_integer.cmake)
include(cmake/tuklib_gnu_c_attributes.cmake)
include(cmake/tuklib_cpucores.cmake)
include(cmake/tuklib_physmem.cmake)
include(cmake/tuklib_progname.cmake)
@ -750,17 +751,7 @@ if(NOT TUKLIB_CPUCORES_FOUND OR NOT TUKLIB_PHYSMEM_FOUND)
endif()
# Check for __attribute__((__constructor__)) support.
# This needs -Werror because some compilers just warn
# about this being unsupported.
cmake_push_check_state()
set(CMAKE_REQUIRED_FLAGS "-Werror")
check_c_source_compiles("
__attribute__((__constructor__))
static void my_constructor_func(void) { return; }
int main(void) { return 0; }
"
HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR)
cmake_pop_check_state()
tuklib_check_func_attribute_constructor(HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR)
tuklib_add_definition_if(liblzma HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR)
# The Win95 threading lacks a thread-safe one-time initialization function.
@ -782,25 +773,7 @@ option(ALLOW_ATTR_IFUNC "Allow use of __attribute__((__ifunc__())) if \
supported by the system" ON)
if(ALLOW_ATTR_IFUNC)
cmake_push_check_state()
set(CMAKE_REQUIRED_FLAGS "-Werror")
check_c_source_compiles("
static void func(void) { return; }
static void (*resolve_func(void)) (void) { return func; }
void func_ifunc(void)
__attribute__((__ifunc__(\"resolve_func\")));
int main(void) { return 0; }
/*
* 'clang -Wall' incorrectly warns that resolve_func is
* unused (-Wunused-function). Correct assembly output is
* still produced. This problem exists at least in Clang
* versions 4 to 17. The following silences the bogus warning:
*/
void make_clang_quiet(void);
void make_clang_quiet(void) { resolve_func()(); }
"
HAVE_FUNC_ATTRIBUTE_IFUNC)
cmake_pop_check_state()
tuklib_check_func_attribute_ifunc(HAVE_FUNC_ATTRIBUTE_IFUNC)
tuklib_add_definition_if(liblzma HAVE_FUNC_ATTRIBUTE_IFUNC)
endif()
@ -856,10 +829,28 @@ calculation if supported by the system" ON)
endif()
endif()
# Support -fvisiblity=hidden when building shared liblzma.
# These lines do nothing on Windows (even under Cygwin).
# HAVE_VISIBILITY should always be defined to 0 or 1.
if(BUILD_SHARED_LIBS)
# Check for __attribute__((__always_inline__)) support.
tuklib_check_func_attribute_always_inline(HAVE_FUNC_ATTRIBUTE_ALWAYS_INLINE)
tuklib_add_definition_if(liblzma HAVE_FUNC_ATTRIBUTE_ALWAYS_INLINE)
# Symbol visibility support:
#
# The C_VISIBILITY_PRESET property takes care of adding the compiler
# option -fvisibility=hidden (or equivalent) if and only if it is supported.
#
# HAVE_VISIBILITY indicates if __attribute__((__visibility__("default")))
# is supported. HAVE_VISIBILITY is ignored on Windows and Cygwin in
# the C code so we don't need to handle that here. HAVE_VISIBILITY
# should always be defined to 0 or 1.
#
# CMake's GenerateExportHeader module is too fancy since liblzma already
# has the necessary macros. Instead, check CMake's internal variable
# CMAKE_C_COMPILE_OPTIONS_VISIBILITY (it's the C-specific variant of
# CMAKE_<LANG>_COMPILE_OPTIONS_VISIBILITY) which contains the compiler
# command line option for visibility support. It's empty or unset when
# visibility isn't supported. It was added to CMake 2.8.12 in the commit
# 0e9f4bc00c6b26f254e74063e4026ac33b786513 in 2013.
if(BUILD_SHARED_LIBS AND CMAKE_C_COMPILE_OPTIONS_VISIBILITY)
set_target_properties(liblzma PROPERTIES C_VISIBILITY_PRESET hidden)
target_compile_definitions(liblzma PRIVATE HAVE_VISIBILITY=1)
else()

View File

@ -0,0 +1,64 @@
#
# tuklib_gnu_c_attributes.cmake - Checks for GNU C attributes
#
# Author: Lasse Collin
#
# This file has been put into the public domain.
# You can do whatever you want with this file.
#
include("${CMAKE_CURRENT_LIST_DIR}/tuklib_common.cmake")
include(CheckCSourceCompiles)
# This is a helper function for the actual attribute tests.
function(tuklib_check_attribute CODE RESULT)
# GCC, Clang, ICC, Solaris Studio, and XLC don't exit with
# a non-zero exit status if an unknown attribute is provided.
# They only print a warning. Accept the attribute only if no
# attribute-related warnings were issued.
#
# - XLC doesn't use the lower-case string "warning".
# It might use "WARNING" on z/OS or "(W)" on AIX.
# So "warning" isn't checked.
#
# - A few XLC messages use "Attribute" instead of "attribute".
#
# - ICC doesn't use the word "ignored".
#
# The problem with this method is that the regex might become
# outdated with newer compiler versions. Using -Werror would be
# an alternative but it fails if warnings occur for reasons other
# than unsupported attribute.
#
# The first pattern is for GCC, Solaris Studio, and XLC.
# The second one is for ICC. Both patterns work with Clang.
# Matching the leading space or colon reduces chances of
# matching any unrelated messages.
check_c_source_compiles("${CODE} int main(void) { return 0; }" "${RESULT}"
FAIL_REGEX " [Aa]ttribute .* ignored"
": unknown attribute")
endfunction()
function(tuklib_check_func_attribute_always_inline RESULT)
tuklib_check_attribute("
__attribute__((__always_inline__))
static inline int my_inline_func(int x) { return x + 1; }
void my_func(void) { return my_inline_func(123); }
" "${RESULT}")
endfunction()
function(tuklib_check_func_attribute_constructor RESULT)
tuklib_check_attribute("
__attribute__((__constructor__))
void my_constructor_func(void) { return; }
" "${RESULT}")
endfunction()
function(tuklib_check_func_attribute_ifunc RESULT)
tuklib_check_attribute("
static void func(void) { return; }
static void (*resolve_func(void))(void) { return &func; }
void func_ifunc(void)
__attribute__((__ifunc__(\"resolve_func\")));
" "${RESULT}")
endfunction()

View File

@ -820,32 +820,7 @@ AC_SYS_LARGEFILE
AC_C_BIGENDIAN
# __attribute__((__constructor__)) can be used for one-time initializations.
# Use -Werror because some compilers accept unknown attributes and just
# give a warning.
#
# FIXME? Unfortunately -Werror can cause trouble if CFLAGS contains options
# that produce warnings for unrelated reasons. For example, GCC and Clang
# support -Wunused-macros which will warn about "#define _GNU_SOURCE 1"
# which will be among the #defines that Autoconf inserts to the beginning of
# the test program. There seems to be no nice way to prevent Autoconf from
# inserting the any defines to the test program.
AC_MSG_CHECKING([if __attribute__((__constructor__)) can be used])
have_func_attribute_constructor=no
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Werror"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
__attribute__((__constructor__))
static void my_constructor_func(void) { return; }
]])], [
AC_DEFINE([HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR], [1],
[Define to 1 if __attribute__((__constructor__))
is supported for functions.])
have_func_attribute_constructor=yes
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
CFLAGS="$OLD_CFLAGS"
AX_GCC_FUNC_ATTRIBUTE([constructor])
# The Win95 threading lacks a thread-safe one-time initialization function.
# The one-time initialization is needed for crc32_small.c and crc64_small.c
@ -853,7 +828,7 @@ CFLAGS="$OLD_CFLAGS"
# win95, and the compiler does not support attribute constructor, then we
# would end up with a multithreaded build that is thread-unsafe. As a
# result this configuration is not allowed.
if test "x$enable_small$enable_threads$have_func_attribute_constructor"\
if test "x$enable_small$enable_threads$ax_cv_have_func_attribute_constructor" \
= xyeswin95no; then
AC_MSG_ERROR([--enable-threads=win95 and --enable-small cannot be
used at the same time with a compiler that doesn't support
@ -867,35 +842,12 @@ fi
AC_ARG_ENABLE([ifunc], [AS_HELP_STRING([--disable-ifunc],
[do not use __attribute__((__ifunc__()))])],
[], [enable_ifunc=yes])
AS_IF([test "x$enable_ifunc" = xyes], [AX_GCC_FUNC_ATTRIBUTE([ifunc])])
if test "x$enable_ifunc" = xyes ; then
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Werror"
AC_MSG_CHECKING([if __attribute__((__ifunc__())) can be used])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
static void func(void) { return; }
static void (*resolve_func (void)) (void) { return func; }
void func_ifunc (void)
__attribute__((__ifunc__("resolve_func")));
/*
* 'clang -Wall' incorrectly warns that resolve_func is
* unused (-Wunused-function). Correct assembly output is
* still produced. This problem exists at least in Clang
* versions 4 to 17. The following silences the bogus warning:
*/
void make_clang_quiet(void);
void make_clang_quiet(void) { resolve_func()(); }
]])], [
AC_DEFINE([HAVE_FUNC_ATTRIBUTE_IFUNC], [1],
[Define to 1 if __attribute__((__ifunc__()))
is supported for functions.])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
CFLAGS="$OLD_CFLAGS"
fi
# GCC >= 3.2 and Clang support the attribute always_inline but a few other
# compilers support it too. So it's better to check for the support here
# instead of just checking if __GNUC__ or __clang__ is defined.
AX_GCC_FUNC_ATTRIBUTE([always_inline])
###############################################################################
@ -1223,7 +1175,7 @@ if test x$tuklib_cv_cpucores_method = xunknown; then
echo "No supported method to detect the number of CPU cores."
fi
if test "x$enable_threads$enable_small$have_func_attribute_constructor" \
if test "x$enable_threads$enable_small$ax_cv_have_func_attribute_constructor" \
= xnoyesno; then
echo
echo "NOTE:"

279
m4/ax_gcc_func_attribute.m4 Normal file
View File

@ -0,0 +1,279 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html
#
# NOTE: This is a modified version! This has a fix for the grep pattern
# to make it detect unsupported attributes with GCC < 4.6, Clang >= 3.5,
# ICC, Solaris Studio, XL C, and CompCert.
# ===========================================================================
#
# SYNOPSIS
#
# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE)
#
# DESCRIPTION
#
# This macro checks if the compiler supports one of GCC's function
# attributes; many other compilers also provide function attributes with
# the same syntax. Compiler warnings are used to detect supported
# attributes as unsupported ones are ignored by default so quieting
# warnings when using this macro will yield false positives.
#
# The ATTRIBUTE parameter holds the name of the attribute to be checked.
#
# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_<ATTRIBUTE>.
#
# The macro caches its result in the ax_cv_have_func_attribute_<attribute>
# variable.
#
# The macro currently supports the following function attributes:
#
# alias
# aligned
# alloc_size
# always_inline
# artificial
# cold
# const
# constructor
# constructor_priority for constructor attribute with priority
# deprecated
# destructor
# dllexport
# dllimport
# error
# externally_visible
# fallthrough
# flatten
# format
# format_arg
# gnu_format
# gnu_inline
# hot
# ifunc
# leaf
# malloc
# noclone
# noinline
# nonnull
# noreturn
# nothrow
# optimize
# pure
# sentinel
# sentinel_position
# unused
# used
# visibility
# warning
# warn_unused_result
# weak
# weakref
#
# Unsupported function attributes will be tested with a prototype
# returning an int and not accepting any arguments and the result of the
# check might be wrong or meaningless so use with care.
#
# The following are known to only warn about unsupported attributes:
# GCC, Clang/LLVM and Clang-based compilers, Intel C Compiler Classic (ICC),
# Oracle Solaris Studio, IBM XL C, and CompCert. Examples:
#
# GCC <= 4.5.3:
# warning: 'foobar' attribute directive ignored
#
# GCC >= 4.6:
# warning: 'foobar' attribute directive ignored [-Wattributes]
#
# Clang < 3.5:
# warning: unknown attribute 'foobar' ignored [-Wattributes]
#
# Clang >= 3.5, CompCert:
# warning: unknown attribute 'foobar' ignored [-Wunknown-attributes]
#
# ICC:
# warning #1292: unknown attribute "foobar"
#
# Solaris Studio:
# warning: attribute "foobar" is unknown, ignored
#
# XL C message might not contain "warning" but might contain
# "WARNING" (z/OS) or "(W)" (AIX). Documentation lists many
# attribute-related messages but they all contain the strings
# "Attribute" or "attribute" and "ignored". For example:
# Attribute "foobar" is not supported and is ignored.
#
# The regex ' [Aa]ttribute .* ignored' matches all the above except
# ICC. It can be matched with ': unknown attribute' which happens to
# match Clang too.
#
# LICENSE
#
# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 13
AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [
AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1])
AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([
m4_case([$1],
[alias], [
int foo( void ) { return 0; }
int bar( void ) __attribute__(($1("foo")));
],
[aligned], [
int foo( void ) __attribute__(($1(32)));
],
[alloc_size], [
void *foo(int a) __attribute__(($1(1)));
],
[always_inline], [
inline __attribute__(($1)) int foo( void ) { return 0; }
],
[artificial], [
inline __attribute__(($1)) int foo( void ) { return 0; }
],
[cold], [
int foo( void ) __attribute__(($1));
],
[const], [
int foo( void ) __attribute__(($1));
],
[constructor_priority], [
int foo( void ) __attribute__((__constructor__(65535/2)));
],
[constructor], [
int foo( void ) __attribute__(($1));
],
[deprecated], [
int foo( void ) __attribute__(($1("")));
],
[destructor], [
int foo( void ) __attribute__(($1));
],
[dllexport], [
__attribute__(($1)) int foo( void ) { return 0; }
],
[dllimport], [
int foo( void ) __attribute__(($1));
],
[error], [
int foo( void ) __attribute__(($1("")));
],
[externally_visible], [
int foo( void ) __attribute__(($1));
],
[fallthrough], [
void foo( int x ) {switch (x) { case 1: __attribute__(($1)); case 2: break ; }};
],
[flatten], [
int foo( void ) __attribute__(($1));
],
[format], [
int foo(const char *p, ...) __attribute__(($1(printf, 1, 2)));
],
[gnu_format], [
int foo(const char *p, ...) __attribute__((format(gnu_printf, 1, 2)));
],
[format_arg], [
char *foo(const char *p) __attribute__(($1(1)));
],
[gnu_inline], [
inline __attribute__(($1)) int foo( void ) { return 0; }
],
[hot], [
int foo( void ) __attribute__(($1));
],
[ifunc], [
int my_foo( void ) { return 0; }
static int (*resolve_foo(void))(void) { return my_foo; }
int foo( void ) __attribute__(($1("resolve_foo")));
],
[leaf], [
__attribute__(($1)) int foo( void ) { return 0; }
],
[malloc], [
void *foo( void ) __attribute__(($1));
],
[noclone], [
int foo( void ) __attribute__(($1));
],
[noinline], [
__attribute__(($1)) int foo( void ) { return 0; }
],
[nonnull], [
int foo(char *p) __attribute__(($1(1)));
],
[noreturn], [
void foo( void ) __attribute__(($1));
],
[nothrow], [
int foo( void ) __attribute__(($1));
],
[optimize], [
__attribute__(($1(3))) int foo( void ) { return 0; }
],
[pure], [
int foo( void ) __attribute__(($1));
],
[sentinel], [
int foo(void *p, ...) __attribute__(($1));
],
[sentinel_position], [
int foo(void *p, ...) __attribute__(($1(1)));
],
[returns_nonnull], [
void *foo( void ) __attribute__(($1));
],
[unused], [
int foo( void ) __attribute__(($1));
],
[used], [
int foo( void ) __attribute__(($1));
],
[visibility], [
int foo_def( void ) __attribute__(($1("default")));
int foo_hid( void ) __attribute__(($1("hidden")));
int foo_int( void ) __attribute__(($1("internal")));
int foo_pro( void ) __attribute__(($1("protected")));
],
[warning], [
int foo( void ) __attribute__(($1("")));
],
[warn_unused_result], [
int foo( void ) __attribute__(($1));
],
[weak], [
int foo( void ) __attribute__(($1));
],
[weakref], [
static int foo( void ) { return 0; }
static int bar( void ) __attribute__(($1("foo")));
],
[
m4_warn([syntax], [Unsupported attribute $1, the test may fail])
int foo( void ) __attribute__(($1));
]
)], [])
],
dnl Some compilers don't exit with an error if an unknown
dnl attribute is provided. They only output a warning, so accept
dnl the attribute only if no attribute-related warnings were issued.
[AS_IF([[grep ' [Aa]ttribute .* ignored' conftest.err >/dev/null \
|| grep ': unknown attribute' conftest.err >/dev/null]],
[AS_VAR_SET([ac_var], [no])],
[AS_VAR_SET([ac_var], [yes])])],
[AS_VAR_SET([ac_var], [no])])
])
AS_IF([test yes = AS_VAR_GET([ac_var])],
[AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1,
[Define to 1 if the system has the `$1' function attribute])], [])
AS_VAR_POPDEF([ac_var])
])

View File

@ -190,6 +190,16 @@ typedef unsigned char _Bool;
# define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
#endif
// With MSVC, __forceinline can be used instead of inline.
// Using both keywords results in a warning.
#if defined(HAVE_FUNC_ATTRIBUTE_ALWAYS_INLINE)
# define lzma_always_inline inline __attribute__((__always_inline__))
#elif defined(_MSC_VER)
# define lzma_always_inline __forceinline
#else
# define lzma_always_inline inline
#endif
#if defined(__GNUC__) \
&& ((__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4)
# define lzma_attr_alloc_size(x) __attribute__((__alloc_size__(x)))

View File

@ -49,8 +49,7 @@
/// It's rounded up to 2^n. This extra amount needs to be
/// allocated in the buffers being used. It needs to be
/// initialized too to keep Valgrind quiet.
lzma_attribute((__always_inline__))
static inline uint32_t
static lzma_always_inline uint32_t
lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
uint32_t len, uint32_t limit)
{