e949195f64
In order for an ifunc resolver to detect the presence of certain CPU features, access to getauxval(AT_HWCAP) or getauxval(AT_HWCAP2) may be required. In order for getauxval() to work, it needs to access the pointer to the auxiliary vector stored by the linker in the libc shared globals data structure. Accessing the shared globals requires libc to call the __libc_shared_globals() function exported by the linker. However, in order to call this function, libc must be fully relocated, which is not guaranteed to be the case at the point when ifunc resolvers are called. glibc solves this problem by passing the values of getauxval(AT_HWCAP) (and getauxval(AT_HWCAP2) on aarch64) as arguments to the ifunc resolver. Since this seems to be not only the most straightforward way to solve the problem but also improves our compatibility with glibc, we adopt their calling convention. This change is ABI compatible with old resolvers because the arguments are passed in registers, so the old resolvers will simply ignore the new arguments. Bug: 135772972 Change-Id: Ie65bd6e7067f0c878df3d348c815fda61dc12de2
46 lines
2.1 KiB
C++
46 lines
2.1 KiB
C++
/*
|
|
* Copyright (C) 2019 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 "private/bionic_call_ifunc_resolver.h"
|
|
#include <sys/auxv.h>
|
|
#include <sys/ifunc.h>
|
|
|
|
ElfW(Addr) __bionic_call_ifunc_resolver(ElfW(Addr) resolver_addr) {
|
|
#if defined(__aarch64__)
|
|
typedef ElfW(Addr) (*ifunc_resolver_t)(uint64_t, __ifunc_arg_t*);
|
|
static __ifunc_arg_t arg = { sizeof(__ifunc_arg_t), getauxval(AT_HWCAP), getauxval(AT_HWCAP2) };
|
|
return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(arg._hwcap | _IFUNC_ARG_HWCAP, &arg);
|
|
#elif defined(__arm__)
|
|
typedef ElfW(Addr) (*ifunc_resolver_t)(unsigned long);
|
|
static unsigned long hwcap = getauxval(AT_HWCAP);
|
|
return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(hwcap);
|
|
#else
|
|
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
|
|
return reinterpret_cast<ifunc_resolver_t>(resolver_addr)();
|
|
#endif
|
|
}
|