/*
* Copyright ( C ) 2018 The Android Open Source Project
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in
* the documentation and / or other materials provided with the
* distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS
* OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*/
#include <fcntl.h>
#include <private /bionic_ifuncs.h>
#include <sys/syscall.h>
extern "C" {
enum CpuVariant {
kUnknown = 0 ,
kGeneric,
kCortexA7,
kCortexA9,
kCortexA53,
kCortexA55,
kKrait,
kKryo,
};
static constexpr int MAX_CPU_NAME_LEN = 12 ;
struct CpuVariantNames {
alignas(alignof(int )) char name[MAX_CPU_NAME_LEN];
CpuVariant variant;
};
static constexpr CpuVariantNames cpu_variant_names[] = {
{"cortex-a76" , kCortexA55},
{"kryo385" , kCortexA55},
{"cortex-a75" , kCortexA55},
{"kryo" , kKryo},
{"cortex-a73" , kCortexA55},
{"cortex-a55" , kCortexA55},
{"cortex-a53" , kCortexA53},
{"krait" , kKrait},
{"cortex-a9" , kCortexA9},
{"cortex-a7" , kCortexA7},
// kUnknown indicates the end of this array.
{"" , kUnknown},
};
static long ifunc_open(const char * pathname) {
register long r0 __asm__("r0" ) = AT_FDCWD;
register long r1 __asm__("r1" ) = reinterpret_cast <long >(pathname);
register long r2 __asm__("r2" ) = O_RDONLY;
register long r3 __asm__("r3" ) = 0 ;
register long r7 __asm__("r7" ) = __NR_openat;
__asm__ volatile ("swi #0"
: "=r" (r0)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r7));
return r0;
}
static ssize_t ifunc_read(int fd, void * buf, size_t count) {
register long r0 __asm__("r0" ) = fd;
register long r1 __asm__("r1" ) = reinterpret_cast <long >(buf);
register long r2 __asm__("r2" ) = count;
register long r7 __asm__("r7" ) = __NR_read;
__asm__ volatile ("swi #0"
: "=r" (r0)
: "r" (r0), "r" (r1), "r" (r2), "r" (r7)
: "memory" );
return r0;
}
static int ifunc_close(int fd) {
register long r0 __asm__("r0" ) = fd;
register long r7 __asm__("r7" ) = __NR_close;
__asm__ volatile ("swi #0" : "=r" (r0) : "r" (r0), "r" (r7));
return r0;
}
static bool is_same_name(const char * a, const char * b) {
static_assert(MAX_CPU_NAME_LEN % sizeof (int ) == 0 , "" );
const int * ia = reinterpret_cast <const int *>(a);
const int * ib = reinterpret_cast <const int *>(b);
for (size_t i = 0 ; i < MAX_CPU_NAME_LEN / sizeof (int ); ++i) {
if (ia[i] != ib[i]) {
return false ;
}
}
return true ;
}
static CpuVariant init_cpu_variant() {
int fd = ifunc_open("/dev/cpu_variant:arm" );
if (fd < 0 ) return kGeneric;
alignas(alignof(int )) char name[MAX_CPU_NAME_LEN] = {};
int bytes_read, total_read = 0 ;
while (total_read < MAX_CPU_NAME_LEN - 1 &&
(bytes_read = ifunc_read(fd, name + total_read,
MAX_CPU_NAME_LEN - 1 - total_read)) > 0 ) {
total_read += bytes_read;
}
ifunc_close(fd);
if (bytes_read != 0 ) {
// The file is too big. We haven't reach the end. Or maybe there is an
// error when reading.
return kGeneric;
}
name[total_read] = 0 ;
const CpuVariantNames* cpu_variant = cpu_variant_names;
while (cpu_variant->variant != kUnknown) {
if (is_same_name(cpu_variant->name, name)) {
return cpu_variant->variant;
}
cpu_variant++;
}
return kGeneric;
}
static CpuVariant get_cpu_variant() {
static CpuVariant cpu_variant = kUnknown;
if (cpu_variant == kUnknown) {
cpu_variant = init_cpu_variant();
}
return cpu_variant;
}
DEFINE_IFUNC_FOR(memmove) {
RETURN_FUNC(memmove_func_t, memmove_a15);
}
MEMMOVE_SHIM()
DEFINE_IFUNC_FOR(memcpy) {
return memmove_resolver(hwcap);
}
MEMCPY_SHIM()
// On arm32, __memcpy() is not publicly exposed, but gets called by memmove()
// in cases where the copy is known to be overlap-safe.
typedef void * __memcpy_func_t(void *, const void *, size_t);
DEFINE_IFUNC_FOR(__memcpy) {
switch (get_cpu_variant()) {
case kCortexA7:
RETURN_FUNC(__memcpy_func_t, __memcpy_a7);
case kCortexA9:
RETURN_FUNC(__memcpy_func_t, __memcpy_a9);
case kKrait:
RETURN_FUNC(__memcpy_func_t, __memcpy_krait);
case kCortexA53:
RETURN_FUNC(__memcpy_func_t, __memcpy_a53);
case kCortexA55:
RETURN_FUNC(__memcpy_func_t, __memcpy_a55);
case kKryo:
RETURN_FUNC(__memcpy_func_t, __memcpy_kryo);
default :
RETURN_FUNC(__memcpy_func_t, __memcpy_a15);
}
}
DEFINE_STATIC_SHIM(void * __memcpy(void * dst, const void * src, size_t n) {
FORWARD(__memcpy)(dst, src, n);
})
DEFINE_IFUNC_FOR(__memset_chk) {
switch (get_cpu_variant()) {
case kCortexA7:
case kCortexA53:
case kCortexA55:
case kKryo:
RETURN_FUNC(__memset_chk_func_t, __memset_chk_a7);
case kCortexA9:
RETURN_FUNC(__memset_chk_func_t, __memset_chk_a9);
case kKrait:
RETURN_FUNC(__memset_chk_func_t, __memset_chk_krait);
default :
RETURN_FUNC(__memset_chk_func_t, __memset_chk_a15);
}
}
__MEMSET_CHK_SHIM()
DEFINE_IFUNC_FOR(memset) {
switch (get_cpu_variant()) {
case kCortexA7:
case kCortexA53:
case kCortexA55:
case kKryo:
RETURN_FUNC(memset_func_t, memset_a7);
case kCortexA9:
RETURN_FUNC(memset_func_t, memset_a9);
case kKrait:
RETURN_FUNC(memset_func_t, memset_krait);
default :
RETURN_FUNC(memset_func_t, memset_a15);
}
}
MEMSET_SHIM()
DEFINE_IFUNC_FOR(strcpy) {
switch (get_cpu_variant()) {
case kCortexA9:
RETURN_FUNC(strcpy_func_t, strcpy_a9);
default :
RETURN_FUNC(strcpy_func_t, strcpy_a15);
}
}
STRCPY_SHIM()
DEFINE_IFUNC_FOR(__strcpy_chk) {
switch (get_cpu_variant()) {
case kCortexA7:
RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a7);
case kCortexA9:
RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a9);
case kKrait:
case kKryo:
RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_krait);
case kCortexA53:
RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a53);
case kCortexA55:
RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a55);
default :
RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a15);
}
}
__STRCPY_CHK_SHIM()
DEFINE_IFUNC_FOR(stpcpy) {
switch (get_cpu_variant()) {
case kCortexA9:
RETURN_FUNC(stpcpy_func_t, stpcpy_a9);
default :
RETURN_FUNC(stpcpy_func_t, stpcpy_a15);
}
}
STPCPY_SHIM()
DEFINE_IFUNC_FOR(strcat) {
switch (get_cpu_variant()) {
case kCortexA9:
RETURN_FUNC(strcat_func_t, strcat_a9);
default :
RETURN_FUNC(strcat_func_t, strcat_a15);
}
}
STRCAT_SHIM()
DEFINE_IFUNC_FOR(__strcat_chk) {
switch (get_cpu_variant()) {
case kCortexA7:
RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a7);
case kCortexA9:
RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a9);
case kKrait:
case kKryo:
RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_krait);
case kCortexA53:
RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a53);
case kCortexA55:
RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a55);
default :
RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a15);
}
}
__STRCAT_CHK_SHIM()
DEFINE_IFUNC_FOR(strcmp) {
RETURN_FUNC(strcmp_func_t, strcmp_a15);
}
STRCMP_SHIM()
DEFINE_IFUNC_FOR(strlen) {
switch (get_cpu_variant()) {
case kCortexA9:
RETURN_FUNC(strlen_func_t, strlen_a9);
default :
RETURN_FUNC(strlen_func_t, strlen_a15);
}
}
STRLEN_SHIM()
} // extern "C"
Messung V0.5 in Prozent C=90 H=86 G=87
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-06-28)
¤
*© Formatika GbR, Deutschland