linux-user/arm: Add vdso
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
ee95fae075
commit
a9f495b93f
17
linux-user/arm/Makefile.vdso
Normal file
17
linux-user/arm/Makefile.vdso
Normal file
@ -0,0 +1,17 @@
|
||||
include $(BUILD_DIR)/tests/tcg/arm-linux-user/config-target.mak
|
||||
|
||||
SUBDIR = $(SRC_PATH)/linux-user/arm
|
||||
VPATH += $(SUBDIR)
|
||||
|
||||
all: $(SUBDIR)/vdso-be.so $(SUBDIR)/vdso-le.so
|
||||
|
||||
# Adding -use-blx disables unneeded interworking without actually using blx.
|
||||
LDFLAGS = -nostdlib -shared -Wl,-use-blx \
|
||||
-Wl,-h,linux-vdso.so.1 -Wl,--build-id=sha1 \
|
||||
-Wl,--hash-style=both -Wl,-T,$(SUBDIR)/vdso.ld
|
||||
|
||||
$(SUBDIR)/vdso-be.so: vdso.S vdso.ld vdso-asmoffset.h
|
||||
$(CC) -o $@ $(LDFLAGS) -mbig-endian $<
|
||||
|
||||
$(SUBDIR)/vdso-le.so: vdso.S vdso.ld vdso-asmoffset.h
|
||||
$(CC) -o $@ $(LDFLAGS) -mlittle-endian $<
|
@ -5,3 +5,15 @@ syscall_nr_generators += {
|
||||
arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
|
||||
output: '@BASENAME@_nr.h')
|
||||
}
|
||||
|
||||
# TARGET_BIG_ENDIAN is defined to 'n' for little-endian; which means it
|
||||
# is always true as far as source_set.apply() is concerned. Always build
|
||||
# both header files and include the right one via #if.
|
||||
|
||||
vdso_be_inc = gen_vdso.process('vdso-be.so',
|
||||
extra_args: ['-s', 'sigreturn_codes'])
|
||||
|
||||
vdso_le_inc = gen_vdso.process('vdso-le.so',
|
||||
extra_args: ['-s', 'sigreturn_codes'])
|
||||
|
||||
linux_user_ss.add(when: 'TARGET_ARM', if_true: [vdso_be_inc, vdso_le_inc])
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "user-internals.h"
|
||||
#include "signal-common.h"
|
||||
#include "linux-user/trace.h"
|
||||
#include "vdso-asmoffset.h"
|
||||
|
||||
struct target_sigcontext {
|
||||
abi_ulong trap_no;
|
||||
@ -102,6 +103,11 @@ struct rt_sigframe
|
||||
struct sigframe sig;
|
||||
};
|
||||
|
||||
QEMU_BUILD_BUG_ON(offsetof(struct sigframe, retcode[3])
|
||||
!= SIGFRAME_RC3_OFFSET);
|
||||
QEMU_BUILD_BUG_ON(offsetof(struct rt_sigframe, sig.retcode[3])
|
||||
!= RT_SIGFRAME_RC3_OFFSET);
|
||||
|
||||
static abi_ptr sigreturn_fdpic_tramp;
|
||||
|
||||
/*
|
||||
@ -160,6 +166,9 @@ get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
|
||||
return (sp - framesize) & ~7;
|
||||
}
|
||||
|
||||
static void write_arm_sigreturn(uint32_t *rc, int syscall);
|
||||
static void write_arm_fdpic_sigreturn(uint32_t *rc, int ofs);
|
||||
|
||||
static int
|
||||
setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
|
||||
struct sigframe *frame, abi_ulong sp_addr)
|
||||
@ -167,9 +176,9 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
|
||||
abi_ulong handler = 0;
|
||||
abi_ulong handler_fdpic_GOT = 0;
|
||||
abi_ulong retcode;
|
||||
int thumb, retcode_idx;
|
||||
int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
|
||||
bool copy_retcode;
|
||||
bool is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
|
||||
bool is_rt = ka->sa_flags & TARGET_SA_SIGINFO;
|
||||
bool thumb;
|
||||
|
||||
if (is_fdpic) {
|
||||
/* In FDPIC mode, ka->_sa_handler points to a function
|
||||
@ -184,9 +193,7 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
|
||||
} else {
|
||||
handler = ka->_sa_handler;
|
||||
}
|
||||
|
||||
thumb = handler & 1;
|
||||
retcode_idx = thumb + (ka->sa_flags & TARGET_SA_SIGINFO ? 2 : 0);
|
||||
|
||||
uint32_t cpsr = cpsr_read(env);
|
||||
|
||||
@ -202,24 +209,32 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
|
||||
cpsr &= ~CPSR_E;
|
||||
}
|
||||
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
if (is_fdpic) {
|
||||
__put_user((abi_ulong)ka->sa_restorer, &frame->retcode[3]);
|
||||
retcode = (sigreturn_fdpic_tramp +
|
||||
retcode_idx * RETCODE_BYTES + thumb);
|
||||
copy_retcode = true;
|
||||
} else {
|
||||
retcode = ka->sa_restorer;
|
||||
copy_retcode = false;
|
||||
}
|
||||
/* Our vdso default_sigreturn label is a table of entry points. */
|
||||
retcode = default_sigreturn + (is_fdpic * 2 + is_rt) * 8;
|
||||
|
||||
/*
|
||||
* Put the sigreturn code on the stack no matter which return
|
||||
* mechanism we use in order to remain ABI compliant.
|
||||
* Because this is about ABI, always use the A32 instructions,
|
||||
* despite the fact that our actual vdso trampoline is T16.
|
||||
*/
|
||||
if (is_fdpic) {
|
||||
write_arm_fdpic_sigreturn(frame->retcode,
|
||||
is_rt ? RT_SIGFRAME_RC3_OFFSET
|
||||
: SIGFRAME_RC3_OFFSET);
|
||||
} else {
|
||||
retcode = default_sigreturn + retcode_idx * RETCODE_BYTES + thumb;
|
||||
copy_retcode = true;
|
||||
write_arm_sigreturn(frame->retcode,
|
||||
is_rt ? TARGET_NR_rt_sigreturn
|
||||
: TARGET_NR_sigreturn);
|
||||
}
|
||||
|
||||
/* Copy the code to the stack slot for ABI compatibility. */
|
||||
if (copy_retcode) {
|
||||
memcpy(frame->retcode, g2h_untagged(retcode & ~1), RETCODE_BYTES);
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
if (is_fdpic) {
|
||||
/* Place the function descriptor in slot 3. */
|
||||
__put_user((abi_ulong)ka->sa_restorer, &frame->retcode[3]);
|
||||
} else {
|
||||
retcode = ka->sa_restorer;
|
||||
}
|
||||
}
|
||||
|
||||
env->regs[0] = usig;
|
||||
|
3
linux-user/arm/vdso-asmoffset.h
Normal file
3
linux-user/arm/vdso-asmoffset.h
Normal file
@ -0,0 +1,3 @@
|
||||
/* offsetof(struct sigframe, retcode[3]) */
|
||||
#define SIGFRAME_RC3_OFFSET 756
|
||||
#define RT_SIGFRAME_RC3_OFFSET 884
|
BIN
linux-user/arm/vdso-be.so
Executable file
BIN
linux-user/arm/vdso-be.so
Executable file
Binary file not shown.
BIN
linux-user/arm/vdso-le.so
Executable file
BIN
linux-user/arm/vdso-le.so
Executable file
Binary file not shown.
174
linux-user/arm/vdso.S
Normal file
174
linux-user/arm/vdso.S
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* arm linux replacement vdso.
|
||||
*
|
||||
* Copyright 2023 Linaro, Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <asm/unistd.h>
|
||||
#include "vdso-asmoffset.h"
|
||||
|
||||
/*
|
||||
* All supported cpus have T16 instructions: at least arm4t.
|
||||
*
|
||||
* We support user-user with m-profile cpus as an extension, because it
|
||||
* is useful for testing gcc, which requires we avoid A32 instructions.
|
||||
*/
|
||||
.thumb
|
||||
.arch armv4t
|
||||
.eabi_attribute Tag_FP_arch, 0
|
||||
.eabi_attribute Tag_ARM_ISA_use, 0
|
||||
|
||||
.text
|
||||
|
||||
.macro raw_syscall n
|
||||
.ifne \n < 0x100
|
||||
mov r7, #\n
|
||||
.elseif \n < 0x1ff
|
||||
mov r7, #0xff
|
||||
add r7, #(\n - 0xff)
|
||||
.else
|
||||
.err
|
||||
.endif
|
||||
swi #0
|
||||
.endm
|
||||
|
||||
.macro fdpic_thunk ofs
|
||||
ldr r3, [sp, #\ofs]
|
||||
ldmia r2, {r2, r3}
|
||||
mov r9, r3
|
||||
bx r2
|
||||
.endm
|
||||
|
||||
.macro endf name
|
||||
.globl \name
|
||||
.type \name, %function
|
||||
.size \name, . - \name
|
||||
.endm
|
||||
|
||||
/*
|
||||
* We must save/restore r7 for the EABI syscall number.
|
||||
* While we're doing that, we might as well save LR to get a free return,
|
||||
* and a branch that is interworking back to ARMv5.
|
||||
*/
|
||||
|
||||
.macro SYSCALL name, nr
|
||||
\name:
|
||||
.cfi_startproc
|
||||
push {r7, lr}
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_offset r7, -8
|
||||
.cfi_offset lr, -4
|
||||
raw_syscall \nr
|
||||
pop {r7, pc}
|
||||
.cfi_endproc
|
||||
endf \name
|
||||
.endm
|
||||
|
||||
SYSCALL __vdso_clock_gettime, __NR_clock_gettime
|
||||
SYSCALL __vdso_clock_gettime64, __NR_clock_gettime64
|
||||
SYSCALL __vdso_clock_getres, __NR_clock_getres
|
||||
SYSCALL __vdso_gettimeofday, __NR_gettimeofday
|
||||
|
||||
|
||||
/*
|
||||
* We, like the real kernel, use a table of sigreturn trampolines.
|
||||
* Unlike the real kernel, we do not attempt to pack this into as
|
||||
* few bytes as possible -- simply use 8 bytes per slot.
|
||||
*
|
||||
* Within each slot, use the exact same code sequence as the kernel,
|
||||
* lest we trip up someone doing code inspection.
|
||||
*/
|
||||
|
||||
.macro slot n
|
||||
.balign 8
|
||||
.org sigreturn_codes + 8 * \n
|
||||
.endm
|
||||
|
||||
.macro cfi_fdpic_r9 ofs
|
||||
/*
|
||||
* fd = *(r13 + ofs)
|
||||
* r9 = *(fd + 4)
|
||||
*
|
||||
* DW_CFA_expression r9, length (7),
|
||||
* DW_OP_breg13, ofs, DW_OP_deref,
|
||||
* DW_OP_plus_uconst, 4, DW_OP_deref
|
||||
*/
|
||||
.cfi_escape 0x10, 9, 7, 0x7d, (\ofs & 0x7f) + 0x80, (\ofs >> 7), 0x06, 0x23, 4, 0x06
|
||||
.endm
|
||||
|
||||
.macro cfi_fdpic_pc ofs
|
||||
/*
|
||||
* fd = *(r13 + ofs)
|
||||
* pc = *fd
|
||||
*
|
||||
* DW_CFA_expression lr (14), length (5),
|
||||
* DW_OP_breg13, ofs, DW_OP_deref, DW_OP_deref
|
||||
*/
|
||||
.cfi_escape 0x10, 14, 5, 0x7d, (\ofs & 0x7f) + 0x80, (\ofs >> 7), 0x06, 0x06
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Start the unwind info at least one instruction before the signal
|
||||
* trampoline, because the unwinder will assume we are returning
|
||||
* after a call site.
|
||||
*/
|
||||
.cfi_startproc simple
|
||||
.cfi_signal_frame
|
||||
.cfi_return_column 15
|
||||
|
||||
.cfi_def_cfa sp, 32 + 64
|
||||
.cfi_offset r0, -16 * 4
|
||||
.cfi_offset r1, -15 * 4
|
||||
.cfi_offset r2, -14 * 4
|
||||
.cfi_offset r3, -13 * 4
|
||||
.cfi_offset r4, -12 * 4
|
||||
.cfi_offset r5, -11 * 4
|
||||
.cfi_offset r6, -10 * 4
|
||||
.cfi_offset r7, -9 * 4
|
||||
.cfi_offset r8, -8 * 4
|
||||
.cfi_offset r9, -7 * 4
|
||||
.cfi_offset r10, -6 * 4
|
||||
.cfi_offset r11, -5 * 4
|
||||
.cfi_offset r12, -4 * 4
|
||||
.cfi_offset r13, -3 * 4
|
||||
.cfi_offset r14, -2 * 4
|
||||
.cfi_offset r15, -1 * 4
|
||||
|
||||
nop
|
||||
|
||||
.balign 16
|
||||
sigreturn_codes:
|
||||
/* [EO]ABI sigreturn */
|
||||
slot 0
|
||||
raw_syscall __NR_sigreturn
|
||||
|
||||
.cfi_def_cfa_offset 160 + 64
|
||||
|
||||
/* [EO]ABI rt_sigreturn */
|
||||
slot 1
|
||||
raw_syscall __NR_rt_sigreturn
|
||||
|
||||
.cfi_endproc
|
||||
|
||||
/* FDPIC sigreturn */
|
||||
.cfi_startproc
|
||||
cfi_fdpic_pc SIGFRAME_RC3_OFFSET
|
||||
cfi_fdpic_r9 SIGFRAME_RC3_OFFSET
|
||||
|
||||
slot 2
|
||||
fdpic_thunk SIGFRAME_RC3_OFFSET
|
||||
.cfi_endproc
|
||||
|
||||
/* FDPIC rt_sigreturn */
|
||||
.cfi_startproc
|
||||
cfi_fdpic_pc RT_SIGFRAME_RC3_OFFSET
|
||||
cfi_fdpic_r9 RT_SIGFRAME_RC3_OFFSET
|
||||
|
||||
slot 3
|
||||
fdpic_thunk RT_SIGFRAME_RC3_OFFSET
|
||||
.cfi_endproc
|
||||
|
||||
.balign 16
|
||||
endf sigreturn_codes
|
67
linux-user/arm/vdso.ld
Normal file
67
linux-user/arm/vdso.ld
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Linker script for linux arm replacement vdso.
|
||||
*
|
||||
* Copyright 2023 Linaro, Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
VERSION {
|
||||
LINUX_2.6 {
|
||||
global:
|
||||
__vdso_clock_gettime;
|
||||
__vdso_gettimeofday;
|
||||
__vdso_clock_getres;
|
||||
__vdso_clock_gettime64;
|
||||
|
||||
local: *;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
PHDRS {
|
||||
phdr PT_PHDR FLAGS(4) PHDRS;
|
||||
load PT_LOAD FLAGS(7) FILEHDR PHDRS; /* FLAGS=RWX */
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
eh_frame_hdr PT_GNU_EH_FRAME;
|
||||
note PT_NOTE FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS {
|
||||
. = SIZEOF_HEADERS;
|
||||
|
||||
/*
|
||||
* The following, including the FILEHDRS and PHDRS, are modified
|
||||
* when we relocate the binary. We want them to be initially
|
||||
* writable for the relocation; we'll force them read-only after.
|
||||
*/
|
||||
.note : { *(.note*) } :load :note
|
||||
.dynamic : { *(.dynamic) } :load :dynamic
|
||||
.dynsym : { *(.dynsym) } :load
|
||||
/*
|
||||
* There ought not be any real read-write data.
|
||||
* But since we manipulated the segment layout,
|
||||
* we have to put these sections somewhere.
|
||||
*/
|
||||
.data : {
|
||||
*(.data*)
|
||||
*(.sdata*)
|
||||
*(.got.plt) *(.got)
|
||||
*(.gnu.linkonce.d.*)
|
||||
*(.bss*)
|
||||
*(.dynbss*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
}
|
||||
|
||||
.rodata : { *(.rodata*) }
|
||||
.hash : { *(.hash) }
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) } :load :eh_frame_hdr
|
||||
.eh_frame : { *(.eh_frame) } :load
|
||||
|
||||
.text : { *(.text*) } :load
|
||||
}
|
@ -944,13 +944,14 @@ const char *elf_hwcap2_str(uint32_t bit)
|
||||
|
||||
#undef GET_FEATURE_ID
|
||||
|
||||
#endif /* not TARGET_AARCH64 */
|
||||
|
||||
#if TARGET_BIG_ENDIAN
|
||||
# define VDSO_HEADER "vdso-be.c.inc"
|
||||
#else
|
||||
# define VDSO_HEADER "vdso-le.c.inc"
|
||||
#endif
|
||||
|
||||
#endif /* not TARGET_AARCH64 */
|
||||
#endif /* TARGET_ARM */
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
|
Loading…
Reference in New Issue
Block a user