blob: be86a6074cf80fb57f4508e0b85e8b8b0ac758ca [file] [log] [blame]
/*
* Userspace implementations of __get_datapage
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __VDSO_DATAPAGE_H
#define __VDSO_DATAPAGE_H
#include <linux/bitops.h>
#include <linux/types.h>
#include <asm/vdso_datapage.h>
/*
* We use the hidden visibility to prevent the compiler from generating a GOT
* relocation. Not only is going through a GOT useless (the entry couldn't and
* mustn't be overridden by another library), it does not even work: the linker
* cannot generate an absolute address to the data page.
*
* With the hidden visibility, the compiler simply generates a PC-relative
* relocation (R_ARM_REL32), and this is what we need.
*/
extern const struct vdso_data _vdso_data __attribute__((visibility("hidden")));
static inline const struct vdso_data *__get_datapage(void)
{
const struct vdso_data *ret;
/*
* This simply puts &_vdso_data into ret. The reason why we don't use
* `ret = &_vdso_data` is that the compiler tends to optimise this in a
* very suboptimal way: instead of keeping &_vdso_data in a register,
* it goes through a relocation almost every time _vdso_data must be
* accessed (even in subfunctions). This is both time and space
* consuming: each relocation uses a word in the code section, and it
* has to be loaded at runtime.
*
* This trick hides the assignment from the compiler. Since it cannot
* track where the pointer comes from, it will only use one relocation
* where __get_datapage() is called, and then keep the result in a
* register.
*/
asm("" : "=r"(ret) : "0"(&_vdso_data));
return ret;
}
/* We can only guarantee 56 bits of precision. */
#define ARCH_CLOCK_FIXED_MASK GENMASK_ULL(55, 0)
#endif /* __VDSO_DATAPAGE_H */