mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Use auxv to check for CRC32 instructions on ARM.
Previously we probed for CRC32 instructions by testing if they caused SIGILL. Some have expressed doubts about that technique, the Linux documentation advises not to use it, and it's not exactly beautiful. Now that more operating systems expose CPU features to userspace via the ELF loader in approximately the same way, let's use that instead. This is expected to work on Linux, FreeBSD and recent OpenBSD. OpenBSD/ARM has not been tested and is not present in our build farm, but the API matches FreeBSD. On macOS, compilers use a more recent baseline ISA so the runtime test mechanism isn't reached. (A similar situation is expected for Windows/ARM when that port lands.) On NetBSD, runtime feature probing is lost for armv8-a builds. It looks potentially doable with sysctl following the example of the cpuctl program; patches are welcome. No back-patch for now, since we don't have any evidence of actual breakage from the previous technique. Suggested-by: Bastien Roucariès <rouca@debian.org> Discussion: https://postgr.es/m/4496616.iHFcN1HehY%40portable-bastien
This commit is contained in:
2
configure
vendored
2
configure
vendored
@ -15144,7 +15144,7 @@ fi
|
||||
LIBS_including_readline="$LIBS"
|
||||
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
|
||||
|
||||
for ac_func in backtrace_symbols copyfile copy_file_range getifaddrs getpeerucred inet_pton kqueue mbstowcs_l memset_s posix_fallocate ppoll pthread_is_threaded_np setproctitle setproctitle_fast strchrnul strsignal syncfs sync_file_range uselocale wcstombs_l
|
||||
for ac_func in backtrace_symbols copyfile copy_file_range elf_aux_info getauxval getifaddrs getpeerucred inet_pton kqueue mbstowcs_l memset_s posix_fallocate ppoll pthread_is_threaded_np setproctitle setproctitle_fast strchrnul strsignal syncfs sync_file_range uselocale wcstombs_l
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
|
@ -1723,6 +1723,8 @@ AC_CHECK_FUNCS(m4_normalize([
|
||||
backtrace_symbols
|
||||
copyfile
|
||||
copy_file_range
|
||||
elf_aux_info
|
||||
getauxval
|
||||
getifaddrs
|
||||
getpeerucred
|
||||
inet_pton
|
||||
|
@ -2623,7 +2623,9 @@ func_checks = [
|
||||
# when enabling asan the dlopen check doesn't notice that -ldl is actually
|
||||
# required. Just checking for dlsym() ought to suffice.
|
||||
['dlsym', {'dependencies': [dl_dep], 'define': false}],
|
||||
['elf_aux_info'],
|
||||
['explicit_bzero'],
|
||||
['getauxval'],
|
||||
['getifaddrs'],
|
||||
['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
|
||||
['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
|
||||
|
@ -125,6 +125,9 @@
|
||||
/* Define to 1 if you have the <editline/readline.h> header file. */
|
||||
#undef HAVE_EDITLINE_READLINE_H
|
||||
|
||||
/* Define to 1 if you have the `elf_aux_info' function. */
|
||||
#undef HAVE_ELF_AUX_INFO
|
||||
|
||||
/* Define to 1 if you have the <execinfo.h> header file. */
|
||||
#undef HAVE_EXECINFO_H
|
||||
|
||||
@ -154,6 +157,9 @@
|
||||
*/
|
||||
#undef HAVE_GCC__SYNC_INT64_CAS
|
||||
|
||||
/* Define to 1 if you have the `getauxval' function. */
|
||||
#undef HAVE_GETAUXVAL
|
||||
|
||||
/* Define to 1 if you have the `getifaddrs' function. */
|
||||
#undef HAVE_GETIFADDRS
|
||||
|
||||
|
@ -24,57 +24,37 @@
|
||||
#include "postgres_fe.h"
|
||||
#endif
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#if defined(HAVE_ELF_AUX_INFO) || defined(HAVE_GETAUXVAL)
|
||||
#include <sys/auxv.h>
|
||||
#if defined(__linux__) && !defined(__aarch64__) && !defined(HWCAP2_CRC32)
|
||||
#include <asm/hwcap.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "port/pg_crc32c.h"
|
||||
|
||||
|
||||
static sigjmp_buf illegal_instruction_jump;
|
||||
|
||||
/*
|
||||
* Probe by trying to execute pg_comp_crc32c_armv8(). If the instruction
|
||||
* isn't available, we expect to get SIGILL, which we can trap.
|
||||
*/
|
||||
static void
|
||||
illegal_instruction_handler(SIGNAL_ARGS)
|
||||
{
|
||||
siglongjmp(illegal_instruction_jump, 1);
|
||||
}
|
||||
|
||||
static bool
|
||||
pg_crc32c_armv8_available(void)
|
||||
{
|
||||
uint64 data = 42;
|
||||
int result;
|
||||
#if defined(HAVE_ELF_AUX_INFO)
|
||||
unsigned long value;
|
||||
|
||||
/*
|
||||
* Be careful not to do anything that might throw an error while we have
|
||||
* the SIGILL handler set to a nonstandard value.
|
||||
*/
|
||||
pqsignal(SIGILL, illegal_instruction_handler);
|
||||
if (sigsetjmp(illegal_instruction_jump, 1) == 0)
|
||||
{
|
||||
/* Rather than hard-wiring an expected result, compare to SB8 code */
|
||||
result = (pg_comp_crc32c_armv8(0, &data, sizeof(data)) ==
|
||||
pg_comp_crc32c_sb8(0, &data, sizeof(data)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We got the SIGILL trap */
|
||||
result = -1;
|
||||
}
|
||||
pqsignal(SIGILL, SIG_DFL);
|
||||
|
||||
#ifndef FRONTEND
|
||||
/* We don't expect this case, so complain loudly */
|
||||
if (result == 0)
|
||||
elog(ERROR, "crc32 hardware and software results disagree");
|
||||
|
||||
elog(DEBUG1, "using armv8 crc32 hardware = %d", (result > 0));
|
||||
#ifdef __aarch64__
|
||||
return elf_aux_info(AT_HWCAP, &value, sizeof(value)) == 0 &&
|
||||
(value & HWCAP_CRC32) != 0;
|
||||
#else
|
||||
return elf_aux_info(AT_HWCAP2, &value, sizeof(value)) == 0 &&
|
||||
(value & HWCAP2_CRC32) != 0;
|
||||
#endif
|
||||
#elif defined(HAVE_GETAUXVAL)
|
||||
#ifdef __aarch64__
|
||||
return (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0;
|
||||
#else
|
||||
return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0;
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return (result > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user