Browse Source

get_elf_hwcap_from_getauxval (#3301)

tags/20211122
nihui GitHub 4 years ago
parent
commit
ac3d32aa0d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 63 additions and 3 deletions
  1. +63
    -3
      src/cpu.cpp

+ 63
- 3
src/cpu.cpp View File

@@ -38,6 +38,9 @@
#endif

#if defined __ANDROID__ || defined __linux__
#if defined __ANDROID__
#include <dlfcn.h>
#endif
#include <stdint.h>
#include <sys/syscall.h>
#include <unistd.h>
@@ -91,17 +94,63 @@ namespace ncnn {

#if defined __ANDROID__ || defined __linux__

#define AT_HWCAP 16
#define AT_HWCAP2 26

#if defined __ANDROID__
// Probe the system's C library for a 'getauxval' function and call it if
// it exits, or return 0 for failure. This function is available since API
// level 20.
//
// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the
// edge case where some NDK developers use headers for a platform that is
// newer than the one really targetted by their application.
// This is typically done to use newer native APIs only when running on more
// recent Android versions, and requires careful symbol management.
//
// Note that getauxval() can't really be re-implemented here, because
// its implementation does not parse /proc/self/auxv. Instead it depends
// on values that are passed by the kernel at process-init time to the
// C runtime initialization layer.
static unsigned int get_elf_hwcap_from_getauxval()
{
typedef unsigned long getauxval_func_t(unsigned long);

dlerror();
void* libc_handle = dlopen("libc.so", RTLD_NOW);
if (!libc_handle)
{
NCNN_LOGE("dlopen libc.so failed %s", dlerror());
return 0;
}

unsigned int result = 0;
getauxval_func_t* func = (getauxval_func_t*)dlsym(libc_handle, "getauxval");
if (!func)
{
NCNN_LOGE("dlsym getauxval failed");
}
else
{
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
result = (unsigned int)(*func)(AT_HWCAP);
}
dlclose(libc_handle);

return result;
}
#endif // defined __ANDROID__

// extract the ELF HW capabilities bitmap from /proc/self/auxv
static unsigned int get_elf_hwcap_from_proc_self_auxv()
{
FILE* fp = fopen("/proc/self/auxv", "rb");
if (!fp)
{
NCNN_LOGE("fopen /proc/self/auxv failed");
return 0;
}

#define AT_HWCAP 16
#define AT_HWCAP2 26
#if __aarch64__ || __riscv_xlen == 64
struct
{
@@ -139,7 +188,18 @@ static unsigned int get_elf_hwcap_from_proc_self_auxv()
return result;
}

static unsigned int g_hwcaps = get_elf_hwcap_from_proc_self_auxv();
static unsigned int get_elf_hwcap()
{
#if defined __ANDROID__
unsigned int hwcap = get_elf_hwcap_from_getauxval();
if (hwcap)
return hwcap;
#endif

return get_elf_hwcap_from_proc_self_auxv();
}

static unsigned int g_hwcaps = get_elf_hwcap();

#if __aarch64__
// from arch/arm64/include/uapi/asm/hwcap.h


Loading…
Cancel
Save